একটি অ্যারের নামটি কি সি তে পয়েন্টার হয়? যদি তা না হয় তবে অ্যারের নাম এবং পয়েন্টার ভেরিয়েবলের মধ্যে পার্থক্য কী?
&array[0]
একটি পয়েন্টার দেয়, অ্যারে নয়;)
একটি অ্যারের নামটি কি সি তে পয়েন্টার হয়? যদি তা না হয় তবে অ্যারের নাম এবং পয়েন্টার ভেরিয়েবলের মধ্যে পার্থক্য কী?
&array[0]
একটি পয়েন্টার দেয়, অ্যারে নয়;)
উত্তর:
একটি অ্যারে একটি অ্যারে এবং একটি পয়েন্টারটি পয়েন্টার হয় তবে বেশিরভাগ ক্ষেত্রে অ্যারের নামগুলি পয়েন্টারে রূপান্তরিত হয়। একটি শব্দ প্রায়শই ব্যবহৃত হয় এটি পয়েন্টারগুলিতে ক্ষয় হয়।
এখানে একটি অ্যারে রয়েছে:
int a[7];
a
সাতটি পূর্ণসংখ্যার জন্য স্থান রয়েছে এবং আপনি এ্যাসাইনমেন্ট সহ এর মধ্যে একটিতে একটি মান রাখতে পারেন:
a[3] = 9;
এখানে একটি পয়েন্টার রয়েছে:
int *p;
p
পূর্ণসংখ্যার জন্য কোনও স্থান নেই, তবে এটি কোনও পূর্ণসংখ্যার জন্য কোনও স্থানকে নির্দেশ করতে পারে। উদাহরণস্বরূপ, আমরা এটিকে অ্যারেতে যে কোনও একটি জায়গায় চিহ্নিত করতে পারি a
, যেমন প্রথমটি:
p = &a[0];
বিভ্রান্তিকর কি হতে পারে আপনি এটি লিখতে পারেন যে:
p = a;
এই আছে না অ্যারের বিষয়বস্তু কপি a
পয়েন্টার মধ্যে p
(যাই হোক না কেন তার মানে হবে)। পরিবর্তে, অ্যারের নামটিকে a
তার প্রথম এলিমেন্টে পয়েন্টারে রূপান্তর করা হয়। সুতরাং যে নিয়োগটি পূর্ববর্তী হিসাবে একই কাজ করে।
আপনি এখন p
অ্যারের মতো একইভাবে ব্যবহার করতে পারেন :
p[3] = 17;
যে কারণে এটি কাজ করে তা হ'ল সিটিতে অ্যারে ডিरेফারেন্সিং অপারেটরটি [ ]
পয়েন্টারগুলির ক্ষেত্রে সংজ্ঞায়িত করা হয়। x[y]
মাধ্যম: পয়েন্টার দিয়ে শুরু x
পদক্ষেপ, y
কি পয়েন্টার পয়েন্ট পরে উপাদান এগিয়ে, এবং তারপর নিতে যাই হোক না কেন নেই। পয়েন্টার গাণিতিক সিনট্যাক্স ব্যবহার করে, x[y]
হিসাবেও লেখা যেতে পারে *(x+y)
।
এই যেমন আমাদের যেমন একটি স্বাভাবিক অ্যারে সঙ্গে কাজ করার জন্য a
, নাম a
মধ্যে a[3]
অবশ্যই প্রথমে একটি পয়েন্টার (প্রথম উপাদানে রূপান্তরিত করা a
)। তারপরে আমরা 3 টি উপাদানকে এগিয়ে নিয়ে যাই এবং যা আছে তা নিয়ে যাই। অন্য কথায়: উপাদানটিকে অ্যারেতে 3 পজিশনে নিন। (অ্যারের মধ্যে চতুর্থ উপাদান কোনটি, যেহেতু প্রথমটির সংখ্যাটি 0 হয়)
সুতরাং, সংক্ষেপে, একটি সি প্রোগ্রামের অ্যারের নামগুলি (বেশিরভাগ ক্ষেত্রে) পয়েন্টারে রূপান্তরিত হয়। একটি ব্যতিক্রম হ'ল আমরা যখন sizeof
অ্যারেতে অপারেটরটি ব্যবহার করি । যদি a
এই প্রসঙ্গে পয়েন্টারে রূপান্তর করা হয় তবে পয়েন্টারটির sizeof a
আকার দেবে এবং প্রকৃত অ্যারে নয়, যা অকেজো হবে, সুতরাং সেই ক্ষেত্রে a
অ্যারে নিজেই বোঝায়।
functionpointer()
এবং (*functionpointer)()
একই জিনিসটির অর্থ, আশ্চর্যের সাথে যথেষ্ট।
sizeof()
, অন্যান্য প্রসঙ্গ যেখানে কোন অ্যারে-> পয়েন্টার ক্ষয় নেই অপারেটর &
- উপরে আপনার উদাহরণে, &a
7 এর অ্যারে পয়েন্টার হবে, একটি বিন্দুতে int
নয় int
; অর্থাৎ, এর প্রকারটি হবে int(*)[7]
, যা রূপান্তরিত নয় int*
। এইভাবে, ফাংশনগুলি নির্দিষ্ট আকারের অ্যারেগুলিতে পয়েন্টার নিতে পারে এবং টাইপ সিস্টেমের মাধ্যমে সীমাবদ্ধতা প্রয়োগ করতে পারে।
একটি অ্যারে যখন মান হিসাবে ব্যবহৃত হয়, এর নামটি প্রথম উপাদানটির ঠিকানা উপস্থাপন করে।
যখন কোনও অ্যারে মান হিসাবে ব্যবহৃত হয় না তখন এর নামটি পুরো অ্যারে উপস্থাপন করে।
int arr[7];
/* arr used as value */
foo(arr);
int x = *(arr + 1); /* same as arr[1] */
/* arr not used as value */
size_t bytes = sizeof arr;
void *q = &arr; /* void pointers are compatible with pointers to any object */
যদি অ্যারের ধরণের একটি এক্সপ্রেশন (যেমন অ্যারের নাম) বৃহত্তর এক্সপ্রেশনতে উপস্থিত হয় এবং এটি অপারেটর &
বা sizeof
অপারেটরগুলির না হয় তবে অ্যারের এক্সপ্রেশনটির ধরণটি "এন-এলিমেন্ট অ্যারে" টি তে রূপান্তরিত হয় "টি-তে পয়েন্টার" এবং অভিব্যক্তির মান হ'ল অ্যারেতে প্রথম উপাদানটির ঠিকানা।
সংক্ষেপে, অ্যারের নামটি কোনও পয়েন্টার নয়, তবে বেশিরভাগ প্রসঙ্গে এটির সাথে বিবেচনা করা হয় যেন এটি পয়েন্টার ছিল।
সম্পাদন করা
মন্তব্যে প্রশ্নের উত্তর:
আমি যদি মাপের ব্যবহার করি তবে আমি কি অ্যারের উপাদানগুলির আকারটি গণনা করব? তারপরে অ্যারে "হেড" দৈর্ঘ্য এবং একটি পয়েন্টার সম্পর্কিত তথ্য নিয়েও স্থান নেয় (এবং এর অর্থ এটি একটি সাধারণ পয়েন্টারের চেয়ে আরও বেশি জায়গা নেয়)?
আপনি যখন একটি অ্যারে তৈরি করেন, কেবলমাত্র বরাদ্দকৃত উপাদানটি তাদের উপাদানগুলির জন্য স্থান; কোনও স্টোরেজ পৃথক পয়েন্টার বা কোনও মেটাডেটার জন্য কার্যকর করা হয় না। প্রদত্ত
char a[10];
স্মৃতিতে যা পাবেন তা হ'ল
+---+
a: | | a[0]
+---+
| | a[1]
+---+
| | a[2]
+---+
...
+---+
| | a[9]
+---+
অভিব্যক্তি a
সম্পূর্ণ অ্যারে উল্লেখ করে, কিন্তু কোন ব্যাপার বস্তুর a
অ্যারে উপাদানের নিজেদের থেকে আলাদা। সুতরাং, sizeof a
আপনাকে পুরো অ্যারের আকার দেয় (বাইটে)। এক্সপ্রেশন &a
আপনাকে অ্যারের ঠিকানা দেয় যা প্রথম উপাদানটির ঠিকানার মতো । মধ্যে পার্থক্য &a
এবং &a[0]
ফলাফলের প্রকার 1 - char (*)[10]
প্রথম ক্ষেত্রে এবং char *
সেকেন্ডের মধ্যে।
জিনিসগুলি যখন অদ্ভুত হয়ে যায় তখন আপনি পৃথক উপাদানগুলিতে অ্যাক্সেস করতে চান - এক্সপ্রেশনটি a[i]
ফলাফল হিসাবে সংজ্ঞায়িত হয় *(a + i)
- কোনও ঠিকানা মান দেওয়া হয় a
, সেই ঠিকানা থেকে i
উপাদানগুলি অফসেট ( বাইট নয় ) এবং ফলাফলটিকে অবলম্বন করে।
সমস্যাটি হ'ল এটি a
কোনও পয়েন্টার বা ঠিকানা নয় - এটি সম্পূর্ণ অ্যারে অবজেক্ট। সুতরাং, সি-র নিয়মটি যখনই সংকলক অ্যারে টাইপের একটি এক্সপ্রেশন দেখায় (যেমন a
, যা টাইপ করে char [10]
) এবং সেই অভিব্যক্তিটি sizeof
অ্যানারি &
অপারেটরদের অপরেন্ড নয় , তখন সেই অভিব্যক্তির ধরণটি রূপান্তরিত হয় ("ডেসে") একটি পয়েন্টার টাইপ ( char *
) এবং এক্সপ্রেশনটির মান হ'ল অ্যারের প্রথম উপাদানটির ঠিকানা। অতএব, অভিব্যক্তিটির মত প্রকাশের মত a
একই ধরণের এবং মান থাকে &a[0]
(এবং এক্সটেনশন দ্বারা, এক্সপ্রেশন *a
হিসাবে এক্সপ্রেশন হিসাবে একই ধরণের এবং মান থাকে a[0]
)।
সি আগের বি নামক ভাষা থেকে উদ্ভূত হয়, এবং 'বি' a
ছিল অ্যারে উপাদান থেকে আলাদা পয়েন্টার বস্তুর a[0]
, a[1]
ইত্যাদি রিচি খ এর অ্যারে শব্দার্থবিদ্যা রাখতে চেয়েছিলেন, কিন্তু পৃথক পয়েন্টার বস্তুর সংরক্ষণকারী সঙ্গে জগাখিচুড়ি চায়নি। তাই সে এ থেকে মুক্তি পেল। পরিবর্তে, সংকলক প্রয়োজন অনুসারে অনুবাদকালে অ্যারে এক্সপ্রেশনগুলিকে পয়েন্টার এক্সপ্রেশনগুলিতে রূপান্তর করবে।
মনে রাখবেন যে আমি বলেছিলাম অ্যারেগুলি তাদের আকার সম্পর্কে কোনও মেটাডেটা সঞ্চয় করে না। এই অ্যারে এক্সপ্রেশনটি পয়েন্টারের কাছে "ক্ষয়" হওয়ার সাথে সাথে আপনার সমস্ত কিছুই একক উপাদানের পয়েন্টার। সেই উপাদানটি উপাদানগুলির ক্রমের প্রথম হতে পারে, বা এটি কোনও একক বস্তু হতে পারে। পয়েন্টারের উপর ভিত্তি করে জানার কোনও উপায় নেই।
যখন আপনি কোনও ফাংশনে অ্যারে এক্সপ্রেশনটি পাস করেন, সমস্ত ক্রিয়াকলাপটি প্রথম উপাদানটির জন্য একটি পয়েন্টার হয় - অ্যারেটি কত বড় তা কোনও ধারণা নেই (এই কারণেই gets
ফাংশনটি এমন একটি মারাত্মক ঘটনা ছিল এবং শেষ পর্যন্ত লাইব্রেরি থেকে সরানো হয়েছিল)। অ্যারেতে কতগুলি উপাদান রয়েছে তা জানার জন্য আপনাকে অবশ্যই একটি সেন্ডিনেল মান (যেমন সি স্ট্রিংগুলিতে 0 টার্মিনেটর) ব্যবহার করতে হবে বা আপনাকে পৃথক প্যারামিটার হিসাবে উপাদানগুলির সংখ্যাটি অবশ্যই পাস করতে হবে।
sizeof
অপারেটর এবং এটি অপারেন্ডের সংখ্যা বাইটগুলিতে মূল্যায়ন করে (হয় কোনও পদার্থকে চিহ্নিত করে এমন একটি অভিব্যক্তি, বা বন্ধনীতে কোনও প্রকারের নাম)। সুতরাং, একটি অ্যারের জন্য, sizeof
একক উপাদানের বাইট সংখ্যা দ্বারা গুণিত উপাদানের সংখ্যাকে মূল্যায়ন করে। যদি কোনও int
4 বাইট প্রশস্ত হয়, তবে 5-এলিমেন্টের অ্যারে int
20 বাইট নেয় takes
[ ]
বিশেষ নয়? উদাহরণস্বরূপ, int a[2][3];
তারপরে x = a[1][2];
, যদিও এটি আবার লিখতে পারা যায় x = *( *(a+1) + 2 );
, এখানে a
একটি পয়েন্টার টাইপে রূপান্তরিত হয় না int*
(যদিও a
কোনও ফাংশনের যুক্তি হলে এটি রূপান্তর করা উচিত int*
)।
a
টাইপ থাকে int [2][3]
, যা টাইপ করতে "সিদ্ধান্ত নেয়" int (*)[3]
। এক্সপ্রেশনটির *(a + 1)
ধরন রয়েছে int [3]
যা "সিদ্ধান্ত নেয়" int *
। সুতরাং, *(*(a + 1) + 2)
টাইপ হবে int
। a
প্রথম 3-উপাদানের বিন্যাস পয়েন্ট int
, a + 1
দ্বিতীয় 3-উপাদানের বিন্যাস পয়েন্ট int
, *(a + 1)
হয় দ্বিতীয় 3-উপাদানের বিন্যাস int
, *(a + 1) + 2
দ্বিতীয় অ্যারের তৃতীয় উপাদান পয়েন্ট int
, তাই *(*(a + 1) + 2)
হয় দ্বিতীয় অ্যারের তৃতীয় উপাদান int
। এটি কীভাবে মেশিন কোডে ম্যাপ করা যায় তা সম্পূর্ণরূপে সংকলকটির উপর নির্ভর করে।
একটি অ্যারে এভাবে ঘোষিত হয়েছে
int a[10];
10 টির জন্য মেমরি বরাদ্দ করে int
। আপনি সংশোধন করতে পারবেন না a
তবে আপনি পয়েন্টার গাণিতিকটি করতে পারেন a
।
এই জাতীয় পয়েন্টার কেবলমাত্র পয়েন্টারের জন্য মেমরি বরাদ্দ করে p
:
int *p;
এটি কোনও int
এস বরাদ্দ করে না । আপনি এটি পরিবর্তন করতে পারেন:
p = a;
এবং অ্যারে সাবস্ক্রিপ্টগুলি আপনি এটির সাথে ব্যবহার করতে পারেন:
p[2] = 5;
a[2] = 5; // same
*(p+2) = 5; // same effect
*(a+2) = 5; // same effect
int
স্বয়ংক্রিয় স্টোরেজ duration` সঙ্গে সে।
অ্যারের নাম নিজে থেকেই একটি স্মৃতি অবস্থান দেয়, তাই আপনি অ্যারের নামটিকে পয়েন্টারের মতো আচরণ করতে পারেন:
int a[7];
a[0] = 1976;
a[1] = 1984;
printf("memory location of a: %p", a);
printf("value at memory location %p is %d", a, *a);
এবং অন্যান্য নিফটি স্টাফগুলি যা আপনি পয়েন্টারটিতে করতে পারেন (উদাঃ একটি অফসেট যোগ / বিয়োগ), আপনি একটি অ্যারেও করতে পারেন:
printf("value at memory location %p is %d", a + 1, *(a + 1));
ভাষাভিত্তিক, সি যদি বিন্যাসটিকে কিছু প্রকারের "পয়েন্টার" হিসাবে প্রকাশ না করে (প্যাডেন্টালি এটি কেবল একটি মেমরির অবস্থান। এটি স্মৃতিতে স্বেচ্ছাসেবী অবস্থানকে নির্দেশ করতে পারে না বা প্রোগ্রামার দ্বারা নিয়ন্ত্রণ করা যায় না)। আমাদের সর্বদা এটি কোড করা প্রয়োজন:
printf("value at memory location %p is %d", &a[1], a[1]);
আমি মনে করি এই উদাহরণটি এই বিষয়ে কিছুটা আলোকপাত করেছে:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
int **b = &a;
printf("a == &a: %d\n", a == b);
return 0;
}
এটি জিসিসি ৪.৯.২ এ জরিমানা (২ টি সতর্কতা সহ) সংকলন করে এবং নিম্নলিখিতগুলি মুদ্রণ করে:
a == &a: 1
উফ :-)
সুতরাং, উপসংহারটি হ'ল না, অ্যারেটি কোনও পয়েন্টার নয়, এটি পয়েন্টার হিসাবে মেমরির মধ্যে সংরক্ষণ করা হয় না (কেবলমাত্র পঠনযোগ্য একও নয়) যদিও এটি দেখতে মনে হচ্ছে, যেহেতু আপনি & অপারেটরের সাথে তার ঠিকানাটি পেতে পারেন । তবে - ওফ - সেই অপারেটর কাজ করে না :-)), কোনওভাবেই আপনাকে সতর্ক করা হয়েছে:
p.c: In function ‘main’:
pp.c:6:12: warning: initialization from incompatible pointer type
int **b = &a;
^
p.c:8:28: warning: comparison of distinct pointer types lacks a cast
printf("a == &a: %d\n", a == b);
সি ++ সংকলন-সময় ত্রুটিযুক্ত এই জাতীয় কোনও প্রচেষ্টা প্রত্যাখ্যান করে।
সম্পাদনা:
এই আমি বোঝাতে চেয়েছিলাম:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
void *c = a;
void *b = &a;
void *d = &c;
printf("a == &a: %d\n", a == b);
printf("c == &c: %d\n", c == d);
return 0;
}
যদিও c
এবং a
একই মেমরি "নির্দেশ", আপনি এর ঠিকানা পেতে পারেন c
পয়েন্টার, কিন্তু আপনি এর ঠিকানা প্রাপ্ত করতে পারবেন না a
পয়েন্টার।
-std=c11 -pedantic-errors
, আপনি অবৈধ সি কোড লেখার জন্য একটি সংকলক ত্রুটি পান। এর কারণ হ'ল কারণ আপনি int (*)[3]
একটি ভেরিয়েবলের জন্য একটি নির্ধারণ করার চেষ্টা করেন int**
যা দুটি ধরণের যা একে অপরের সাথে একেবারে কিছুই করার নেই। সুতরাং এই উদাহরণটি যা প্রমাণ করার কথা, সে সম্পর্কে আমার কোনও ধারণা নেই।
int **
টাইপ বিন্দু নেই, এক ভাল ব্যবহার করা উচিত void *
এই জন্য।
অ্যারের নামটি পয়েন্টারের মতো আচরণ করে এবং অ্যারের প্রথম উপাদানটিকে নির্দেশ করে। উদাহরণ:
int a[]={1,2,3};
printf("%p\n",a); //result is similar to 0x7fff6fe40bc0
printf("%p\n",&a[0]); //result is similar to 0x7fff6fe40bc0
মুদ্রণ বিবৃতি উভয়ই একটি মেশিনের জন্য ঠিক একই আউটপুট দেবে। আমার সিস্টেমে এটি দিয়েছে:
0x7fff6fe40bc0
একটি অ্যারের স্মৃতিতে সিক্যুয়াল এবং সংযুক্ত উপাদানগুলির একটি সংগ্রহ। সি-তে একটি অ্যারের নাম হ'ল প্রথম উপাদানটির সূচক এবং অফসেট প্রয়োগ করে আপনি বাকী উপাদানগুলিতে অ্যাক্সেস করতে পারেন। একটি "প্রথম উপাদান সূচক" প্রকৃতপক্ষে একটি মেমরি দিকের নির্দেশক।
পয়েন্টার ভেরিয়েবলের সাথে পার্থক্য হ'ল আপনি অ্যারের নামটি নির্দেশ করছেন যে অবস্থানটি পরিবর্তন করতে পারবেন না তাই কনস্ট পয়েন্টারের অনুরূপ (এটি একইরকম, একই নয়। মার্কের মন্তব্য দেখুন)। তবে আপনি যদি পয়েন্টার অ্যারিমেটিক ব্যবহার করেন তবে মানটি পেতে আপনার অ্যারের নামটি অবলম্বন করতে হবে না:
char array = "hello wordl";
char* ptr = array;
char c = array[2]; //array[2] holds the character 'l'
char *c1 = ptr[2]; //ptr[2] holds a memory direction that holds the character 'l'
উত্তরটি হ'ল 'হ্যাঁ'।
অ্যারের নামটি একটি অ্যারের প্রথম উপাদানটির ঠিকানা। সুতরাং হ্যাঁ অ্যারের নামটি একটি কনস্ট পয়েন্টার।