পয়েন্টার থেকে পয়েন্টার সি তে কীভাবে কাজ করে? আপনি কখন তাদের ব্যবহার করবেন?
পয়েন্টার থেকে পয়েন্টার সি তে কীভাবে কাজ করে? আপনি কখন তাদের ব্যবহার করবেন?
উত্তর:
8 বিট ঠিকানা সহ একটি 8 বিট কম্পিউটার ধরে নেওয়া যাক (এবং এইভাবে কেবল 256 মেমরির বাইট)। এটি সেই স্মৃতির অংশ (শীর্ষে থাকা সংখ্যাগুলি ঠিকানাগুলি):
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| | 58 | | | 63 | | 55 | | | h | e | l | l | o | \0 | |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
আপনি এখানে যা দেখতে পাচ্ছেন, তা হ'ল ঠিকানাতে স্ট্রিংটি "হ্যালো" শুরু হয়। সুতরাং এই ক্ষেত্রে যদি মেমরিতে কেবলমাত্র "হ্যালো" এর ঘটনা থাকে তবে,
const char *c = "hello";
... সংজ্ঞায়িত c
করার জন্য একটি পয়েন্টার হতে (শুধুমাত্র পাঠযোগ্য) স্ট্রিং "হ্যালো", এবং এইভাবে মান 63. রয়েছে c
নিজেই কোথাও সংরক্ষণ করা আবশ্যক: উপরোক্ত উদাহরণের অবশ্যই আমরা করতে পারবেন ভাষা অক্ষরে বিন্দু অবস্থান 58. এ , তবে অন্যান্য পয়েন্টারেও। উদাহরণ:
const char **cp = &c;
এখন cp
নির্দেশ করে c
, এটিতে এর ঠিকানা রয়েছে c
(যা 58)। আমরা আরও এগিয়ে যেতে পারেন। বিবেচনা:
const char ***cpp = &cp;
এখন cpp
ঠিকানা সংরক্ষণ করে cp
। সুতরাং এর মান 55 আছে (উপরের উদাহরণের উপর ভিত্তি করে), এবং আপনি এটি অনুমান করেছেন: এটি নিজেই 60 ঠিকানায় সংরক্ষণ করা হয়েছে।
হিসেবে কেন এক পয়েন্টার পয়েন্টার ব্যবহার করে:
t
একটি রেফারেন্স টাইপ করে t *
। এখন টাইপের অ্যারেগুলির একটি অ্যারে বিবেচনা করুন t
: স্বাভাবিকভাবেই এই 2 ডি অ্যারের রেফারেন্সটিতে টাইপ (t *)*
= থাকবেt **
, এবং তাই এটি একটি পয়েন্টারের কাছে পয়েন্টার।char **
।f
টাইপের একটি আর্গুমেন্ট t **
পরিবর্তন করতে হলে টাইপের একটি আর্গুমেন্ট গ্রহণ করতে হবেt *
।পয়েন্টার থেকে পয়েন্টার সি তে কীভাবে কাজ করে?
প্রথমে পয়েন্টারটি হ'ল একটি ভেরিয়েবল, অন্যান্য ভেরিয়েবলের মতো, তবে এটি একটি ভেরিয়েবলের ঠিকানা ধারণ করে।
পয়েন্টারের কাছে পয়েন্টারটি অন্য চলকগুলির মতো একটি চলক, তবে এটি একটি ভেরিয়েবলের ঠিকানা ধারণ করে। যে পরিবর্তনশীল ঠিক পয়েন্টার হতে পারে।
আপনি কখন তাদের ব্যবহার করবেন?
আপনি যখন গাদা কিছু স্মৃতিতে পয়েন্টার ফিরিয়ে দিতে হবে তখন আপনি সেগুলি ব্যবহার করতে পারেন, তবে ফেরতের মানটি ব্যবহার করবেন না।
উদাহরণ:
int getValueOf5(int *p)
{
*p = 5;
return 1;//success
}
int get1024HeapMemory(int **p)
{
*p = malloc(1024);
if(*p == 0)
return -1;//error
else
return 0;//success
}
এবং আপনি এটিকে এটি বলে:
int x;
getValueOf5(&x);//I want to fill the int varaible, so I pass it's address in
//At this point x holds 5
int *p;
get1024HeapMemory(&p);//I want to fill the int* variable, so I pass it's address in
//At this point p holds a memory address where 1024 bytes of memory is allocated on the heap
অন্যান্য ব্যবহারগুলিও রয়েছে, যেমন প্রতিটি সি প্রোগ্রামের মূল () আর্গুমেন্টটি আরগভের জন্য একটি পয়েন্টারটিতে একটি পয়েন্টার থাকে, যেখানে প্রতিটি উপাদান কমান্ড লাইন বিকল্পগুলির মধ্যে একটি অক্ষরের অ্যারে ধারণ করে। আপনি অবশ্যই সাবধান হন যখন আপনি পয়েন্টারগুলির পয়েন্টারগুলি 2 ত্রিমাত্রিক অ্যারেতে নির্দেশ করতে ব্যবহার করেন তবে পরিবর্তে 2 মাত্রিক অ্যারেতে পয়েন্টার ব্যবহার করা ভাল।
কেন এটি বিপজ্জনক?
void test()
{
double **a;
int i1 = sizeof(a[0]);//i1 == 4 == sizeof(double*)
double matrix[ROWS][COLUMNS];
int i2 = sizeof(matrix[0]);//i2 == 240 == COLUMNS * sizeof(double)
}
সঠিকভাবে সম্পন্ন ২ টি মাত্রিক অ্যারের প্রতি নির্দেশকের উদাহরণ এখানে রয়েছে:
int (*myPointerTo2DimArray)[ROWS][COLUMNS]
আপনি যদি ROWS এবং COLUMNS এর জন্য পরিবর্তনশীল সংখ্যক উপাদানকে সমর্থন করতে চান তবে আপনি ২ টি মাত্রিক অ্যারেটিতে পয়েন্টার ব্যবহার করতে পারবেন না। তবে যখন আপনি হাতের আগে জানবেন আপনি একটি 2 মাত্রিক অ্যারে ব্যবহার করবেন।
গিটার ২.০ তে পয়েন্টার ব্যবহারের জন্য পয়েন্টার ব্যবহারের এই "বাস্তব বিশ্বের" কোড উদাহরণটি আমার পছন্দ হয়েছে, 7b1004 বি প্রতিশ্রুতিবদ্ধ :
লিনাস একবার বলেছিলেন:
আমি প্রকৃতপক্ষে আরও লোকেদের সত্যিকারের মূল নিম্ন-স্তরের কোডিংয়ের বোঝার ইচ্ছা করি। লকলেস নাম অনুসন্ধানের মতো বড় বড় জটিল জিনিস নয়, তবে পয়েন্টার-টু-পয়েন্টার ইত্যাদির সহজ ব্যবহার ইত্যাদি
উদাহরণস্বরূপ, আমি অনেক বেশি লোককে দেখেছি যারা "পূর্ব" এন্ট্রি ট্র্যাক করে একক সংযুক্ত তালিকার এন্ট্রি মুছে দেয় delete , এবং তারপরে এমন কিছু করে এন্ট্রি মুছতে
if (prev)
prev->next = entry->next;
else
list_head = entry->next;
এবং যখনই আমি এর মতো কোড দেখি, আমি কেবল "এই ব্যক্তি পয়েন্টার বোঝে না" go এবং দুঃখজনকভাবে এটি খুব সাধারণ।
পয়েন্টার বোঝে এমন লোকেরা কেবল " এন্ট্রি পয়েন্টারটিতে পয়েন্টার " ব্যবহার করে এবং তালিকা_ইডের ঠিকানা দিয়ে এটি সূচনা করে। এবং তারপরে তারা তালিকাটি অতিক্রম করার সাথে সাথে কোনও কন্ডিশন ব্যবহার না করেই এন্ট্রি সরাতে পারে কেবল একটি করে
*pp = entry->next
সরলীকরণটি প্রয়োগ করা আমাদের 2 টি লাইনের মন্তব্য যুক্ত করার পরেও এই ফাংশনটি থেকে 7 টি লাইন হারাতে দেয়।
- struct combine_diff_path *p, *pprev, *ptmp;
+ struct combine_diff_path *p, **tail = &curr;
ফিলিপ বুকের 2016 সালের ভিডিও " লিনাস টরভাল্ডসের ডাবল পয়েন্টার সমস্যা " মন্তব্যটিতে ক্রিস ইঙ্গিত করেছেন ।
কুমার ব্লগ পোস্টে " লিনাস ইনস্ট্যান্ডিং পয়েন্টারস " বোঝার মন্তব্যে উল্লেখ করেছেন , যেখানে গ্রিশা ট্রুবেটস্কয় ব্যাখ্যা করেছেন:
কল্পনা করুন যে আপনার লিঙ্কযুক্ত তালিকাটি সংজ্ঞায়িত হয়েছে:
typedef struct list_entry {
int val;
struct list_entry *next;
} list_entry;
আপনাকে শুরু থেকে শেষ পর্যন্ত এটিকে পুনরাবৃত্তি করতে হবে এবং একটি নির্দিষ্ট উপাদানটি মুছতে হবে যার মান to_remove এর সমান।
এটি করার আরও সুস্পষ্ট উপায় হ'ল:
list_entry *entry = head; /* assuming head exists and is the first entry of the list */
list_entry *prev = NULL;
while (entry) { /* line 4 */
if (entry->val == to_remove) /* this is the one to remove ; line 5 */
if (prev)
prev->next = entry->next; /* remove the entry ; line 7 */
else
head = entry->next; /* special case - first entry ; line 9 */
/* move on to the next entry */
prev = entry;
entry = entry->next;
}
আমরা উপরে যা করছি তা হ'ল:
- এন্ট্রি না হওয়া পর্যন্ত তালিকার উপরে পুনরাবৃত্তি করা
NULL
, যার অর্থ আমরা তালিকার শেষে (লাইন 4) পৌঁছেছি।- যখন আমরা কোনও প্রবেশিকা জুড়ে আসি তখন আমরা সরিয়ে ফেলতে চাই (লাইন 5)
- আমরা পূর্ববর্তীটির সাথে বর্তমান পরবর্তী পয়েন্টারের মান নির্ধারণ করি,
- সুতরাং বর্তমান উপাদান (লাইন 7) অপসারণ।
উপরে একটি বিশেষ কেস রয়েছে - পুনরাবৃত্তির শুরুতে কোনও পূর্ববর্তী প্রবেশ নেই (
prev
হয়)NULL
) নেই এবং তাই তালিকার প্রথম এন্ট্রি সরাতে আপনাকে নিজের মাথাটি পরিবর্তন করতে হবে (লাইন 9)।লিনাস যা বলছিলেন তা হ'ল উপরের কোডটি পূর্ববর্তী উপাদানটিকে কেবলমাত্র পয়েন্টার না করে পয়েন্টারটিতে পয়েন্টার বানিয়ে সরল করা যায় ।
কোডটি তখন এর মতো দেখায়:
list_entry **pp = &head; /* pointer to a pointer */
list_entry *entry = head;
while (entry) {
if (entry->val == to_remove)
*pp = entry->next;
pp = &entry->next;
entry = entry->next;
}
উপরের কোড খুব পূর্ববর্তী বৈকল্পিক অনুরূপ, কিন্তু নোটিশ কীভাবে আমরা তালিকার প্রথম উপাদান বিশেষ মামলায় দেখার জন্য আর প্রয়োজন নেই, যেহেতু
pp
নয়NULL
শুরুতে। সাধারণ এবং চালাক।এছাড়াও, সেই থ্রেডের কেউ মন্তব্য করেছেন যে এটি ভাল হওয়ার কারণটি
*pp = entry->next
হচ্ছে পারমাণবিক। এটি অবশ্যই পারমাণবিক নয় ।
উপরের এক্সপ্রেশনটিতে দুটি ডিরিফারেন্স অপারেটর (*
এবং->
) এবং একটি অ্যাসাইনমেন্ট রয়েছে এবং এই তিনটি জিনিসের কোনওটিই পারমাণবিক নয়।
এটি একটি সাধারণ ভুল ধারণা হয়, কিন্তু সি হায়রে প্রায় কাছাকাছি কিছুই কি কখনো পারমাণবিক গণ্য করা হবে (তত্সহ++
এবং--
অপারেটরদের)!
বিশ্ববিদ্যালয়ে প্রোগ্রামিং কোর্সে পয়েন্টারগুলি কভার করার সময়, তাদের সম্পর্কে শিখতে কীভাবে শুরু করা যায় সে সম্পর্কে আমাদের দুটি ইঙ্গিত দেওয়া হয়েছিল। প্রথমটি ছিল বিনকি সহ পয়েন্টার ফান । দ্বিতীয়টি হ'ল লুইস ক্যারোলের থ্রু দ্য লুকিং-গ্লাসের হ্যাডকসসের চোখের প্যাসেজ সম্পর্কে think
নাইট উদ্বেগজনক সুরে বলেছিলেন: "তুমি দুঃখী," তোমাকে সান্ত্বনা দেওয়ার জন্য আমাকে একটি গান গাইতে দাও। "
"এটা খুব দীর্ঘ?" অ্যালিস জিজ্ঞাসা করেছিলেন, যেহেতু সেদিন সে ভাল কবিতা শুনেছিল।
নাইট বলল, “এটি দীর্ঘ, তবে এটি খুব সুন্দর very যে কেউ আমার কথা শুনে সে এটি গান করে - হয় এটি তাদের চোখে অশ্রু নিয়ে আসে, অন্যথায় - "
"নাহলে কি?" অ্যালিস বলেছিলেন, নাইট হঠাৎ বিরতি দিয়েছিল।
"অন্যথায় এটি না, আপনি জানেন। গানের নামটিকে 'হ্যাডকস' আইজ বলা হয় ”'
"ওহ, এটিই গানের নাম, তাই না?" আগ্রহী হওয়ার চেষ্টা করে অ্যালিস বলেছিলেন।
"না, আপনি বুঝতে পারছেন না," নাইট কিছুটা বিরক্ত হয়ে বললেন। “এই নামেই বলা হয়। নামটি আসলে 'দ্য বয়স্ক মানুষ'।
"তারপরে আমার বলা উচিত ছিল যে 'গানটিকেই বলা হয়'?" অ্যালিস নিজেকে সংশোধন করলেন।
"না, আপনার উচিত নয়: এটি অন্য একটি জিনিস! গানটির নাম 'ওয়েজ অ্যান্ড মিনস': তবে এটাকেই বলা হয়, আপনি জানেন! "
"আচ্ছা, গানটি কি তবে?" এলিস বলেছিলেন, যিনি এই সময়ের মধ্যে পুরোপুরি শঙ্কিত হয়েছিলেন।
নাইট বলল, “আমি সেখানে আসছিলাম।” "গানটি সত্যিই 'একটি গেটে এ-সিটিং': এবং সুরটি আমার নিজের আবিষ্কার।
আপনি এটি পড়তে চাইতে পারেন: পয়েন্টারগুলিতে পয়েন্টারগুলি
আশা করি এটি কিছু প্রাথমিক সন্দেহগুলি পরিষ্কার করতে সহায়তা করে।
যখন কোনও পয়েন্টারের রেফারেন্স প্রয়োজন হয়। উদাহরণস্বরূপ, আপনি যখন একটি কলিং ফাংশনের অভ্যন্তরে কলিং ফাংশনটির স্কোপে ঘোষিত পয়েন্টার ভেরিয়েবলের মান (ঠিকানার দিকে নির্দেশিত) পরিবর্তন করতে চান।
আপনি যদি একটি একক পয়েন্টারটিকে আর্গুমেন্ট হিসাবে পাস করেন তবে আপনি কলিং স্কোপের মূল পয়েন্টারটি নয়, পয়েন্টারের স্থানীয় কপিগুলি সংশোধন করবেন। একটি পয়েন্টারের সাথে একটি পয়েন্টার সহ, আপনি পরবর্তীটি পরিবর্তন করুন।
পয়েন্টারের কাছে পয়েন্টারকে হ্যান্ডেলও বলা হয় । এর জন্য একটি ব্যবহার প্রায়শই যখন কোনও বস্তু স্মৃতিতে সরানো বা সরিয়ে ফেলা যায়। একজন অবজেক্টের ব্যবহারটিকে লক এবং আনলক করতে প্রায়শই দায়ী তাই এটি অ্যাক্সেস করার সময় এটি সরানো হবে না।
এটি প্রায়শই মেমোরি সীমিত পরিবেশে অর্থাৎ পাম ওএসে ব্যবহৃত হয়।
এই ধারণাটি আরও ভালভাবে বুঝতে নীচের চিত্র এবং প্রোগ্রামটি বিবেচনা করুন ।
চিত্রে অনুযায়ী, ptr1 একটি হল একক পয়েন্টার যা পরিবর্তনশীল এর ঠিকানা হচ্ছে না NUM ।
ptr1 = #
একইভাবে ptr2 একটি হল পয়েন্টার (ডবল পয়েন্টার) এর পয়েন্টার যা পয়েন্টার এর ঠিকানা হচ্ছে না ptr1 ।
ptr2 = &ptr1;
একটি পয়েন্টার যা অন্য পয়েন্টারকে নির্দেশ করে ডাবল পয়েন্টার হিসাবে পরিচিত। এই উদাহরণে পিটিআর 2 একটি ডাবল পয়েন্টার।
উপরের চিত্রের মানগুলি:
Address of variable num has : 1000
Address of Pointer ptr1 is: 2000
Address of Pointer ptr2 is: 3000
উদাহরণ:
#include <stdio.h>
int main ()
{
int num = 10;
int *ptr1;
int **ptr2;
// Take the address of var
ptr1 = #
// Take the address of ptr1 using address of operator &
ptr2 = &ptr1;
// Print the value
printf("Value of num = %d\n", num );
printf("Value available at *ptr1 = %d\n", *ptr1 );
printf("Value available at **ptr2 = %d\n", **ptr2);
}
আউটপুট:
Value of num = 10
Value available at *ptr1 = 10
Value available at **ptr2 = 10
এটি পয়েন্টারের ঠিকানা মানের একটি পয়েন্টার। (এটা আমি জানি ভয়ানক)
মূলত, এটি আপনাকে অন্য পয়েন্টারের ঠিকানার মানতে একটি পয়েন্টারটি প্রেরণ করতে দেয়, যাতে আপনি অন্য ফাংশনকারীটি একটি উপ ফাংশন থেকে কোথায় পয়েন্ট করা হচ্ছে তা সংশোধন করতে পারবেন, যেমন:
void changeptr(int** pp)
{
*pp=&someval;
}
পয়েন্টার একটি পয়েন্টার ভাল, পয়েন্টার একটি পয়েন্টার।
সামুর টাইপ ** এর অর্থপূর্ণ উদাহরণ হ'ল দ্বি-মাত্রিক অ্যারে: আপনার একটি অ্যারে রয়েছে, অন্য অ্যারেগুলিতে পয়েন্টার ভরা থাকে, তাই যখন আপনি লিখেন
dpointer [5] [6]
আপনি তার অ্যারে অ্যাক্সেস করতে পারেন যা তার ৫ ম অবস্থানে অন্যান্য অ্যারেগুলিতে পয়েন্টার রয়েছে, পয়েন্টারটি পাবেন (তার নামটি fpointer করুন) এবং তারপরে সেই অ্যারের সাথে উল্লিখিত অ্যারের 6th ষ্ঠ উপাদানটি অ্যাক্সেস করুন (সুতরাং, ফাইপয়েন্টার []])।
এটি কীভাবে কাজ করে: এটি একটি পরিবর্তনশীল যা অন্য পয়েন্টার সঞ্চয় করতে পারে।
আপনি কখন সেগুলি ব্যবহার করবেন: আপনার ফাংশনটি অ্যারে তৈরি করতে এবং এটি কলারকে ফিরিয়ে দিতে চায় তবে তাদের মধ্যে একটি ব্যবহার করে।
//returns the array of roll nos {11, 12} through paramater
// return value is total number of students
int fun( int **i )
{
int *j;
*i = (int*)malloc ( 2*sizeof(int) );
**i = 11; // e.g., newly allocated memory 0x2000 store 11
j = *i;
j++;
*j = 12; ; // e.g., newly allocated memory 0x2004 store 12
return 2;
}
int main()
{
int *i;
int n = fun( &i ); // hey I don't know how many students are in your class please send all of their roll numbers.
for ( int j=0; j<n; j++ )
printf( "roll no = %d \n", i[j] );
return 0;
}
আমি একটি 5 মিনিটের ভিডিও তৈরি করেছি যা পয়েন্টারগুলি কীভাবে কাজ করে তা ব্যাখ্যা করে:
সেখানে দরকারী ব্যাখ্যার অনেক, কিন্তু আমি একটি সংক্ষিপ্ত বিবরণ পাই নি, তাই ..
মূলত পয়েন্টার হল ভেরিয়েবলের ঠিকানা। সংক্ষিপ্ত সংক্ষিপ্ত কোড:
int a, *p_a;//declaration of normal variable and int pointer variable
a = 56; //simply assign value
p_a = &a; //save address of "a" to pointer variable
*p_a = 15; //override the value of the variable
//print 0xfoo and 15
//- first is address, 2nd is value stored at this address (that is called dereference)
printf("pointer p_a is having value %d and targeting at variable value %d", p_a, *p_a);
রেফারেন্স এবং ডিরিফারেন্স বলতে কী বোঝায় সে বিষয়েও দরকারী তথ্য পাওয়া যাবে
এবং আমি এতটা নিশ্চিত নই, কখন পয়েন্টারগুলি কার্যকর হতে পারে তবে সাধারণভাবে যখন আপনি কিছু ম্যানুয়াল / গতিশীল মেমরি বরাদ্দ করছেন - ম্যালোক, কলোক ইত্যাদি,
সুতরাং আমি আশা করি এটি সমস্যাযুক্ত স্পষ্ট করতেও সহায়তা করবে :)