একটি অ্যারের ঠিকানা সি এর মানের সমান হয় কীভাবে?


189

নিম্নলিখিত কোডের বিটগুলিতে, পয়েন্টার মান এবং পয়েন্টার ঠিকানাগুলি প্রত্যাশার সাথে পৃথক হয়।

কিন্তু অ্যারে মান এবং ঠিকানাগুলি না!

এটা কিভাবে হতে পারে?

আউটপুট

my_array = 0022FF00
&my_array = 0022FF00
pointer_to_array = 0022FF00
&pointer_to_array = 0022FEFC
#include <stdio.h>

int main()
{
  char my_array[100] = "some cool string";
  printf("my_array = %p\n", my_array);
  printf("&my_array = %p\n", &my_array);

  char *pointer_to_array = my_array;
  printf("pointer_to_array = %p\n", pointer_to_array);
  printf("&pointer_to_array = %p\n", &pointer_to_array);

  printf("Press ENTER to continue...\n");
  getchar();
  return 0;
}

কমপ্লেং.এল.সি.এফ.একিউ থেকে: - [তাহলে সি এর poin poin পয়েন্টার এবং অ্যারেগুলির সমতুল্যতা বলতে কী বোঝায়? ] ( c-faq.com/aryptr/aryptrequiv.html ) - [যেহেতু অ্যারে রেফারেন্সগুলি পয়েন্টারে ক্ষয় হয়, যদি অ্যারেরটি একটি অ্যারে হয় তবে অ্যারে এবং আরারের মধ্যে পার্থক্য কী? ] ( c-faq.com/aryptr/aryvsadr.html ) অথবা পুরো অ্যারে এবং পয়েন্টার বিভাগটি পড়ুন।
জেমসডলিন

3
আমি এই প্রশ্নে ডায়াগ্রামের সাথে একটি উত্তর যুক্ত করেছি দুই বছর আগে এখানে কী sizeof(&array)ফিরে আসে?
গ্রিজেশ চৌহান

উত্তর:


212

একটি অ্যারের নাম সাধারণত অ্যারের প্রথম উপাদানটির ঠিকানা মূল্যায়ন করে, arrayএবং &arrayএকই মান হয় (তবে বিভিন্ন ধরণের, সুতরাং array+1এবং অ্যারের 1 টির বেশি উপাদানের বেশি হলে সমান &array+1হবে না )।

এর দুটি ব্যতিক্রম রয়েছে: যখন অ্যারের নামটি অপারেন্ড sizeofবা আনরি &(অ্যাড্রেস অফ) হয় তখন নামটি অ্যারে অবজেক্টকেই বোঝায়। সুতরাং sizeof arrayআপনাকে পুরো অ্যারের বাইটে আকার দেয়, পয়েন্টারের আকার নয়।

হিসাবে সংজ্ঞায়িত অ্যারের জন্য T array[size]এটির ধরণ থাকবে T *। আপনি / যখন এটি বৃদ্ধি করেন, আপনি অ্যারেতে পরবর্তী উপাদানটি পাবেন।

&arrayএকই ঠিকানায় মূল্যায়ন করে, তবে একই সংজ্ঞা দেওয়া থাকলে, এটি টাইপের একটি পয়েন্টার তৈরি করে T(*)[size]- যেমন এটি কোনও অ্যারেতে বিন্দু নয়, কোনও উপাদানকে নয়। আপনি যদি এই পয়েন্টারটি বাড়ান, তবে এটি সম্পূর্ণ অ্যারের আকার যুক্ত করবে, একটি একক উপাদানের আকার নয়। উদাহরণস্বরূপ, এই জাতীয় কোড সহ:

char array[16];
printf("%p\t%p", (void*)&array, (void*)(&array+1));

আমরা দ্বিতীয় পয়েন্টারটি প্রথমটির চেয়ে 16 টি বেশি হওয়ার আশা করতে পারি (কারণ এটি 16 চরের এর অ্যারে)। যেহেতু% পি হেক্সাডেসিমালগুলিতে পয়েন্টারগুলিকে সাধারণত রূপান্তর করে তাই এটি দেখতে এর মতো দেখতে পারে:

0x12341000    0x12341010

3
@ অ্যালেক্সানড্রে: &arrayঅ্যারের প্রথম উপাদানটির একটি পয়েন্টার, যেখানে arrayপুরো অ্যারে বোঝায়। মৌলিক পার্থক্য এছাড়াও তুলনা করে পালন করা sizeof(array)যেতে পারে sizeof(&array)। তবে খেয়াল করুন যে আপনি যদি arrayকোনও ফাংশনের পক্ষে যুক্তি হিসাবে পাস করেন তবে কেবল &arrayবাস্তবেই এটি পাস করা হয়েছে। আপনি যদি কোনও অ্যারে দিয়ে এনপ্যাপুলেটেড না হন তবে মান দ্বারা আপনি কোনও অ্যারে পাস করতে পারবেন না struct
ক্লিফোর্ড

14
@ ক্লিফোর্ড: আপনি যদি কোনও ফাংশনে অ্যারে পাস করেন তবে এটি তার প্রথম উপাদানটির একটি পয়েন্টারকে এত কার্যকরভাবে &array[0]পাস করার সিদ্ধান্ত নিয়েছে, &arrayযা অ্যারেতে নির্দেশক হবে না। এটি নিট-পিক হতে পারে তবে আমি মনে করি এটি পরিষ্কার করা গুরুত্বপূর্ণ; সংস্থাগুলি সতর্ক করবে যদি ফাংশনটিতে এমন কোনও প্রোটোটাইপ থাকে যা পয়েন্টারের মধ্যে চলে যাওয়ার ধরণের সাথে মেলে
সিবি বেইলি

2
@ জেরি কফিন উদাহরণস্বরূপ int * p = & a এর জন্য, যদি আমি ইন্ট পয়েন্টার পি এর মেমরি ঠিকানা চাই, আমি & পি করতে পারি। & অ্যারে পুরো অ্যারের ঠিকানায় রূপান্তর করে (যা প্রথম উপাদানটির ঠিকানায় শুরু হয়)। তারপরে আমি অ্যারে পয়েন্টারের (যা অ্যারেতে প্রথম উপাদানটির ঠিকানা সঞ্চয় করে) এর মেমরি ঠিকানাটি কীভাবে খুঁজে পাব? এটা নিশ্চয়ই কোথাও স্মৃতি আছে?
জন লি

2
@ জনলি: না, স্মৃতিতে কোথাও অ্যারেটির পয়েন্টার হওয়ার দরকার নেই। আপনি যদি একটি পয়েন্টার তৈরি করেন, তারপর আপনি এটির ঠিকানা নিতে পারেন: int *p = array; int **pp = &p;
জেরি কফিন

3
@ ক্লিফোর্ড প্রথম মন্তব্যটি ভুল, এখনও এটি রাখছেন কেন? আমি মনে করি এটি নিম্নলিখিত (@ চারেলস) জবাবটি পড়েন না তাদের জন্য ভুল বুঝাবুঝির কারণ হতে পারে।
রিক

30

এর কারণ অ্যারের নাম ( my_array) পয়েন্টার থেকে অ্যারে পৃথক হয়। এটি একটি অ্যারের ঠিকানার একটি উপনাম এবং এর ঠিকানাটি অ্যারের ঠিক নিজের ঠিকানা হিসাবে সংজ্ঞায়িত করা হয়।

তবে পয়েন্টারটি স্ট্যাকের একটি সাধারণ সি পরিবর্তনশীল। সুতরাং, আপনি এটির ঠিকানা নিতে পারেন এবং এটি ভিতরে থাকা ঠিকানা থেকে আলাদা মান পেতে পারে।

আমি এই বিষয় সম্পর্কে এখানে লিখেছি - দয়া করে একবার দেখুন।


আমার_আরয়ের মান স্ট্যাকের উপর না থাকায় & আমার_আরিকে কোনও অবৈধ অপারেশন হওয়া উচিত নয়, কেবল আমার_আররে [0 ... দৈর্ঘ্য]? তাহলে এটি সমস্ত অর্থবহ হয়ে উঠবে ...
আলেকজান্দ্রে

@ আলেকজান্দ্রে: আসলে কেন এটি অনুমোদিত তা নিশ্চিত নই।
এলি বেন্ডারস্কি

registerস্থিতিশীল, গতিশীল বা স্বয়ংক্রিয়: আপনি যেকোন ভেরিয়েবলের ঠিকানা নিতে পারেন (যদি চিহ্নিত না করা হয় ) তবে তার স্টোরেজ সময়কাল।
সিবি বেইলি

my_arrayখোদ স্ট্যাক কারণ my_array হল সম্পূর্ণ অ্যারে।
ক্যাফে

3
my_array, যখন অপারেটরগুলির বিষয় নয় &বা sizeofতার প্রথম উপাদানটির (যেমন। &my_array[0]) নির্দেশকের কাছে মূল্যায়ন করা হয় - তবে my_arrayনিজেই সেই পয়েন্টারটি হয় না ( my_arrayএখনও অ্যারে হয়)। এই পয়েন্টারটি কেবল একটি সাময়িক মূল (যেমন প্রদত্ত int a;, এটি ঠিক তেমন a + 1) - ধারণাটি কমপক্ষে এটি "প্রয়োজনীয় হিসাবে গণনা করা হয়"। আসল "মান" my_arrayপুরো অ্যারের সামগ্রীর বিষয়বস্তু - এটি ঠিক যে এই মানটি সিতে পিন করা একটি জারে কুয়াশা ধরার চেষ্টা করার মতো।
ক্যাফে

27

সি, যখন আপনি একটি এক্সপ্রেশনে একটি অ্যারের নাম ব্যবহার (ক ফাংশন এটি ক্ষণস্থায়ী সহ) যদি না তা ঠিকানা অফ (এর প্রতীক হল &) অপারেটর বা sizeofঅপারেটর, এটা decays তার প্রথম উপাদান একটি পয়েন্টার করতে।

যে, বেশিরভাগ প্রসঙ্গে উভয় প্রকার এবং মান arrayসমান &array[0]

আপনার উদাহরণে, my_arrayটাইপ করুন char[100]যা প্রিন্টএফ এ char*পাস করার সময় কোনটির সিদ্ধান্ত নেয়।

&my_arrayটাইপ char (*)[100](100 এর অ্যারে পয়েন্টার char) আছে। যেমন এটি অপরেন্ড &, এটি এমন একটি ক্ষেত্রে যা my_arrayতার প্রথম উপাদানটির সাথে সাথে কোনও পয়েন্টারের সাথে সাথে ক্ষয় হয় না।

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

pointer_to_arrayটাইপ আছে char *- অ্যারের প্রথম উপাদানটিকে নির্দেশ করতে ইনিশিয়ালাইজড হিসাবে my_arrayএটি ইনিশিয়ালার এক্সপ্রেশনটিতে কী ক্ষয় হয় - এবং &pointer_to_array এর টাইপ char **(পয়েন্টার এ এ পয়েন্টার char) থাকে।

এর মধ্যে: my_array(ক্ষয় হওয়ার পরে char*), &my_arrayএবং pointer_to_arrayসমস্ত বিন্দু সরাসরি অ্যারে বা অ্যারের প্রথম উপাদানটিতে হয় এবং তাই একই ঠিকানা মান হয় have


3

কারণ my_arrayএবং &my_arrayএকই ঠিকানাতে ফলাফলের সহজে বোঝা যাবে যখন আপনি একটি অ্যারের মেমরির বিন্যাস দিকে তাকাও।

ধরা যাক আপনার 10 টি অক্ষরের অ্যারে রয়েছে (পরিবর্তে আপনার কোডের 100 টি)।

char my_array[10];

স্মৃতি my_arrayদেখতে কিছু দেখতে:

+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array.

সি / সি ++ এ, একটি অ্যারে যেমন কোনও এক্সপ্রেশনটিতে প্রথম উপাদানটির দিকে নির্দেশককে স্থির করে

printf("my_array = %p\n", my_array);

যদি আপনি পরীক্ষা করে থাকেন যে অ্যারের প্রথম উপাদানটি কোথায় রয়েছে তবে আপনি দেখতে পাবেন যে এর ঠিকানাটি অ্যারের ঠিকানার মতো:

my_array[0]
|
v
+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array[0].

3

বি প্রোগ্রামিং ল্যাঙ্গুয়েজে, যা সি এর তাত্ক্ষণিক পূর্বসূর ছিল, পয়েন্টার এবং পূর্ণসংখ্যা অবাধে বিনিময়যোগ্য ছিল। সিস্টেমটি এমন আচরণ করবে যেমন সমস্ত মেমরি একটি দৈত্য অ্যারে। প্রতিটি চলক নামের সাথে এটির সাথে সম্পর্কিত একটি গ্লোবাল বা স্ট্যাক-আপেক্ষিক ঠিকানা ছিল, প্রতিটি চলক নামের জন্য কম্পাইলার কেবলমাত্র একটি বিষয় যা বিশ্বব্যাপী বা স্থানীয় পরিবর্তনশীল ছিল এবং এটির ঠিকানাটি প্রথম বিশ্বব্যাপী বা স্থানীয়ের সাথে সম্পর্কিত কিনা তা লক্ষ্য রাখতে হবে পরিবর্তনশীল।

প্রদত্ত মত একটি বৈশ্বিক ঘোষণা i;[একটি টাইপ নির্দিষ্ট করার কোন প্রয়োজন ছিল, যেহেতু সবকিছু একটি পূর্ণসংখ্যা / পয়েন্টার ছিল] হিসেবে কম্পাইলার দ্বারা প্রক্রিয়াভুক্ত করা হবে: address_of_i = next_global++; memory[address_of_i] = 0;এবং একটি বিবৃতি মত i++প্রক্রিয়া করা হবে: memory[address_of_i] = memory[address_of_i]+1;

arr[10];যেমন একটি ঘোষণা হিসাবে প্রক্রিয়া করা হবে address_of_arr = next_global; memory[next_global] = next_global; next_global += 10;। দ্রষ্টব্য যে ঘোষণাপত্রটি প্রক্রিয়া করার সাথে সাথে সংকলকটি তাত্ক্ষণিকভাবে arrঅ্যারে হওয়ার কথা ভুলে যেতে পারে । একটি বিবৃতি arr[i]=6;হিসাবে প্রক্রিয়া করা হবে memory[memory[address_of_a] + memory[address_of_i]] = 6;। সংকলক arrকোনও অ্যারে এবং iপূর্ণসংখ্যা বা তার বিপরীতে উপস্থাপন করে কিনা তা বিবেচ্য নয়। প্রকৃতপক্ষে, তারা উভয় অ্যারে বা উভয় পূর্ণসংখ্যার কিনা তা বিবেচ্য নয়; বর্ণিত আচরণটি সম্ভবত কার্যকর কার্যকর হবে কিনা তা বিবেচনা না করে এটি পুরোপুরি আনন্দের সাথে কোডটি উত্পন্ন করবে।

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


1

প্রকৃতপক্ষে &myarrayএবং myarrayউভয়ই মূল ঠিকানা।

আপনি যদি ব্যবহার না করে পার্থক্যটি দেখতে চান

printf("my_array = %p\n", my_array);
printf("my_array = %p\n", &my_array);

ব্যবহার

printf("my_array = %s\n", my_array);
printf("my_array = %p\n", my_array);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.