কোনও সংখ্যার বর্গক্ষেত্র গণনা করার জন্য এইভাবে বুঝতে পারি না


135

আমি একটি ফাংশন পেয়েছি যা একটি সংখ্যার স্কোয়ার গণনা করে:

int p(int n) {
    int a[n]; //works on C99 and above
    return (&a)[n] - a;
}

এটি এন 2 এর মান প্রদান করে । প্রশ্ন, এটি কিভাবে এটি করে? একটু পরীক্ষামূলক পর, আমি দেখা গেছে যে মধ্যবর্তী (&a)[k]এবং (&a)[k+1]হয় sizeof(a)/ sizeof(int)। কেন এমন?


6
আপনি যেখানে এই তথ্যটি পেয়েছেন তার লিঙ্ক আছে?
আর সাহু

4
int p(n)? এটি কি সংকলন করে?
বারাক মানস

78
এই সন্ত্রস্ত, এখন আবার এটি ব্যবহার এবং কখনও ব্যবহার n * যেসব এন পরিবর্তে ...

26
বা আরও ভাল:int q(int n) { return sizeof (char [n][n]); }
ah ই

17
@ouah এই প্রশ্নের অভিমানী বোঝায় codegolf.stackexchange.com/a/43262/967 কারণ আমি ব্যবহার না sizeofঅক্ষর সংরক্ষণ করতে ছিল। বাকি সবাই: এটি ইচ্ছাকৃতভাবে অস্পষ্ট কোড, এটি অপরিজ্ঞাত আচরণ, @ ahউহের উত্তর সঠিক।
ইকত্মুর

উত্তর:


117

অবশ্যই হ্যাক ... তবে *অপারেটরটি ব্যবহার না করেই একটি সংখ্যা স্কোয়ার করার একটি উপায় (এটি কোডিং প্রতিযোগিতার প্রয়োজনীয়তা ছিল)।

(&a)[n] 

intঅবস্থানের পয়েন্টারের সমান

(a + sizeof(a[n])*n)

এবং এইভাবে সম্পূর্ণ অভিব্যক্তি হয়

  (&a)[n] -a 

= (a + sizeof(a[n])*n -a) /sizeof(int)

= sizeof(a[n])*n / sizeof(int)
= sizeof(int) * n * n / sizeof(int)
= n * n

11
এবং আপনি যেমন স্পষ্টভাবে বোঝাচ্ছেন তবে আমি স্পষ্ট করে বলার প্রয়োজনীয়তা অনুভব করছি এটি সেরাভাবে একটি সিনট্যাক্স হ্যাক। বহুগুণ অপারেশন এখনও সেখানে থাকবে; এটি কেবল অপারেটর যা এড়ানো হচ্ছে।
টমি

এর পিছনে যা ঘটেছিল তা আমি পেয়েছি, তবে আমার আসল প্রশ্নটি হল কেন (& ক) [কে] ++ * আকারের (ক) / আকারের (পূর্ববর্তী) হিসাবে একই ঠিকানায়
ইমানুয়েল

33
একটি পুরানো কোডার হিসাবে আমি কম্প্রেলারটি কখন সংকলনের সময় জানা যায়নি তার (&a)কোনও অবজেক্টের পয়েন্টার হিসাবে বিবেচনা করতে পারে তা দেখে আমি অচল হয়ে পড়েছি । সি সরল ভাষা n*sizeof(int)n
হ'ল

এটি একটি দুর্দান্ত চালাক হ্যাক, তবে এমন কিছু যা আপনি উত্পাদন কোডে দেখছেন না (আশা করি)।
জন ওডম

14
একটি সরু হিসাবে, এটিও ইউবি, কারণ এটি অন্তর্নিহিত অ্যারেগুলির উপাদান বা কেবল অতীতকে নির্দেশ না করার জন্য একটি পয়েন্টার বৃদ্ধি করে।
উত্সাহকরা

86

এই হ্যাকটি বুঝতে, প্রথমে আপনাকে পয়েন্টার পার্থক্যটি বুঝতে হবে, অর্থাত্, যখন একই অ্যারের উপাদানগুলিতে নির্দেশিত দুটি পয়েন্টারগুলি বিয়োগ করা হয় তখন কী ঘটে ?

যখন একটি পয়েন্টার অন্য থেকে বিয়োগ করা হয়, ফলাফলটি পয়েন্টারগুলির মধ্যে দূরত্ব (অ্যারে উপাদানগুলিতে পরিমাপ করা হয়)। সুতরাং, যদি pপয়েন্ট করে a[i]এবং qনির্দেশ করে a[j]তবে p - qসমান equali - j

সি 11: 6.5.6 অ্যাডিটিভ অপারেটর (p9):

যখন দুটি পয়েন্টার বিয়োগ করা হয় , উভয়ই একই অ্যারে অবজেক্টের উপাদানগুলিকে নির্দেশ করবে বা অ্যারে অবজেক্টের শেষ উপাদানটির একটিতে; ফলাফলটি দুটি অ্যারের উপাদানগুলির সাবস্ক্রিপ্টগুলির পার্থক্য । [...]।
অন্য কথায়, যদি ক্রমান্বয়ে অভিব্যক্তি Pএবং Qনির্দেশিত হয়, যথাক্রমে, একটি অ্যারে অবজেক্টের iচতুর্থ ও- jতম উপাদানগুলি, এক্সপ্রেশনটির (P)-(Q)মানi−j প্রদান করে মানটি টাইপের কোনও বস্তুর সাথে মানিয়ে যায় ptrdiff_t

এখন আমি প্রত্যাশা করছি যে আপনি পয়েন্টারে অ্যারে নাম রূপান্তর সম্পর্কে অবগত আছেন, a পয়েন্টারে অ্যারের প্রথম উপাদানকে রূপান্তর করেন a&aপুরো মেমরি ব্লকের ঠিকানা, অর্থাত্ এটি অ্যারের ঠিকানা a। নীচের চিত্রটি আপনাকে বুঝতে সহায়তা করবে ( বিস্তারিত ব্যাখ্যাের জন্য এই উত্তরটি পড়ুন ):

এখানে চিত্র বর্ণনা লিখুন

এটি আপনাকে বুঝতে সহায়তা করবে যে কেন aএবং &aএকই ঠিকানা রয়েছে এবং (&a)[i]আমি কী অ্যারের ঠিকানা ( যেটির আকারের একই আকার a)।

সুতরাং, বিবৃতি

return (&a)[n] - a; 

সমতুল্য

return (&a)[n] - (&a)[0];  

এবং এই পার্থক্য পয়েন্টার মধ্যে উপাদানের সংখ্যা দেব (&a)[n]এবং (&a)[0], যা হয় nঅ্যারে প্রতিটিn int উপাদানকে করে। সুতরাং, মোট অ্যারে উপাদানগুলি n*n= n2


বিঃদ্রঃ:

সি 11: 6.5.6 অ্যাডিটিভ অপারেটর (p9):

যখন দুটি পয়েন্টার বিয়োগ করা হয়, উভয়ই একই অ্যারে অবজেক্টের উপাদানগুলিকে নির্দেশ করবে বা অ্যারে অবজেক্টের শেষ উপাদানটির একটিতে ; ফলাফলটি দুটি অ্যারের উপাদানগুলির সাবস্ক্রিপ্টগুলির পার্থক্য। ফলাফলের আকারটি বাস্তবায়ন-সংজ্ঞায়িত হয় এবং এর প্রকার (স্বাক্ষরিত পূর্ণসংখ্যার প্রকার) শিরোনামে ptrdiff_tসংজ্ঞায়িত করা হয় <stddef.h>। ফলাফল যদি সেই ধরণের কোনও বস্তুর মধ্যে উপস্থাপনযোগ্য না হয়, তবে আচরণটি সংজ্ঞায়িত।

যেহেতু (&a)[n]একই অ্যারে অবজেক্টের উপাদানগুলির দিকে ইঙ্গিত করে না বা অ্যারে অবজেক্টের শেষ উপাদানটির একটিও অতীত হয় না, তাই অপরিজ্ঞাত আচরণের জন্য(&a)[n] - a প্রার্থনা করবে ।

এছাড়াও মনে রাখবেন, ভাল ফাংশনের রিটার্ন টাইপ পরিবর্তন করতে pকরতে ptrdiff_t


"উভয়ই একই অ্যারে অবজেক্টের উপাদানগুলিকে নির্দেশ করবে" - যা এই "হ্যাক" সর্বোপরি ইউবি নয় কিনা তা আমার জন্য প্রশ্ন উত্থাপন করে। পয়েন্টার গাণিতিক এক্সপ্রেশনটি অ-অস্তিত্বশীল অবজেক্টের কাল্পনিক প্রান্তটিকে বোঝায়: এটি কি অনুমোদিত?
মার্টিন বা

সংক্ষেপে বলতে গেলে, একটি হ'ল এন উপাদানগুলির অ্যারের ঠিকানা, সুতরাং & একটি [0] এই অ্যারেতে প্রথম উপাদানটির ঠিকানা, যা একটির সমান; তদ্ব্যতীত, & a [কে] কে সবসময় কে, নির্বিশেষে এন উপাদানগুলির একটি অ্যারের ঠিকানা হিসাবে বিবেচনা করা হবে এবং যেহেতু & a [1..n] পাশাপাশি একটি ভেক্টর, তাই এর উপাদানগুলির "অবস্থান" ক্রমাগত হয়, যার অর্থ প্রথম উপাদানটি অবস্থান x এ, দ্বিতীয়টি অবস্থান x + এ (ভেক্টরের উপাদানগুলির সংখ্যা যা n হয়) এবং এই জাতীয়। আমি কি সঠিক? এছাড়াও, এটি একটি গাদা স্থান, সুতরাং এর অর্থ কি এই যে আমি যদি একই এন উপাদানগুলির একটি নতুন ভেক্টর বরাদ্দ করি তবে এর ঠিকানাটি (& a) [1] এর মতো?
ইমানুয়েল

1
@Emanuel; অ্যারের তম উপাদান &a[k]একটি ঠিকানা । এটি সর্বদা উপাদানগুলির একটি অ্যারের ঠিকানা হিসাবে বিবেচিত হবে । সুতরাং, প্রথম উপাদানটি অবস্থানে (বা ), দ্বিতীয় অবস্থানে রয়েছে + (অ্যারের উপাদানগুলির সংখ্যা যা ) * (একটি অ্যারের উপাদানের আকার) এবং এই জাতীয়। এবং মনে রাখবেন যে পরিবর্তনশীল দৈর্ঘ্যের অ্যারেগুলির জন্য মেমরিটি স্ট্যাকের জন্য বরাদ্দ করা হয়, গাদা নয় on ka(&a)[k]ka&aaan
হ্যাকগুলি

@MartinBa; এটি কি অনুমোদিত? না এটি অনুমোদিত নয়। এর ইউবি। সম্পাদনা দেখুন।
হ্যাক

1
প্রশ্ন OT প্রকৃতি এবং আপনার ডাকনাম মধ্যে চমৎকার দেখা গেল @haccks
Dimitar Tsonev

35

aএকটি (পরিবর্তনশীল) অ্যারে হল n int

&aএর (পরিবর্তনশীল) অ্যারের পয়েন্টার n int

(&a)[1]এর একটি পয়েন্টার intএক intগত অ্যারের উপাদান গত। এই পয়েন্টারটি n intপরে উপাদানসমূহ &a[0]

(&a)[2]এর একটি পয়েন্টার intএক intদুইটি অ্যারের শেষ অ্যারের উপাদান গত। এই পয়েন্টারটি 2 * n intপরে উপাদানসমূহ &a[0]

(&a)[n]এর একটি পয়েন্টার intএক intশেষ অ্যারের উপাদান গত nঅ্যারে। এই পয়েন্টারটি n * n intপরে উপাদানসমূহ &a[0]। শুধু বিয়োগ &a[0]বা aআপনার আছেn

অবশ্যই এটি প্রযুক্তিগতভাবে অপরিজ্ঞাত আচরণ এমনকি যদি এটি আপনার মেশিনে কাজ করে তবে এটি (&a)[n]অ্যারের অভ্যন্তরে নির্দেশ করে না বা শেষ অ্যারে উপাদানটির একটিতে অতীত হয় না (পয়েন্টার পাটিগণিতের সি বিধি দ্বারা প্রয়োজনীয়)।


ঠিক আছে, আমি পেয়েছিলাম, কিন্তু কেন সি এ ঘটে? এর পিছনে যুক্তি কী?
ইমানুয়েল

@ ইমানুয়েল এর পক্ষে এর কোন কড়া উত্তর নেই যে পয়েন্টার পাটিগণিত দূরত্ব (সাধারণত একটি অ্যারেতে) পরিমাপের জন্য কার্যকর, [n]সিনট্যাক্সটি অ্যারে ঘোষণা করে এবং অ্যারে পয়েন্টারগুলিতে বিচ্ছিন্ন হয়। এই পরিণতিটি সহ তিনটি পৃথকভাবে দরকারী জিনিস।
টমি

1
@ ইমানুয়েল যদি আপনি জিজ্ঞাসা করছেন যে কেন কেউ এটি করবে কেন , খুব অল্প কারণ আছে এবং প্রতিটি কারণের ইউবি প্রকৃতির কারণে নয় । এবং এটি লক্ষণীয় যে (&a)[n]টাইপ int[n], এবং এটিint* অ্যারে তাদের প্রথম উপাদানটির ঠিকানা হিসাবে প্রকাশের কারণে প্রকাশ করে , যদি বিবরণে এটি পরিষ্কার ছিল না was
হুজক্রাইগ

না, আমি বোঝাতে চাইছি না যে কেউ কেন এটি করবে, আমি বোঝাতে চাইছিলাম কেন এই পরিস্থিতিতে সি স্ট্যান্ডার্ডটি এরকম আচরণ করে।
ইমানুয়েল

1
@ ইমানুয়েল পয়েন্টার গাণিতিক (এবং এক্ষেত্রে সেই বিষয়ের একটি সাব-চ্যাপ্টর : পয়েন্টার ডিফারেন্সিং ) এটি গুগল করার পাশাপাশি এই সাইটে প্রশ্নোত্তর পড়ার মতো। এটির অনেক দরকারী সুবিধা রয়েছে এবং সঠিকভাবে ব্যবহার করার সময় মানগুলিতে দৃ concrete়ভাবে সংজ্ঞায়িত হয়। অর্ডার সম্পূর্ণরূপে উপলব্ধি করতে আপনি আছে বুঝতে ধরনের কোডে আপনি তালিকাভুক্ত কল্পিত হয়।
হুৎসক্রাইগ

12

আপনার যদি দুটি পয়েন্টার থাকে যা একই অ্যারের দুটি উপাদানগুলিতে নির্দেশ করে তবে তার পার্থক্য এই পয়েন্টারগুলির মধ্যে উপাদানের সংখ্যা অর্জন করবে। উদাহরণস্বরূপ এই কোড স্নিপেট 2 আউটপুট হবে।

int a[10];

int *p1 = &a[1];
int *p2 = &a[3];

printf( "%d\n", p2 - p1 ); 

এখন অভিব্যক্তি বিবেচনা করা যাক

(&a)[n] - a;

এই এক্সপ্রেশন aটাইপ আছেint * এবং এর প্রথম উপাদান নির্দেশ করে।

এক্সপ্রেশনটিতে চিত্রযুক্ত দ্বিমাত্রিক অ্যারের প্রথম সারিতে &aটাইপ int ( * )[n]এবং পয়েন্ট রয়েছে । aযদিও এর মানটি বিভিন্ন ধরণের হলেও মানের সাথে মেলে ।

( &a )[n]

এই ইমেজযুক্ত দ্বি মাত্রিক অ্যারের এন-থ এলিমেন্ট এবং টাইপ int[n]রয়েছে এটি ইমেজড অ্যারের এন-তম সারি। প্রকাশে(&a)[n] - a এটি তার প্রথম উপাদানটির ঠিকানায় রূপান্তরিত হয় এবং এতে টাইপ হয় `int *।

সুতরাং (&a)[n]এবং aএর মধ্যে এন উপাদানগুলির সারি রয়েছে। সুতরাং পার্থক্য সমান হবে n * n


সুতরাং প্রতিটি অ্যারের পিছনে এন * এন আকারের একটি ম্যাট্রিক্স আছে?
ইমানুয়েল

@ ইমানুয়েল এই দুটি পয়েন্টারের মধ্যে এনএক্সএন উপাদানগুলির একটি ম্যাট্রিক্স রয়েছে। এবং পয়েন্টারের পার্থক্য n * n এর সমান মান দেয় যা পয়েন্টারগুলির মধ্যে কতগুলি উপাদান।
মস্কো থেকে ভ্লাদ 21

তবে আকারের এই ম্যাট্রিক্সটি এন * এন পিছনে কেন? সি এর কোন ব্যবহার আছে? আমি বোঝাতে চাইছি, এটি সিটির চেয়ে বেশি "এন" বরাদ্দযুক্ত এন এর আকারের আরও অ্যারে, আমাকে না জেনে? যদি তাই হয় তবে আমি কি সেগুলি ব্যবহার করতে পারি? অন্যথায়, কেন এই ম্যাট্রিক্সটি গঠিত হবে (আমি বোঝাতে চাইছি এটির সেখানে থাকার জন্য এটির একটি উদ্দেশ্য থাকতে হবে)।
ইমানুয়েল

2
@ ইমানুয়েল - এই ক্ষেত্রে ম্যাট্রিক্স কীভাবে পয়েন্টার গাণিতিক কাজ করে তার একটি ব্যাখ্যা মাত্র। এই ম্যাট্রিক্স বরাদ্দ করা হয়নি এবং আপনি এটি ব্যবহার করতে পারবেন না। যেমন এটি ইতিমধ্যে কয়েকবার বলা হয়েছিল, 1) এই কোড স্নিপেট হ্যাক যা এর ব্যবহারিক ব্যবহার নেই; 2) এই হ্যাক বুঝতে পয়েন্টার গাণিতিক কীভাবে কাজ করে তা শিখতে হবে।
void_ptr

@ ইমানুয়েল এটি পয়েন্টার পাটিগণিত ব্যাখ্যা করে। ব্যাখ্যা (এবং ক) [এন] পয়েন্টার পাটিগণিতের কারণে চিত্রযুক্ত দ্বি মাত্রিক অ্যারের এন-উপাদানকে নির্দেশক।
মস্কো থেকে ভ্লাদ

4
Expression     | Value                | Explanation
a              | a                    | point to array of int elements
a[n]           | a + n*sizeof(int)    | refer to n-th element in array of int elements
-------------------------------------------------------------------------------------------------
&a             | a                    | point to array of (n int elements array)
(&a)[n]        | a + n*sizeof(int[n]) | refer to n-th element in array of (n int elements array)
-------------------------------------------------------------------------------------------------
sizeof(int[n]) | n * sizeof(int)      | int[n] is a type of n-int-element array

সুতরাং,

  1. এর টাইপ (&a)[n]হয়int[n]পয়েন্টার
  2. এর টাইপ aহয় intপয়েন্টার

এখন এক্সপ্রেশন (&a)[n]-aএকটি পয়েন্টার বিয়োগফল সম্পাদন করে:

  (&a)[n]-a
= ((a + n*sizeof(int[n])) - a) / sizeof(int)
= (n * sizeof(int[n])) / sizeof(int)
= (n * n * sizeof(int)) / sizeof(int)
= n * n
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.