অ্যারে সহ, কেন এটি একটি [5] == 5 [এ]?


1621

জোল স্ট্যাক ওভারফ্লো পডকাস্ট # 34- তে সি প্রোগ্রামিং ল্যাঙ্গুয়েজে (যেমন: কে ও আর) উল্লেখ করেছেন, সি-তে অ্যারের এই সম্পত্তিটির উল্লেখ রয়েছে:a[5] == 5[a]

জোয়েল বলেছেন যে এটি পয়েন্টার পাটিগণিতের কারণে হয়েছে তবে আমি এখনও বুঝতে পারি না। কেন করেa[5] == 5[a] ?


48
একটি [+] এর মতো কিছুও কি * (a ++) বা * (++ এ) এর মতো কাজ করবে?
ডিম

45
@ এগন: এটি অত্যন্ত সৃজনশীল তবে দুর্ভাগ্যক্রমে এটি সংকলকরা কীভাবে কাজ করে না। a[1]সংকলকটি স্ট্রিং নয়, টোকেনের একটি সিরিজ হিসাবে ব্যাখ্যা করে: * (} a {অপারেটর} + {পূর্ণসংখ্যা} 1 এর {পূর্ণসংখ্যার অবস্থান) * ({পূর্ণসংখ্যা} 1 {অপারেটর} + {ger a এর পূর্ণসংখ্যার অবস্থান) এর সমান তবে * (} a {অপারেটরের {+ {অপারেটর {+ এর পূর্ণসংখ্যার অবস্থানের মতো নয়)
দিনাহ

11
এ সম্পর্কে একটি আকর্ষণীয় যৌগের প্রকরণ ইলজিকাল অ্যারে অ্যাক্সেসে চিত্রিত করা হয়েছে , যেখানে আপনার কাছে রয়েছে char bar[]; int foo[];এবং foo[i][bar]একটি অভিব্যক্তি হিসাবে ব্যবহৃত হয়।
জোনাথন লেফলার

5
@ এল্ড্রিচকনড্রাম, আপনি কেন ভাবেন যে 'সংকলক বাম অংশটি পয়েন্টার হিসাবে পরীক্ষা করতে পারে না'? হ্যা পারি. এটি সত্য যে a[b]= *(a + b)কোনও প্রদত্ত aএবং এর জন্য b, তবে ভাষা ডিজাইনারদের +সকল প্রকারের জন্য পরিবহণ সংজ্ঞায়িত করার অবাধ পছন্দ ছিল । i + pঅনুমতি দেওয়ার সময় কোনও কিছুই তাদের নিষেধ করতে বাধা দিতে পারেনি p + i
অচ

13
@ আন্ড্রে ওয়ান সাধারণত সচল +হওয়ার প্রত্যাশা করে, তাই সম্ভবত প্রকৃত সমস্যাটি পৃথক অফসেট অপারেটর ডিজাইনের পরিবর্তে পয়েন্টার অপারেশনগুলিকে পাটিগণিতের সাথে সাদৃশ্য করা বেছে নেওয়া হচ্ছে।
এল্ড্রিচ কনড্রাম

উত্তর:


1924

সি স্ট্যান্ডার্ড []অপারেটরটিকে নিম্নলিখিত হিসাবে সংজ্ঞায়িত করে:

a[b] == *(a + b)

সুতরাং a[5]মূল্যায়ন করতে হবে:

*(a + 5)

এবং 5[a]মূল্যায়ন করবে:

*(5 + a)

aঅ্যারের প্রথম উপাদানটির পয়েন্টার। a[5]এর থেকে আরও 5 উপাদান আরও বেশি a, যা একই রকম *(a + 5)এবং প্রাথমিক বিদ্যালয়ের গণিত থেকে আমরা জানি যেগুলি সমান ( সংযোজনীয় হয় )।


325
আমি আশ্চর্য হই যে এটি * ((5 * আকারের (ক)) + এ) এর মতো না হলে। যদিও দুর্দান্ত ব্যাখ্যা।
জন ম্যাকআইন্টির

92
@ দিনাহ: সি-সংকলক দৃষ্টিকোণ থেকে আপনি ঠিক বলেছেন। কোন আকারের প্রয়োজন নেই এবং আমি যে সমস্ত অভিব্যক্তি উল্লেখ করেছি সেগুলি হ'ল একই। তবে মেশিন কোড তৈরি করার সময় সংকলকটি আকারে বিবেচনা করবে। যদি একটি অন্তর্ বিন্যাস হয় তবে এর পরিবর্তে a[5]এমন কিছু সংকলন করবেmov eax, [ebx+20][ebx+5]
মেহরদাদ আফশারি

12
@ দিনাহ: এ একটি ঠিকানা, 0x1230 বলুন। যদি একটি 32-বিট ইন্টে অ্যারেতে থাকে, তবে [[0] 0x1230 এ, একটি [1] 0x1234 এ, একটি [2] 0x1238 এ ... একটি [5] x1244 ইত্যাদিতে হয় যদি আমরা কেবল 5 টি যোগ করি 0x1230, আমরা 0x1235 পাই, যা ভুল।
জেমস কুরান

36
@ sr105: এটি + অপারেটরের জন্য একটি বিশেষ কেস, যেখানে অপারেন্ডগুলির মধ্যে একটি পয়েন্টার এবং অন্যটি পূর্ণসংখ্যা। স্ট্যান্ডার্ড বলছে যে ফলাফলটি পয়েন্টারের ধরণের হবে। সংকলক / যথেষ্ট / স্মার্ট হতে হবে।
আইবিব

48
"প্রাথমিক বিদ্যালয়ের গণিত থেকে আমরা জানি যে সেগুলি সমান" - আমি বুঝতে পেরেছি আপনি সরলীকরণ করছেন, তবে আমি তাদের সাথে আছি যারা এটিকে সরলকরণের চেয়ে বেশি মনে করেন । এটি প্রাথমিক নয় *(10 + (int *)13) != *((int *)10 + 13)। অন্য কথায়, এখানে প্রাথমিক বিদ্যালয়ের পাটিগণিতের চেয়ে আরও বেশি কিছু চলছে। যাতায়াতটি কোন অপারেন্ডটি পয়েন্টার (এবং কোন বস্তুর আকারের) তা স্বীকৃতি দিয়ে সংকলকটির উপর সমালোচনা করে। এটি অন্যভাবে রাখা (1 apple + 2 oranges) = (2 oranges + 1 apple), কিন্তু (1 apple + 2 oranges) != (1 orange + 2 apples)
LarsH

288

কারণ অ্যারে অ্যাক্সেস পয়েন্টারগুলির ক্ষেত্রে সংজ্ঞায়িত করা হয়। a[i]অর্থ *(a + i)সংজ্ঞাযুক্ত, যা পরিবর্তনশীল।


42
অ্যারেগুলি পয়েন্টারগুলির ক্ষেত্রে সংজ্ঞায়িত করা হয় না, তবে তাদের অ্যাক্সেস
কক্ষপথের হালকাতা রেস

5
আমি যোগ করব "সুতরাং এটি সমান *(i + a), যা হিসাবে লেখা যেতে পারে i[a]"।
জিম বাল্টার

4
আমি আপনাকে স্ট্যান্ডার্ডের উদ্ধৃতিটি অন্তর্ভুক্ত করার পরামর্শ দিচ্ছি যা নিম্নরূপ: 6.5.2.1: 2 একটি পোস্টফিক্স এক্সপ্রেশনটি বর্গাকার বন্ধনীগুলিতে একটি এক্সপ্রেশন দ্বারা অনুসরণ করা হয়েছে [] একটি অ্যারে অবজেক্টের একটি উপাদানটির সাবস্ক্রিপশনযুক্ত উপাধি। সাবস্ক্রিপ্ট অপারেটর [] এর সংজ্ঞাটি হ'ল E1 [E2] (* ((E1) + (E2))) এর সাথে সমান। বাইনারি + অপারেটরের ক্ষেত্রে রূপান্তর নিয়মের প্রযোজ্য কারণ, E1 যদি অ্যারে অবজেক্ট হয় (সমানভাবে, একটি অ্যারে অবজেক্টের প্রাথমিক উপাদানটির জন্য একটি পয়েন্টার) এবং E2 একটি পূর্ণসংখ্যা হয়, E1 [E2] এর E2-th উপাদান নির্ধারণ করে ই 1 (শূন্য থেকে গণনা)।
মূল্য

আরও সঠিক হতে: আপনি যখন অ্যাক্সেস করেন তখন অ্যারে পয়েন্টারগুলিতে ক্ষয় হয়।
12431234123412341234123

নিতপিক: এটি " *(a + i)পরিবর্তনশীল" বলে বোধগম্য নয় । যাইহোক, *(a + i) = *(i + a) = i[a]কারণ ছাড়াও বিনিময় হয়।
আন্দ্রেয়াস রেজব্র্যান্ড

231

আমি মনে করি অন্য উত্তরগুলি দিয়ে কিছু মিস হচ্ছে।

হ্যাঁ, p[i]সংজ্ঞা অনুসারে সমান *(p+i), যা (কারণ সংযোজনীয় হয়) এর সমতুল্য *(i+p), যা (আবার []অপারেটরের সংজ্ঞা অনুসারে ) সমতুল্য i[p]

(এবং এর মধ্যে array[i]অ্যারের নামটি সুস্পষ্টভাবে অ্যারের প্রথম উপাদানটিতে পয়েন্টারে রূপান্তরিত হয়))

তবে সংযোজনের যোগাযোগের বিষয়টি এই ক্ষেত্রে সুস্পষ্ট নয়।

উভয় operands একই ধরনের, অথবা এমনকি বিভিন্ন সাংখ্যিক ধরনের একটি সাধারণ ধরন উন্নীত করছে হয়, commutativity নির্ভুল জ্ঞান করে তোলে: x + y == y + x

তবে এই ক্ষেত্রে আমরা নির্দিষ্টভাবে পয়েন্টার গাণিতিক সম্পর্কে বলছি, যেখানে একটি অপারেন্ড একটি পয়েন্টার এবং অন্যটি একটি পূর্ণসংখ্যা। (পূর্ণসংখ্যা + পূর্ণসংখ্যা একটি পৃথক ক্রিয়াকলাপ, এবং পয়েন্টার + পয়েন্টারটি বাজে is

+অপারেটরের সি স্ট্যান্ডার্ডের বিবরণ ( N1570 6.5.6) বলেছেন:

অতিরিক্ত হিসাবে, উভয় অপারেন্ডের গাণিতিক টাইপ থাকবে, বা একটি অপারেন্ড একটি সম্পূর্ণ অবজেক্ট টাইপের পয়েন্টার এবং অন্যটির পূর্ণসংখ্যার টাইপ থাকবে।

এটি ঠিক যেমনটি বলতে পারত:

অতিরিক্ত হিসাবে, উভয় অপারেন্ডের গাণিতিক টাইপ থাকবে, বা বাম অপারেন্ড একটি সম্পূর্ণ অবজেক্ট টাইপের পয়েন্টার হবে এবং ডান অপারেন্ডের পূর্ণসংখ্যার প্রকার থাকবে।

উভয় ক্ষেত্রে i + pএবং i[p]অবৈধ হবে।

সি ++ পদে, আমাদের কাছে সত্যিই ওভারলোডেড +অপারেটরগুলির দুটি সেট রয়েছে , যা আলগাভাবে বর্ণনা করা যেতে পারে:

pointer operator+(pointer p, integer i);

এবং

pointer operator+(integer i, pointer p);

যার মধ্যে শুধুমাত্র প্রথমটি প্রয়োজনীয়।

তাহলে কেন এইভাবে?

সি ++ সি এর কাছ থেকে এই সংজ্ঞাটি উত্তরাধিকার সূত্রে পেয়েছে, যা এটি বি থেকে পেয়েছে (অ্যারে ইনডেক্সিংয়ের পরিবহণের বিষয়টি স্পষ্টভাবে উল্লিখিত হয়েছে ১৯২২ এর বি এর ব্যবহারকারীদের রেফারেন্সে ), যা এটি বিসিপিএল থেকে পেয়েছে (ম্যানুয়াল ১৯ 1967 তারিখের), এটি সম্ভবত এটি থেকেও অর্জন করেছে আগের ভাষা (সিপিএল? আলগোল?))

সুতরাং অ্যারে সূচকগুলি সংযোজনের শর্তে সংজ্ঞায়িত করা হয়েছে, এবং এটি যোগফল এমনকি একটি পূর্ণসংখ্যার এমনকি ক্রমবর্ধমান, বহু দশক ধরে সি এর পূর্বপুরুষের ভাষায় ফিরে যায়।

সেই ভাষাগুলি আধুনিক সি এর চেয়ে অনেক কম শক্তভাবে টাইপ করা হয়েছিল। বিশেষত, পয়েন্টার এবং পূর্ণসংখ্যার মধ্যে পার্থক্য প্রায়শই উপেক্ষা করা হয়। (প্রাথমিক পর্যায়ে সি প্রোগ্রামাররা কখনও কখনও unsignedভাষার সাথে কীওয়ার্ড যুক্ত হওয়ার আগে পয়েন্টারগুলিকে স্বাক্ষরবিহীন পূর্ণসংখ্যার হিসাবে ব্যবহার করত ।) সুতরাং অপারেটরগুলি বিভিন্ন ধরণের হওয়ায় সংযোজনকে অ-পরিবহণমূলক করার ধারণাটি সম্ভবত এই ভাষাগুলির ডিজাইনারদের কাছে ঘটেনি। যদি কোনও ব্যবহারকারী দুটি "জিনিস" যুক্ত করতে চেয়েছিলেন, তবে এই "জিনিসগুলি" পূর্ণসংখ্যা, পয়েন্টার বা অন্য কিছু হোক না কেন, এটি প্রতিরোধ করার জন্য এটি ভাষাটির উপর নির্ভর করে না।

এবং কয়েক বছর ধরে, সেই নিয়মে যে কোনও পরিবর্তনই বিদ্যমান কোডটি ভেঙে ফেলবে (যদিও 1989 এএনএসআই সি মানক একটি ভাল সুযোগ হতে পারে)।

বামদিকে পয়েন্টারটি লাগাতে সি এবং / অথবা সি ++ পরিবর্তন করা এবং ডানদিকে পূর্ণসংখ্যা কিছু বিদ্যমান কোডটি ভেঙে দিতে পারে, তবে প্রকৃত অভিব্যক্তিগত ক্ষতির কোনও ক্ষতি হবে না।

সুতরাং এখন আমাদের ঠিক একই জিনিস রয়েছে arr[3]এবং এর 3[arr]অর্থ হ'ল যদিও পরবর্তী ফর্মটি কখনও আইওসিসি-র বাইরে উপস্থিত না হওয়া উচিত ।


12
এই সম্পত্তিটির চমত্কার বিবরণ। উচ্চ পর্যায়ের দর্শন থেকে, আমি মনে করি 3[arr]এটি একটি আকর্ষণীয় নিদর্শন তবে কখনও ব্যবহার করা থাকলে খুব কমই করা উচিত। এই প্রশ্নের গ্রহণযোগ্য উত্তর (< স্ট্যাকওভারফ্লো.com/q/1390365/356> ) যা আমি কিছুক্ষণ আগে জিজ্ঞাসা করেছি সিনট্যাক্স সম্পর্কে আমার চিন্তাভাবনা বদলে গেছে। যদিও প্রযুক্তিগতভাবে প্রায়শই এই কাজগুলি করার জন্য সঠিক এবং ভুল উপায় নেই তবে এই ধরণের বৈশিষ্ট্যগুলি আপনাকে এমনভাবে ভাবতে শুরু করে যা বাস্তবায়নের বিশদ থেকে পৃথক। আপনি যখন বাস্তবায়নের বিশদটি স্থির করেন তখন এই বিভিন্ন ধরণের চিন্তাভাবনার সুবিধা রয়েছে part
দিনাহ

3
সংযোজন পরিবর্তনশীল। সি স্ট্যান্ডার্ডের জন্য এটি সংজ্ঞায়িত করা অন্যথায় আশ্চর্যজনক হবে। এ কারণেই এটি কেবল সহজেই বলা যায়নি "অতিরিক্ত হিসাবে, উভয় অপারেন্ডের গাণিতিক টাইপ থাকবে, বা বাম অপারেন্ডটি একটি সম্পূর্ণ অবজেক্ট টাইপের একটি পয়েন্টার এবং ডান অপারেন্ডের পূর্ণসংখ্যা টাইপ থাকবে।" - বেশিরভাগ লোকেরা যারা জিনিস যুক্ত করে তাদের পক্ষে তা বোঝা যায় না।
iheanyi

9
@ আইহানিই: সংযোজনটি সাধারণত পরিবর্তিত হয় - এবং এটি সাধারণত একই ধরণের দুটি অপারেন্ড গ্রহণ করে takes পয়েন্টার সংযোজন আপনাকে পয়েন্টার এবং একটি পূর্ণসংখ্যা যোগ করতে দেয় তবে দুটি পয়েন্টার নয়। আইএমএইচও এটি ইতিমধ্যে যথেষ্ট অদ্ভুত বিশেষ কেস যা পয়েন্টারটি বাম অপারেণ্ডের প্রয়োজন হয় তা উল্লেখযোগ্য বোঝা হবে না। (কিছু ভাষাগুলি স্ট্রিং কনটেনটেশনের জন্য "+" ব্যবহার করে; এটি অবশ্যই কমিউটেটিভ নয়))
কিথ থম্পসন

3
@ সুপের্যাট, এটি আরও খারাপ। এর অর্থ হ'ল কখনও কখনও x + 1! = 1 + x। এটি সংযোজনের সংস্থানমূলক সম্পত্তিকে সম্পূর্ণ লঙ্ঘন করবে।
iheanyi

3
@ আইহানেই: আমি মনে করি আপনার অর্থ পরিবহণ সম্পত্তি ছিল; সংযোজনটি ইতিমধ্যে সংঘবদ্ধ নয়, যেহেতু বেশিরভাগ বাস্তবায়নের (1LL + 1U) -2! = 1LL + (1U-2) এ। প্রকৃতপক্ষে, পরিবর্তনটি এমন কিছু পরিস্থিতি সংঘবদ্ধ করে তুলবে যা বর্তমানে নেই, যেমন 3U + (UINT_MAX-2L) সমান (3U + UINT_MAX) -2 হবে। ভাষার পক্ষে প্রচারমূলক পূর্ণসংখ্যা এবং "মোড়ক" বীজগণিতের রিংগুলির জন্য নতুন স্বতন্ত্র প্রকার যুক্ত করার পক্ষে সর্বোত্তমটি কী হবে, যাতে ring16_t65535 রুপ ধারণ করে এমন একটিতে 2 যোগ করার ফলে আকারের চেয়ে পৃথকring16_t মান 1 পাওয়া যায়int
সুপারক্যাট

196

এবং অবশ্যই

 ("ABCD"[2] == 2["ABCD"]) && (2["ABCD"] == 'C') && ("ABCD"[2] == 'C')

এর মূল কারণটি হ'ল 70 এর দশকে যখন সি ডিজাইন করা হয়েছিল, কম্পিউটারগুলিতে খুব বেশি মেমরি ছিল না (64 কেবি অনেক বেশি ছিল), তাই সি সংকলক খুব বেশি সিনট্যাক্স চেকিং করেনি। সুতরাং " X[Y]" এর পরিবর্তে অন্ধভাবে " *(X+Y)" অনুবাদ করা হয়েছিল

এটি " +=" এবং " ++" সিনট্যাক্সগুলিও ব্যাখ্যা করে । " A = B + C" ফর্মের প্রত্যেকটিরই একই সংকলিত ফর্ম ছিল। তবে, বি যদি এ হিসাবে একই জিনিস ছিল, তবে একটি সমাবেশ স্তর অপ্টিমাইজেশন উপলব্ধ ছিল। তবে সংকলক এটি সনাক্ত করতে যথেষ্ট উজ্জ্বল ছিল না, তাই বিকাশকারীকে ( A += C) করতে হয়েছিল। একইভাবে, যদি Cহয় তবে 1একটি পৃথক সমাবেশ স্তরের অপ্টিমাইজেশন উপলব্ধ ছিল এবং আবার বিকাশকারীকে এটিকে স্পষ্ট করে দিতে হয়েছিল, কারণ সংকলক এটি সনাক্ত করতে পারে নি। (অতি সাম্প্রতিক সংকলকগণ তাই করেন, সুতরাং সেই বাক্য গঠনগুলি আজকাল বেশিরভাগ ক্ষেত্রে অপ্রয়োজনীয়)


127
আসলে, যা মিথ্যা মূল্যায়ন করে; প্রথম শব্দ "এবিসিডি" [2] == 2 ["এবিসিডি"] সত্য, বা 1, এবং 1 এর মূল্যায়ন করে! = 'সি': ডি
জোনাথন লেফলার

8
@ জোনাথন: এই পোস্টের মূল শিরোনাম সম্পাদনা করতে একই দ্বিধা প্রকাশ করে। আমরা কি গাণিতিক সমতুল্যতা, কোড সিনট্যাক্স বা সিউডো-কোড সমান চিহ্ন? আমি গাণিতিক সমতুল্যতার পক্ষে যুক্তি দিচ্ছি তবে যেহেতু আমরা কোডের কথা বলছি, আমরা এড়াতে পারি না যে আমরা কোড বাক্য বিন্যাসের দিক দিয়ে সবকিছু দেখছি।
দিনাহ

19
এটি কি কোনও মিথ নয়? আমি বোঝাতে চাইছি যে ++ এবং ++ অপারেটরগুলি সংকলকটির জন্য সহজ করার জন্য তৈরি হয়েছিল? কিছু কোড তাদের সাথে আরও পরিষ্কার হয়ে যায় এবং সংকলক এটির সাথে যা কিছু করে তা বিবেচ্য নয় এটি দরকারী সিনট্যাক্স।
টমাস প্যাড্রন-ম্যাকার্থি

6
+ = এবং ++ এর আরও একটি উল্লেখযোগ্য সুবিধা রয়েছে। বাম দিকটি যদি মূল্যায়নের সময় কিছু পরিবর্তনশীল পরিবর্তন করে তবে পরিবর্তনটি একবারেই করা হবে। a = a + ...; দু'বার করবে
জোহানেস স্কাওব -

8
না - "এবিসিডি" [2] == * ("এবিসিডি" + 2) = * ("সিডি") = 'সি'। স্ট্রিংকে
ডিফারেন্সিং

55

দিনাহর সমস্যা সম্পর্কে কারও কারও উল্লেখ নেই বলে মনে হয় sizeof:

আপনি কেবলমাত্র একটি পয়েন্টারে একটি পূর্ণসংখ্যা যোগ করতে পারেন, আপনি দুটি পয়েন্টার একসাথে যোগ করতে পারবেন না। এইভাবে কোনও পূর্ণসংখ্যার সাথে কোনও পয়েন্টার বা পয়েন্টারের সাথে কোনও পূর্ণসংখ্যার যোগ করার সময়, সংকলকটি সর্বদা জানে যে কোন বিটের একটি আকার রয়েছে যা বিবেচনায় নেওয়া উচিত।


1
গৃহীত উত্তরের মন্তব্যে এটি সম্পর্কে মোটামুটি বিবর্ণ কথোপকথন রয়েছে। আমি মূল প্রশ্নের সাথে সম্পাদনাতে কথোপকথনটি উল্লেখ করেছি তবে আকারের বিষয়ে আপনার খুব বৈধ উদ্বেগকে সরাসরি সম্বোধন করিনি। SO এ কীভাবে সেরা করবেন তা নিশ্চিত নন। আমি কি উত্সটিতে অন্য একটি সম্পাদনা করব? প্রশ্ন?
দিনাহ

50

আক্ষরিকভাবে প্রশ্নের উত্তর দিতে। এটি সবসময় সত্য নয়x == x

double zero = 0.0;
double a[] = { 0,0,0,0,0, zero/zero}; // NaN
cout << (a[5] == 5[a] ? "true" : "false") << endl;

কপি করে প্রিন্ট

false

27
আসলে একটি "নান" নিজের সমান নয়: cout << (a[5] == a[5] ? "true" : "false") << endl;হয় false
সত্য

8
@ ট্রুই: তিনি উল্লেখ করেছিলেন যে বিশেষ করে এনএএন মামলার জন্য (এবং বিশেষত এটি x == xসর্বদা সত্য নয়)। আমার মনে হয় এটাই ছিল তাঁর উদ্দেশ্য। সুতরাং তিনি প্রযুক্তিগতভাবে সঠিক (এবং সম্ভবত তারা যেমন বলেছেন, সর্বোত্তম ধরণের সঠিক!)।
টিম Čas

3
প্রশ্নটি সি সম্পর্কে, আপনার কোডটি সি কোড নয়। এখানে একটা হল NANমধ্যে <math.h>, যা বেশী ভালো 0.0/0.0, কারণ 0.0/0.0UB যখন __STDC_IEC_559__সংজ্ঞায়িত করা হয় না (সর্বাধিক বাস্তবায়নের সংজ্ঞায়িত করেন না __STDC_IEC_559__, কিন্তু অধিকাংশ বাস্তবায়নের উপর 0.0/0.0লেগে থাকব কর্মস্থল)
12431234123412341234123

26

আমি কেবল এটি খুঁজে পেয়েছি যে এই কুরুচিপূর্ণ সিনট্যাক্সটি "দরকারী" হতে পারে, বা আপনি যখন একই অ্যারেতে অবস্থানগুলি উল্লেখ করেন এমন সূচিগুলির একটি অ্যারে নিয়ে কাজ করতে চান তখন খেলতে কমপক্ষে খুব মজাদার। এটি নেস্টেড বর্গাকার বন্ধনীগুলি প্রতিস্থাপন করতে এবং কোডটিকে আরও পঠনযোগ্য করে তুলতে পারে!

int a[] = { 2 , 3 , 3 , 2 , 4 };
int s = sizeof a / sizeof *a;  //  s == 5

for(int i = 0 ; i < s ; ++i) {  

           cout << a[a[a[i]]] << endl;
           // ... is equivalent to ... 
           cout << i[a][a][a] << endl;  // but I prefer this one, it's easier to increase the level of indirection (without loop)

}

অবশ্যই, আমি নিশ্চিত যে সত্যিকারের কোডটিতে এর জন্য কোনও ব্যবহারের ঘটনা নেই তবে আমি এটি আকর্ষণীয় মনে করি :)


আপনি যখন দেখেন i[a][a][a]যে আমি হয় একটি অ্যারের পয়েন্টার বা একটি অ্যারে বা অ্যারেতে পয়েন্টারের একটি অ্যারে ... এবং aএকটি সূচক। আপনি যখন দেখবেন a[a[a[i]]], আপনি একটি অ্যারে বা অ্যারের পয়েন্টার হিসাবে মনে করেন এবং iএটি একটি সূচক।
12431234123412341234123

1
কি দারুন! এটি এই "বোকা" বৈশিষ্ট্যটির খুব দুর্দান্ত ব্যবহার। কিছু সমস্যার ক্ষেত্রে অ্যালগরিদমিক প্রতিযোগিতায় দরকারী হতে পারে))
সার্জে ব্রেসোভ

26

সুন্দর প্রশ্ন / উত্তর।

কেবল উল্লেখ করতে চাই যে সি পয়েন্টার এবং অ্যারেগুলি একই নয় , যদিও এই ক্ষেত্রে পার্থক্যটি অপরিহার্য নয়।

নিম্নলিখিত ঘোষণা বিবেচনা করুন:

int a[10];
int* p = a;

ইন a.out, প্রতীকটি aএমন ঠিকানায় থাকে যা অ্যারের শুরু হয় এবং প্রতীকটি pএমন ঠিকানায় থাকে যেখানে একটি পয়েন্টার সঞ্চিত থাকে এবং সেই মেমরির অবস্থানের পয়েন্টারের মান অ্যারের শুরু হয়।


2
না, প্রযুক্তিগতভাবে তারা এক নয়। যদি আপনি কিছু খকে ইন্ট * কনস্ট হিসাবে সংজ্ঞায়িত করেন এবং এটিকে একটি অ্যারের দিকে নির্দেশ করেন তবে এটি এখনও একটি পয়েন্টার, যার অর্থ প্রতীক টেবিলের মধ্যে, বি একটি স্মৃতি অবস্থানকে বোঝায় যা একটি ঠিকানা সংরক্ষণ করে, যা ঘুরিয়েটি অ্যারে যেখানে অবস্থিত ।
পলিথিংকার

4
খুব ভাল পয়েন্ট। আমার মনে আছে যখন আমি একটি মডিউলে চর s [100] হিসাবে বিশ্বব্যাপী প্রতীকটি সংজ্ঞায়িত করেছি, তখন এটি বহিরাগত চর * গুলি হিসাবে ঘোষণা করব; অন্য একটি মডিউল মধ্যে। এগুলি একসাথে যুক্ত করার পরে প্রোগ্রামটি খুব আশ্চর্যের সাথে আচরণ করেছিল। বাহ্যিক ঘোষণার সাহায্যে মডিউলটি অ্যারের প্রাথমিক বাইটগুলি চরকে নির্দেশক হিসাবে ব্যবহার করছে।
জর্জিও

1
মূলত, সি এর পিতামহ বিসিপিএলে একটি অ্যারে ছিল পয়েন্টার। এটি হ'ল, আপনি লেখার সময় আপনি যা পেয়েছিলেন (আমি সিতে প্রতিলিপি করেছি) int a[10]এটি 'এ' নামে একটি পয়েন্টার ছিল, যা অন্য কোথাও 10 পূর্ণসংখ্যার জন্য পর্যাপ্ত স্টোরকে নির্দেশ করেছিল। এইভাবে একটি + i এবং জে + আমার একই ফর্ম ছিল: কয়েক মেমরি অবস্থানের বিষয়বস্তু যুক্ত করুন। আসলে, আমি মনে করি বিসিপিএল টাইপহীন ছিল, তাই তারা অভিন্ন ছিল। এবং আকারের ধরণের স্কেলিং প্রযোজ্য হয়নি, যেহেতু বিসিপিএল খাঁটি শব্দ-ভিত্তিক ছিল (শব্দ-সম্বোধনকারী মেশিনগুলিতেও)।
ডেভ

আমি মনে করি পার্থক্যটি বোঝার সর্বোত্তম উপায়টি পরবর্তীটির সাথে তুলনা int*p = a;করা int b = 5;, "বি" এবং "5" উভয়ই পূর্ণসংখ্যা, তবে "বি" একটি পরিবর্তনশীল, তবে "5" একটি নির্দিষ্ট মান। একইভাবে, "পি" এবং "ক" হ'ল একটি চরিত্রের ঠিকানা, তবে "ক" একটি নির্দিষ্ট মান।
জেমস কারান

20

সি পয়েন্টার জন্য, আমাদের আছে

a[5] == *(a + 5)

এবং আরো

5[a] == *(5 + a)

সুতরাং এটি সত্য যে a[5] == 5[a].


15

কোনও উত্তর নয়, কেবল চিন্তার জন্য কিছু খাবার। শ্রেণিতে যদি অতিরিক্ত ওভারলোডড ইনডেক্স / সাবস্ক্রিপ্ট অপারেটর থাকে তবে অভিব্যক্তিটি 0[x]কাজ করবে না:

class Sub
{
public:
    int operator [](size_t nIndex)
    {
        return 0;
    }   
};

int main()
{
    Sub s;
    s[0];
    0[s]; // ERROR 
}

যেহেতু আমরা আত এক্সেস আছে int- এ বর্গ, এই কাজ করা যেতে পারে:

class int
{
   int operator[](const Sub&);
};

2
class Sub { public: int operator[](size_t nIndex) const { return 0; } friend int operator[](size_t nIndex, const Sub& This) { return 0; } };
বেন ভয়েগট

1
আপনি কি আসলে এটি সংকলনের চেষ্টা করেছেন? অপারেটরদের এমন কিছু সেট রয়েছে যা শ্রেণীর বাইরে প্রয়োগ করা যায় না (অর্থাত্ অ স্থির ফাংশন হিসাবে)!
অজয়

3
উফ, ঠিক বলেছেন " operator[]হ'ল একটি পরামিতি সহ একটি অ স্থিতিশীল সদস্য ফাংশন হবে" " আমি এই নিষেধাজ্ঞার সাথে পরিচিত ছিলাম operator=, এটি প্রয়োগ করে বলে মনে হয় না []
বেন ভয়েগট

1
অবশ্যই, যদি তোমরা সংজ্ঞা পরিবর্তন []অপারেটর, এটা সমতুল্য আবার না হবে ... যদি a[b]সমান *(a + b)এবং আপনি এই পরিবর্তন করেন, আপনার কাছে জমিদার করতে হবে int::operator[](const Sub&);এবং intএকটি বর্গ ... নয়
লুইস কলোরাডো

7
এই ... না ... সি।
এমডি এক্সএফ

11

টেড জেনসেনের টিউটরিয়াল অন পয়েন্টারস এবং সি ইন ইন অ্যারেটিতে এর খুব ভাল ব্যাখ্যা রয়েছে ।

টেড জেনসেন এটিকে ব্যাখ্যা করেছেন:

প্রকৃতপক্ষে, এটি সত্য, অর্থাৎ যে কোনও যেখানেই লিখুন এটি কোনও সমস্যা ছাড়াই a[i]প্রতিস্থাপন করা যেতে পারে *(a + i)। আসলে, সংকলক উভয় ক্ষেত্রে একই কোড তৈরি করবে। সুতরাং আমরা দেখতে পয়েন্টার পাটিগণিত অ্যারে ইনডেক্সিং একই জিনিস। হয় সিনট্যাক্স একই ফলাফল উত্পাদন করে।

এটি বলছে না যে পয়েন্টার এবং অ্যারে একই জিনিস, তারা তা নয়। আমরা কেবল এটিই বলছি যে অ্যারের প্রদত্ত উপাদানটি সনাক্ত করতে আমাদের কাছে দুটি বাক্য গঠন রয়েছে, একটি অ্যারে সূচক ব্যবহার করে এবং অন্যটি পয়েন্টার গাণিতিক ব্যবহার করে, যা অভিন্ন ফলাফল দেয়।

এখন, এই শেষ অভিব্যক্তিটির দিকে লক্ষ্য করা, এটির (a + i)একটি অংশ, + অপারেটর এবং সি এর নিয়ম ব্যবহার করে একটি সাধারণ সংযোজন যা এই ধরনের অভিব্যক্তিটি পরিবহণযোগ্য। এটি (a + i) এর সাথে অভিন্ন (i + a)। সুতরাং আমরা *(i + a)ঠিক হিসাবে সহজে লিখতে পারে *(a + i)। তবে *(i + a)কি আসতে পারত i[a]! এই সমস্ত থেকে কৌতূহলী সত্য আসে যে যদি:

char a[20];

লেখা

a[3] = 'x';

লেখার মতোই

3[a] = 'x';

4
a + i সহজ সংযোজন নয়, কারণ এটি পয়েন্টার গাণিতিক। যদি একটি এর উপাদানটির আকার 1 (চর) হয় তবে হ্যাঁ, এটি ঠিক পূর্ণসংখ্যার মতো। তবে এটি যদি (যেমন) কোনও পূর্ণসংখ্যার হয় তবে এটি একটি + 4 * i এর সমতুল্য হতে পারে।
অ্যালেক্স ব্রাউন

@ অ্যালেক্সব্রাউন হ্যাঁ, এটি পয়েন্টার গাণিতিক, ঠিক এই কারণেই আপনার শেষ বাক্যটি ভুল, যদি না আপনি প্রথমে 'ক' কে (চর *) হিসাবে গণ্য করেন (ধরে নেওয়া যাক যে কোনও চারটি চর হয়)। আমি সত্যিই বুঝতে পারছি না কেন এত লোক পয়েন্টার গাণিতিকের আসল মান ফলাফলের জন্য ঝুলছে। পয়েন্টার গাণিতিকের পুরো উদ্দেশ্য হ'ল অন্তর্নিহিত পয়েন্টার মানগুলি বিমূর্ত করা এবং প্রোগ্রামারকে ঠিকানা মানগুলির পরিবর্তে বস্তুগুলি হেরফের করা সম্পর্কে ভাবা উচিত।
jschultz410

8

আমি জানি প্রশ্নের উত্তর হয়েছে, কিন্তু আমি এই ব্যাখ্যাটি ভাগ করে নিতে পারিনি।

আমি কম্পাইলার ডিজাইনের নীতিগুলি মনে করি, আসুন ধরে aনেওয়া যাক একটি intঅ্যারে এবং আকার int2 বাইট, এবং এর জন্য বেইস ঠিকানা a1000 is

কিভাবে a[5]কাজ করবে ->

Base Address of your Array a + (5*size of(data type for array a))
i.e. 1000 + (5*2) = 1010

সুতরাং,

একইভাবে সি কোডটি যখন 3-ঠিকানা কোডে বিভক্ত হয়, তখন 5[a]-> হয়ে যাবে

Base Address of your Array a + (size of(data type for array a)*5)
i.e. 1000 + (2*5) = 1010 

সুতরাং মূলত উভয় বক্তব্যই একই অবস্থানের দিকে স্মরণ করে মেমরি এবং তাই a[5] = 5[a],।

এই ব্যাখ্যার কারণেই অ্যারেতে নেতিবাচক সূচকগুলি সি-তে কাজ করে reason

আমি যদি a[-5]এটি অ্যাক্সেস করি তবে তা আমাকে দেবে

Base Address of your Array a + (-5 * size of(data type for array a))
i.e. 1000 + (-5*2) = 990

এটি 990 অবস্থানে আমার আপত্তিটি ফিরিয়ে দেবে।


6

ইন সি অ্যারে , arr[3]এবং 3[arr]একই, এবং তাদের সমতুল্য পয়েন্টার স্বরলিপি হয় *(arr + 3)থেকে *(3 + arr)। তবে বিপরীতে [arr]3বা [3]arrসঠিক নয় এবং এর ফলে সিনট্যাক্স ত্রুটি হবে (arr + 3)*এবং (3 + arr)*বৈধ এক্সপ্রেশন নয়। কারণ হ'ল ডেরিফারেন্স অপারেটরটি ঠিকানার পরে নয়, অভিব্যক্তির দ্বারা উত্পন্ন ঠিকানার আগে স্থাপন করা উচিত।



5

একটু ইতিহাস এখন। অন্যান্য ভাষার মধ্যে, বিসিপিএল সি এর প্রাথমিক বিকাশে মোটামুটি বড় প্রভাব ফেলেছিল। আপনি যদি বিসিপিএলে কোনও অ্যারে হিসাবে ঘোষণা করেন তবে:

let V = vec 10

এটি আসলে মেমরির ১১ টি শব্দের বরাদ্দ করে, ১০ নয় Typ সি এর বিপরীতে, ভি নামকরণ করা লোকেশন সেই জায়গায় গিয়ে অ্যারের শূন্যতম উপাদানের ঠিকানাটি তুলেছে। অতএব, বিসিপিএল-এ অ্যারে ইন্ডাইরেশন, হিসাবে প্রকাশিত

let J = V!5

J = !(V + 5)অ্যারেটির মূল ঠিকানা পেতে ভিচ আনার প্রয়োজন হওয়ায় আসলেই (বিসিপিএল সিনট্যাক্স ব্যবহার করে) করতে হয়েছিল। এইভাবে V!5এবং 5!Vপ্রতিশব্দ ছিল। একটি উপাখ্যান পর্যবেক্ষণ হিসাবে, ডাব্লুএএফএল (ওয়ারউইক ফাংশনাল ল্যাঙ্গুয়েজ) বিসিপিএলে লেখা হয়েছিল, এবং আমার স্মৃতিতে সবচেয়ে ভালভাবে ডেটা স্টোরেজ হিসাবে ব্যবহৃত নোডগুলিতে অ্যাক্সেস করার চেয়ে পূর্বের সিন্টেক্স ব্যবহার করার প্রবণতা ছিল। অনুমোদিত যে এটি কোথাও 35 থেকে 40 বছর আগে থেকে এসেছে, তাই আমার স্মৃতিশক্তি কিছুটা মরিচা। :)

স্টোরেজের অতিরিক্ত শব্দের সাথে বিতরণ এবং সংকলকটি অ্যারের নাম ঠিকানা যুক্ত হওয়ার পরে প্রবেশের মূল ঠিকানা সন্নিবেশ করানোর নতুনত্বটি পরে এলো। সি ইতিহাসের কাগজ অনুসারে সিটির সাথে কাঠামোগুলি যুক্ত হওয়ার সময় এটি ঘটেছিল paper

নোট করুন যে !বিসিপিএল উভয় ক্ষেত্রেই ইন্ডিरेশন করায় একটি অযৌক্তিক উপসর্গ অপারেটর এবং বাইনারি ইনফিক্স অপারেটর ছিল। ঠিক যে বাইনারি ফর্মটি ইন্ডিয়ারেশন করার আগে দুটি অপারেশন যুক্ত করেছিল। বিসিপিএল (এবং বি) এর ওরিয়েন্টেড প্রকৃতির শব্দটি দেওয়া আসলে এটি অনেকটা অর্থবোধ করেছিল। "পয়েন্টার এবং পূর্ণসংখ্যার" সীমাবদ্ধতা সি তে প্রয়োজনীয় করা হয়েছিল যখন এটি ডেটা প্রকার অর্জন করে এবং sizeofএকটি জিনিস হয়ে যায়।


1

ঠিক আছে, এটি এমন একটি বৈশিষ্ট্য যা কেবলমাত্র ভাষা সমর্থনের কারণে সম্ভব।

সংকলকটি ব্যাখ্যা a[i]করে *(a+i)এবং এক্সপ্রেশনটি 5[a]মূল্যায়ন করে *(5+a)। যেহেতু সংযোজনটি পরিবহণযোগ্য তাই দেখা যাচ্ছে যে উভয়ই সমান। সুতরাং অভিব্যক্তি মূল্যায়ন true


অপ্রয়োজনীয় যদিও এটি স্পষ্ট, সংক্ষিপ্ত এবং সংক্ষিপ্ত।
বিল কে

0

সি তে

 int a[]={10,20,30,40,50};
 int *p=a;
 printf("%d\n",*p++);//output will be 10
 printf("%d\n",*a++);//will give an error

পয়েন্টার একটি "পরিবর্তনশীল"

অ্যারের নাম একটি "স্মৃতিচক্র" বা "প্রতিশব্দ"

p++;বৈধ তবে a++অবৈধ

a[2] এটি 2 [a] এর সমান কারণ এই উভয়টির অভ্যন্তরীণ ক্রিয়াকলাপ

"পয়েন্টার গাণিতিক" অভ্যন্তরীণ হিসাবে গণনা করা হয়

*(a+3) সমান *(3+a)


-4

পয়েন্টার প্রকার

1) তথ্য নির্দেশক

int *ptr;

2) ডেটাতে কনস্ট পয়েন্টার

int const *ptr;

3) কনস্ট ডেটাতে কনস্ট পয়েন্টার

int const *const ptr;

এবং অ্যারেগুলি আমাদের তালিকা থেকে টাইপের (2) হয়
আপনি যখন কোনও সময় অ্যারে সংজ্ঞা দেন তখন একটি সূত্র সেই পয়েন্টারে আরম্ভ হয়
কারণ আমরা জানি যে আমরা আমাদের প্রোগ্রামে কনস্টের মানটি পরিবর্তন বা সংশোধন করতে পারি না কারণ এটি সংকলনের সময় একটি ত্রুটি ছুড়ে ফেলেছে সময়

আমি যে প্রধান পার্থক্যটি পেয়েছি তা হ'ল ...

আমরা কোনও ঠিকানার মাধ্যমে পয়েন্টারটি পুনরায় আরম্ভ করতে পারি তবে অ্যারের সাথে একই ক্ষেত্রে নয়।

======
এবং আপনার প্রশ্নের করা হচ্ছে ...
a[5]কিছুই নয় কিন্তু *(a + 5)
আপনি খুব সহজেই বুঝতে পারেন
a - ঠিকানা ধারণকারী (মানুষের বেস ঠিকানা হিসাবে সেটিতে কল) শুধু একটি (2) আমাদের তালিকায় পয়েন্টার ধরণ মত
[]- যে অপারেটর হতে পারে পয়েন্টার সহ প্রতিস্থাপনযোগ্য *

তাই শেষ পর্যন্ত ...

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