সি পয়েন্টার (ঘোষণার বনাম আনারি অপারেটর) কোনও শিক্ষানবিশকে কীভাবে ব্যাখ্যা করবেন?


141

আমি সি প্রোগ্রামিং শুরুর দিকে পয়েন্টারগুলি ব্যাখ্যা করতে সাম্প্রতিক আনন্দ পেয়েছি এবং নিম্নলিখিত অসুবিধায় হোঁচট খেয়েছি। এটি ইতিমধ্যে পয়েন্টারগুলি কীভাবে ব্যবহার করতে হয় তা যদি আপনি ইতিমধ্যে জানেন তবে এটি একটি সমস্যার মতো মনে হচ্ছে না তবে পরিষ্কার উদাহরণ দিয়ে নিম্নলিখিত উদাহরণটি দেখার চেষ্টা করুন:

int foo = 1;
int *bar = &foo;
printf("%p\n", (void *)&foo);
printf("%i\n", *bar);

পরম শুরুর দিকে আউটপুটটি আশ্চর্যজনক হতে পারে। লাইন ২-তে তিনি কেবলমাত্র * বারটিকে & foo বলে ঘোষণা করেছিলেন, তবে ৪ নং লাইনে দেখা যাচ্ছে যে * বারটি আসলে & foo এর পরিবর্তে foo!

বিভ্রান্তি, আপনি বলতে পারেন, * চিহ্নের অস্পষ্টতা থেকে উদ্ভূত: লাইন 2 এ এটি একটি পয়েন্টার ঘোষণার জন্য ব্যবহৃত হয়। লাইন 4 এ এটি অ্যানারি অপারেটর হিসাবে ব্যবহৃত হয় যা পয়েন্টার পয়েন্টের মান আনবে। দুটি ভিন্ন জিনিস, তাই না?

তবে এই "ব্যাখ্যা" কোনও শিক্ষানবিশকে মোটেই সহায়তা করে না doesn't এটি একটি সূক্ষ্ম ভিন্নতা নির্দেশ করে একটি নতুন ধারণা প্রবর্তন করে। এটি এটি শেখানোর সঠিক উপায় হতে পারে না।

তো, কীভাবে কর্নিগান এবং রিচি এটি ব্যাখ্যা করলেন?

অ্যানারি অপারেটর * ইন্ডিয়ারেশন বা ডেরেফারেন্সিং অপারেটর; যখন কোনও পয়েন্টারটিতে প্রয়োগ করা হয়, এটি পয়েন্টারটি নির্দেশিত বস্তুটি অ্যাক্সেস করে। [...]

পয়েন্টার আইপি এর ঘোষণাপত্রটি int *ipস্মৃতিবিজড়িত হিসাবে চিহ্নিত; এটি বলে যে অভিব্যক্তিটি *ipএকটি অন্তর্নিহিত। একটি চলকটির জন্য ঘোষণার বাক্য গঠনটি ভেরিয়েবল প্রদর্শিত হতে পারে এমন বাক্যগুলির সিনট্যাক্সটিকে নকল করে

int *ip" *ipফিরে আসবে " এর মতো পড়তে হবে int? তবে কেন ঘোষণার পরে অ্যাসাইনমেন্ট সেই প্যাটার্নটি অনুসরণ করে না? যদি কোনও শিক্ষানবিশ চলকটি আরম্ভ করতে চায় তবে কী হবে? int *ip = 1(পড়া: *ipএকটি ফিরে আসবে intএবং intহয় 1) না করবে না কাজ আশানুরূপ। ধারণাগত মডেলটি কেবল সুসংগত বলে মনে হয় না। আমি কি এখানে কিছু মিস করছি?


সম্পাদনা করুন: এটি এখানে উত্তরগুলি সংক্ষিপ্ত করার চেষ্টা করেছিল


15
জিনিসগুলিকে একটি কাগজে অঙ্কন করা এবং তীরগুলির সাথে তাদের সংযুক্তি দিয়ে সর্বোত্তম ব্যাখ্যাটি দেওয়া হয়;)
মারআন

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

40
সম্ভবত এটি লেখার int* barফলে এটি আরও সুস্পষ্ট করে তোলে যে তারাটি আসলে ধরণের অংশ, শনাক্তকারীর অংশ নয়। অবশ্যই এটি আপনাকে অনাবাদী স্টাফের মতো বিভিন্ন সমস্যায় ফেলেছে int* a, b
নিক্লাস বি

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

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

উত্তর:


43

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

প্রথমে ব্যাখ্যা করুন যে কোনও ভেরিয়েবলের ঘোষণায় অপারেটর থাকতে পারে না (এটি দেখিয়ে প্রমাণ করুন যে কোনও ভেরিয়েবলের ঘোষণায় একটি চিহ্ন -বা +চিহ্ন রাখলে কেবল ত্রুটি হয়)) তারপরে দেখান যে কোনও এক্সপ্রেশন (অর্থাত্ একটি কার্যের ডানদিকে) অপারেটরগুলি থাকতে পারে। নিশ্চিত করুন যে শিক্ষার্থী বুঝতে পারে যে একটি অভিব্যক্তি এবং একটি পরিবর্তনশীল ঘোষণা দুটি সম্পূর্ণ ভিন্ন প্রসঙ্গ।

যখন তারা বুঝতে পারে যে প্রসঙ্গগুলি ভিন্ন, আপনি ব্যাখ্যা করতে পারেন যে *প্রতীকটি যখন ভেরিয়েবল আইডেন্টিফায়ারের সামনে ভেরিয়েবল ঘোষণায় থাকে তখন এর অর্থ 'এই পরিবর্তনশীলটিকে পয়েন্টার হিসাবে ঘোষণা করুন'। তারপরে আপনি ব্যাখ্যা করতে পারবেন যে কোনও অভিব্যক্তিতে (আনরি অপারেটর হিসাবে) ব্যবহার করা হলে *প্রতীকটি 'ডেরেফারেন্স অপারেটর' এবং এর অর্থ পূর্বের অর্থের পরিবর্তে 'ঠিকানায় মান'।

আপনার ছাত্রকে সত্যিকার অর্থে বোঝানোর জন্য, ব্যাখ্যা করুন যে সি এর নির্মাতারা কোনও প্রতীক ব্যবহার করতে পারত ডিটারেন্স অপারেটরকে বোঝাতে (যেমন তারা @পরিবর্তে ব্যবহার করতে পারত ) তবে যে কোনও কারণেই তারা নকশাগুলি ব্যবহারের সিদ্ধান্ত নিয়েছিল *

সব মিলিয়ে, প্রসঙ্গটি ভিন্ন যে ব্যাখ্যা করার কোনও উপায় নেই। শিক্ষার্থী প্রসঙ্গগুলি পৃথকভাবে বুঝতে না পারলে তারা বুঝতে পারে না কেন *প্রতীকটি বিভিন্ন জিনিস বোঝাতে পারে।


80

শর্টহ্যান্ডের কারণ:

int *bar = &foo;

আপনার উদাহরণে বিভ্রান্তিকর হতে পারে যে এটির সমতুল্য হিসাবে এটি ভুলভাবে পড়া সহজ:

int *bar;
*bar = &foo;    // error: use of uninitialized pointer bar!

এর প্রকৃত অর্থ যখন :

int *bar;
bar = &foo;

ভেরিয়েবল ডিক্লেয়ারেশন এবং অ্যাসাইনমেন্টটি পৃথক করে দিয়ে এইভাবে লিখিত হয়েছিল, বিভ্রান্তির এমন কোনও সম্ভাবনা নেই, এবং ব্যবহার ↔ আপনার কেএন্ডআর উদ্ধৃতিতে বর্ণিত ডিক্লারেশন প্যারালালিজম পুরোপুরি কার্যকর:

  • প্রথম লাইনটি একটি ভেরিয়েবল ঘোষণা করে bar, যেমন *barএকটি int

  • দ্বিতীয় লাইনে (একটি ) ( একটিও) এর জন্য একটি উপন্যাস তৈরি fooকরার ঠিকানা নির্ধারিত করে ।bar*barintfooint

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


4
আমি প্রলুব্ধ করা চাই typedeftypedef int *p_int;এর অর্থ হ'ল ধরণের ভেরিয়েবলের এমন একটি p_intসম্পত্তি রয়েছে যা *p_intএকটি int। তাহলে আমাদের আছে p_int bar = &foo;। কাউকে অস্বীকারহীন ডেটা তৈরি করতে উত্সাহিত করা এবং পরে এটি ডিফল্ট অভ্যাসের বিষয় হিসাবে অর্পণ করা মনে হয় ... এটি একটি খারাপ ধারণা like
ইয়াক্ক - অ্যাডাম নেভ্রামুমন্ট

6
এটি কেবলমাত্র সি-ঘোষণার মস্তিষ্ক-ক্ষতিগ্রস্থ স্টাইল; এটি পয়েন্টার নির্দিষ্ট নয়। বিবেচনা করুন int a[2] = {47,11};, এটি (অস্তিত্বহীন) উপাদান a[2]আইহের একটি সূচনা নয় ।
মার্ক ভ্যান লিউউইন

5
@ মার্কওয়ানলিউউইন মস্তিষ্ক-ক্ষতির সাথে একমত আদর্শভাবে, *এই ধরণের অংশ হওয়া উচিত, ভেরিয়েবলের সাথে আবদ্ধ নয় এবং তারপরে আপনি int* foo_ptr, bar_ptrদুটি পয়েন্টার ঘোষণার জন্য লিখতে সক্ষম হবেন । তবে এটি আসলে একটি পয়েন্টার এবং একটি পূর্ণসংখ্যা ঘোষণা করে।
বার্মার

1
এটি কেবল "শর্টহ্যান্ড" ঘোষণা / কার্যভারগুলি সম্পর্কে নয় about আপনি যখন পয়েন্টারগুলি ফাংশন আর্গুমেন্ট হিসাবে ব্যবহার করতে চান সেই মুহুর্তে পুরো বিষয়টি আবার উঠে আসে।
আরমিন

30

ঘোষণায় সংক্ষিপ্ত

ঘোষণা এবং আরম্ভের মধ্যে পার্থক্যটি জেনে ভাল লাগছে। আমরা ভেরিয়েবলগুলি প্রকার হিসাবে ঘোষণা করি এবং মানগুলির সাথে তাদের সূচনা করি। যদি আমরা একই সাথে উভয়টি করি তবে আমরা প্রায়শই এটি সংজ্ঞা বলি।

1. int a; a = 42;

int a;
a = 42;

আমরা ঘোষণা একটি intনামে একটি । তারপরে আমরা এটিকে একটি মান দিয়ে শুরু করি 42

2. int a = 42;

আমরা ঘোষণা এবং intনামে একটি এবং এটি মান 42. এটা দিয়ে সক্রিয়া করা হয় দিতে 42। একটি সংজ্ঞা।

3. a = 43;

আমরা যখন ভেরিয়েবলগুলি ব্যবহার করি তখন আমরা বলি যে আমরা সেগুলি ব্যবহার করি। a = 43একটি অ্যাসাইনমেন্ট অপারেশন। আমরা ভেরিয়েবল এ 43 নম্বর বরাদ্দ করি।

বলার মাধ্যমে

int *bar;

আমরা বারটিকে কোন ইন্টির পয়েন্টার হিসাবে ঘোষণা করি । বলার মাধ্যমে

int *bar = &foo;

আমরা ঘোষণা দণ্ড এবং ঠিকানা দিয়ে এটি আরম্ভ foo বিন্যাস

পরে আমরা সক্রিয়া আছে বার অ্যাক্সেস একই অপারেটর, তারকাচিহ্ন, ব্যবহার এবং এর মান উপর কাজ করতে পারে foo বিন্যাস । অপারেটর ব্যতীত আমরা পয়েন্টারটি যে দিকে ইঙ্গিত করছে তাতে অ্যাক্সেস এবং পরিচালনা করি।

তা ছাড়া ছবিতে কথা বলতে দিলাম।

কি

যা চলছে তার একটি সরলীকৃত দাবী IM (এবং এখানে যদি আপনি বিরতি দিতে চান তবে কোনও প্লেয়ার সংস্করণ )

          ASCIIMATION


22

২ য় বিবৃতিটি int *bar = &foo;মেমোরিতে চিত্রের মতো হিসাবে দেখা যেতে পারে,

   bar           foo
  +-----+      +-----+
  |0x100| ---> |  1  |
  +-----+      +-----+ 
   0x200        0x100

এখন barধরনের একটি পয়েন্টার intঠিকানা ধারণকারী &এর foo। ইউনারি অপারেটরটি ব্যবহার করে *আমরা পয়েন্টারটি ব্যবহার করে 'ফু' এর মধ্যে থাকা মানটি পুনরুদ্ধার করতে পারি bar

সম্পাদনা : নতুনদের সাথে আমার দৃষ্টিভঙ্গি হল memory addressএকটি ভেরিয়েবলের অর্থ ব্যাখ্যা করা ie

Memory Address:ওএস দ্বারা সরবরাহিত প্রতিটি ভেরিয়েবলের একটি ঠিকানা যুক্ত থাকে। ইন int a;, &aপরিবর্তনশীল ঠিকানা a

মৌলিক ধরণের ভেরিয়েবল Cহিসাবে ব্যাখ্যা করা চালিয়ে যান ,

Types of variables: ভেরিয়েবলগুলি স্বতন্ত্র ধরণের মানগুলি ধরে রাখতে পারে তবে ঠিকানাগুলি নয়।

int a = 10; float b = 10.8; char ch = 'c'; `a, b, c` are variables. 

Introducing pointers: যেমন উপরে ভেরিয়েবল হিসাবে বলা হয়েছে

 int a = 10; // a contains value 10
 int b; 
 b = &a;      // ERROR

এটি কার্যকর করা সম্ভব b = aতবে তা নয় b = &a, যেহেতু ভেরিয়েবল bমান রাখতে পারে তবে ঠিকানা রাখতে পারে না, সুতরাং আমাদের পয়েন্টার প্রয়োজন ।

Pointer or Pointer variables :কোনও ভেরিয়েবলের কোনও ঠিকানা থাকলে এটি পয়েন্টার ভেরিয়েবল হিসাবে পরিচিত। *ঘোষণাপত্রে এটি পয়েন্টার হিসাবে তা জানাতে ব্যবহার করুন ।

 Pointer can hold address but not value
 Pointer contains the address of an existing variable.
 Pointer points to an existing variable

3
সমস্যাটি হ'ল int *ip"আইপি পয়েন্টার (*) টাইপ ইন্টের একটি পয়েন্টার" হিসাবে পড়া আপনি এরকম কিছু পড়ার সময় সমস্যায় পড়েন x = (int) *ip
আর্মিন

2
@abw এটি সম্পূর্ণ আলাদা কিছু, তাই প্রথম বন্ধনী। আমি মনে করি না যে ঘোষণা এবং কাস্টিংয়ের মধ্যে পার্থক্য বুঝতে লোকদের অসুবিধা হবে।
bzeaman

@ abw ইন x = (int) *ip;, পয়েন্টারকে ডিফারেন্সিং ipকরে মানটি পান intএবং যা প্রকারের থেকে মানটি কাস্ট করুন ip
সুনীল বোজনাপালি

1
@ বেনোজেমন আপনি ঠিক বলেছেন: কাস্টিং এবং ঘোষণা দুটি আলাদা জিনিস। আমি নক্ষত্রের বিভিন্ন ভূমিকায় ইঙ্গিত করার চেষ্টা করেছি: 1 ম "এটি কোনও অন্তর্নিহিত নয়, তবে" 2 "ইন্টির একটি পয়েন্টার এটি আপনাকে ইনট দেবে, তবে পয়েন্টারটি ইনট করবে না।
আরমিন

2
@abw: কোনটি কেন শিক্ষার int* bar = &foo;তোলে লোড আরো অর্থে। হ্যাঁ, আমি জানি আপনি যখন কোনও একক ঘোষণায় একাধিক পয়েন্টার ঘোষণা করেন তখন এটি সমস্যার সৃষ্টি করে। না, আমি মোটেই তা মনে করি না।
অরবিটে লাইটনেস রেস

17

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

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

পার্থক্যটি হাইলাইট করার int* barপরিবর্তে আপনি লিখতে পারেন int *bar। এর অর্থ আপনি কে & আর "ঘোষণার নকলগুলি ব্যবহার করুন" পদ্ধতির অনুসরণ করবেন না, তবে স্ট্রস্ট্রপ সি ++ পদ্ধতির :

আমরা *barপূর্ণসংখ্যা হিসাবে ঘোষণা করি না । আমরা ঘোষণা barএকটি হতে int*। আমরা একই লাইনে একটি নব নির্মিত পরিবর্তনশীল আরম্ভ করতে চান, এটা স্পষ্ট যে, আমরা সঙ্গে তার আচরণ করা হয় bar, না *barint* bar = &foo;

ত্রুটিগুলি:

  • আপনাকে একাধিক পয়েন্টার ঘোষণার ইস্যু ( int* foo, barবনাম int *foo, *bar) সম্পর্কে আপনার ছাত্রকে সতর্ক করতে হবে ।
  • আপনাকে তাদের আঘাতের বিশ্বের জন্য প্রস্তুত করতে হবে । অনেক প্রোগ্রামাররা ভেরিয়েবলের নামের সাথে সংলগ্ন তারকাটিকে দেখতে চান এবং তাদের স্টাইলটি ন্যায়সঙ্গত করতে তারা বড় দৈর্ঘ্য নেবে। এবং অনেক স্টাইল গাইড এই স্বরলিপিটি স্পষ্টভাবে প্রয়োগ করে (লিনাক্স কার্নেল কোডিং স্টাইল, নাসা সি স্টাইল গাইড ইত্যাদি)।

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

তবে শিগগিরই শিক্ষার্থীকে ফাংশন আর্গুমেন্ট হিসাবে পয়েন্টারগুলি নিয়ে কাজ করতে হবে। এবং রিটার্ন টাইপ হিসাবে পয়েন্টার। এবং ফাংশন নির্দেশক। আপনি int *func();এবং এর মধ্যে পার্থক্য ব্যাখ্যা করতে হবে int (*func)();। আমি মনে করি খুব শীঘ্রই জিনিসগুলি বিচ্ছিন্ন হয়ে যাবে। এবং খুব শীঘ্রই পরবর্তী সময়ের চেয়ে ভাল।


16

কে int *pঅ্যান্ডআর শৈলীর পক্ষে এবং স্ট্রাস্ট্রাপ শৈলীর পক্ষে হওয়ার কারণ রয়েছে int* p; উভয়ই প্রতিটি ভাষায় বৈধ (এবং একই জিনিসটির অর্থ), তবে স্ট্রস্ট্রট্রপ যেমন লিখেছেন:

"ইনট * পি;" এর মধ্যে পছন্দ এবং "ইনট * পি;" সঠিক এবং ভুল সম্পর্কে নয়, শৈলী এবং জোর সম্পর্কে। সি এক্সপ্রেশন জোর দেওয়া; ঘোষণাগুলি প্রায়শই প্রয়োজনীয় মন্দের চেয়ে সামান্য বেশি বিবেচিত হত। অন্যদিকে, সি ++ এর ধরণের উপর প্রচুর জোর রয়েছে।

এখন, যেহেতু আপনি এখানে সি পড়ানোর চেষ্টা করছেন, এটি আপনাকে পরামর্শ দেয় যে আপনি আরও বেশি প্রকারের মত প্রকাশের প্রতি জোর দেওয়া উচিত, তবে কিছু লোক আরও সহজেই একটি জোরকে অন্যটির চেয়ে দ্রুত তৈরি করতে পারেন, এবং এটি ভাষাটির পরিবর্তে তাদের সম্পর্কে।

অতএব কিছু লোক এই ধারণাটি শুরু করতে আরও সহজ হবে যে একটি int*একটি থেকে আলাদা জিনিস intএবং সেখান থেকে যেতে।

কেউ দ্রুত যে ব্যবহারসমূহ দিকে তাকিয়ে প্রণালী grok হয়, তাহলে int* barআছে barএকটা জিনিস যে কোন int হয় না, কিন্তু একটি পয়েন্টার int, তাহলে তারা দ্রুত দেখতে পাবেন যে *barহয় কিছু কাজ করার জন্য bar, এবং বাকি অনুসরণ করা হবে। একবার এটি হয়ে গেলে আপনি পরে ব্যাখ্যা করতে পারবেন কেন সি কোডাররা পছন্দ করেন int *bar

অথবা না. যদি এমন এক উপায় ছিল যে প্রত্যেকে প্রথমে ধারণাটি বুঝতে পেরেছিল যে আপনি প্রথমে কোনও সমস্যা হবেন না এবং একজন ব্যক্তির কাছে এটি ব্যাখ্যা করার সর্বোত্তম উপায় এটি অপরকে ব্যাখ্যা করার সর্বোত্তম উপায় হবে না।


1
আমি স্ট্রোস্ট্রপের যুক্তি পছন্দ করি তবে আমি অবাক হয়েছি কেন তিনি & উল্লেখ প্রতীকটি উল্লেখগুলি উল্লেখ করতে বেছে নিয়েছিলেন - অন্য একটি সম্ভাব্য সমস্যা।
আর্মিন

1
@ আমার মনে হয় তিনি প্রতিসাম্য দেখেছেন যদি আমরা করতে পারি int* p = &aতবে আমরা করতে পারি int* r = *p। আমি দৃ sure়ভাবে নিশ্চিত যে সে এটি সি ++ এর ডিজাইন এবং বিবর্তনে covered েকে রেখেছে, তবে এটি পড়ার পরে অনেক দিন চলে গেছে, এবং আমি বোকামি দিয়ে আমার অনুলিপি কাউকে ধার দিয়েছি।
জন হানা

3
আমি আপনি কি বলতে চান int& r = *p। এবং আমি বাজি ধরেছি যে orণগ্রহীতা এখনও বইটি হজম করার চেষ্টা করছে।
আর্মিন

@ ডাব্লু, হ্যাঁ আমি যা বলছিলাম ঠিক তাই ছিল। হায়রে টাইপস মন্তব্যগুলিতে সংকলনের ত্রুটি বাড়ায় না। বইটি আসলে বেশ তাত্পর্যপূর্ণ is
জন হান্না

4
কারণ আমি সি এর উপর প্যাসকেলের সিনট্যাক্স (যেমন জনপ্রিয় প্রসারিত) পক্ষপাতী হল যে হয় Var A, B: ^Integer;স্পষ্ট করে তোলে প্রকার "পূর্ণসংখ্যা পয়েন্টার" উভয় ক্ষেত্রে প্রযোজ্য Aএবং B। একটি K&Rশৈলী ব্যবহার int *a, *bকরাও কার্যক্ষম; কিন্তু ঘোষণা মত int* a,b;অবশ্য যেন কেমন লাগে aএবং bউভয় ঘোষিত হওয়ার হিসেবে int*, কিন্তু বাস্তবে এটা ঘোষণা aএকটি হিসাবে int*এবং bএকটি হিসাবে int
সুপারক্যাট

9

TL; ড:

প্রশ্ন: সি পয়েন্টার (ঘোষণার বনাম আনারি অপারেটর) কোনও শিক্ষানবিশকে কীভাবে ব্যাখ্যা করবেন?

উঃ না। শিক্ষানবিসকে পয়েন্টারগুলি ব্যাখ্যা করুন এবং কীভাবে সি সিনট্যাক্সে তাদের পয়েন্টার ধারণাটি উপস্থাপন করবেন তা তাদের দেখান।


আমি সি প্রোগ্রামিং শুরুর দিকে পয়েন্টারগুলি ব্যাখ্যা করতে সাম্প্রতিক আনন্দ পেয়েছি এবং নিম্নলিখিত অসুবিধায় হোঁচট খেয়েছি।

আইএমও সি সিনট্যাক্সটি ভয়াবহ নয়, তবে এটি দুর্দান্তও নয়: আপনি যদি ইতিমধ্যে পয়েন্টারগুলি বুঝতে পারেন বা সেগুলি শেখার ক্ষেত্রে কোনও সহায়তা করেন না তবে এটি কোনও দুর্দান্ত বাধা নয়।

সুতরাং: পয়েন্টারগুলি ব্যাখ্যা করে শুরু করুন এবং নিশ্চিত করুন যে তারা সত্যই সেগুলি বুঝতে পেরেছে:

  • বাক্স এবং তীরের চিত্রগুলি দিয়ে সেগুলি ব্যাখ্যা করুন। আপনি এটি হেক্স অ্যাড্রেস ছাড়াই করতে পারেন, যদি সেগুলি প্রাসঙ্গিক না হয় তবে কেবল তীরগুলি অন্য বাক্সে বা কিছু নুল চিহ্নকে দেখায় show

  • সিউডোকোড দিয়ে ব্যাখ্যা করুন: কেবল foo এর ঠিকানা এবং বারে সঞ্চিত মান লিখুন ।

  • তারপরে, যখন আপনার শিক্ষানবিশরা বুঝতে পারে যে পয়েন্টারগুলি কী, এবং কেন এবং কীভাবে সেগুলি ব্যবহার করতে হয়; তারপরে সি সিনট্যাক্সে ম্যাপিংটি দেখান।

আমার সন্দেহ হয় যে কে & আর পাঠ্যটি একটি ধারণাগত মডেল সরবরাহ করে না তা হ'ল তারা ইতিমধ্যে পয়েন্টারগুলি বুঝতে পেরেছিল এবং সম্ভবত প্রতিটি অন্যান্য সক্ষম প্রোগ্রামারও সে সময় ধরেছিল। স্মৃতিবিজ্ঞান হ'ল ম্যাপিংয়ের বোঝাটি বোঝা ধারণা থেকে সিনট্যাক্সের কেবল স্মৃতি inder


প্রকৃতপক্ষে; প্রথমে তত্ত্বটি দিয়ে শুরু করুন, বাক্য গঠনটি পরে আসে (এবং এটি গুরুত্বপূর্ণ নয়)। মনে রাখবেন যে মেমরির ব্যবহারের তত্ত্বটি ভাষা নির্ভর নয়। এই বাক্স-এবং-তীর মডেলটি আপনাকে যে কোনও প্রোগ্রামিং ভাষায় কাজ করতে সহায়তা করবে।

কিছু উদাহরণের জন্য এখানে দেখুন (যদিও গুগলও এতে
ɔɯǝɹ

7

সি শিখতে শুরু করার সময় এই বিষয়টি কিছুটা বিভ্রান্তিকর is

এখানে প্রাথমিক নীতিগুলি যা আপনাকে শুরু করতে সহায়তা করতে পারে:

  1. সি তে কয়েকটি প্রাথমিক ধরণ রয়েছে:

    • char: 1 বাইটের আকার সহ একটি পূর্ণসংখ্যা মান।

    • short: 2 বাইট আকারের একটি পূর্ণসংখ্যা মান।

    • long: 4 বাইট আকারের একটি পূর্ণসংখ্যা মান।

    • long long: 8 বাইটের আকার সহ একটি পূর্ণসংখ্যা মান।

    • float: 4 বাইটের আকার সহ একটি অ-পূর্ণসংখ্যার মান।

    • double: 8 বাইটের আকার সহ একটি অ-পূর্ণসংখ্যার মান।

    নোট করুন যে প্রতিটি ধরণের আকার সাধারণত সংকলক দ্বারা সংজ্ঞায়িত হয় মান দ্বারা নয়।

    পূর্ণসংখ্যা ধরনের short, longএবং long longসাধারণত দ্বারা অনুসরণ করা হয় int

    এটি অবশ্য প্রয়োজনীয় নয় এবং আপনি এগুলি ব্যবহার না করেই ব্যবহার করতে পারেন int

    বিকল্পভাবে, আপনি কেবল বর্ণনা করতে পারেন int, তবে এটি বিভিন্ন সংকলক দ্বারা আলাদা ব্যাখ্যা করতে পারে।

    সুতরাং সংক্ষেপে এই:

    • shortএকই হিসাবে short intতবে অগত্যা একই নয় int

    • longএকই হিসাবে long intতবে অগত্যা একই নয় int

    • long longএকই হিসাবে long long intতবে অগত্যা একই নয় int

    • একটি প্রদত্ত কম্পাইলার তারিখে intপারেন হয় short intবা long intবা long long int

  2. যদি আপনি কোনও প্রকারের ভেরিয়েবল ঘোষণা করেন তবে আপনি এটির দিকে নির্দেশ করে অন্য ভেরিয়েবলটিও ঘোষণা করতে পারেন।

    উদাহরণ স্বরূপ:

    int a;

    int* b = &a;

    সুতরাং সংক্ষেপে, প্রতিটি মৌলিক টাইপের জন্য, আমরা একটি অনুরূপ পয়েন্টার প্রকার আছে।

    উদাহরণস্বরূপ: shortএবং short*

    পরিবর্তনশীলকে "দেখার" জন্য দুটি উপায় রয়েছে b (এটি সম্ভবত বেশিরভাগ নবজাতককেই বিভ্রান্ত করে) :

    • আপনি bটাইপের একটি পরিবর্তনশীল হিসাবে বিবেচনা করতে পারেন int*

    • আপনি *bটাইপের একটি পরিবর্তনশীল হিসাবে বিবেচনা করতে পারেন int

    সুতরাং, কিছু লোক ঘোষণা করবে int* b, অন্যরা ঘোষণা করবে int *b

    তবে বিষয়টির সত্যতা হ'ল এই দুটি ঘোষণা একই রকম (স্থানগুলি অর্থহীন)।

    আপনি হয় bএকটি পূর্ণসংখ্যা মানের পয়েন্টার হিসাবে ব্যবহার করতে পারেন , বা *bআসল পয়েন্ট পূর্ণসংখ্য মান হিসাবে।

    আপনি পেতে পারেন (পড়ুন) সরু মান: int c = *b

    আর তুমি সেট করতে পারেন (লিখন) সরু মান: *b = 5

  3. একটি পয়েন্টার কোনও মেমরি ঠিকানার দিকে নির্দেশ করতে পারে, এবং কেবলমাত্র আপনি আগে ঘোষণা করেছিলেন এমন কিছু ভেরিয়েবলের ঠিকানার দিকেও নির্দেশ করতে পারে। যাইহোক, পয়েন্টার ব্যবহার করার সময় আপনাকে অবশ্যই সতর্কতা অবলম্বন করতে হবে পয়েন্টেড মেমোরি ঠিকানায় অবস্থিত মানটি পেতে বা সেট করতে।

    উদাহরণ স্বরূপ:

    int* a = (int*)0x8000000;

    এখানে, আমাদের a0x8000000 মেমরি ঠিকানার দিকে চলক নির্দেশ করে।

    যদি এই প্রোগ্রামের মেমোরি স্পেসের মধ্যে এই মেমরি ঠিকানাটি ম্যাপ না করা হয়, তবে *aমেমরি অ্যাক্সেস লঙ্ঘনের কারণে সম্ভবত যে কোনও পড়া বা লেখার ক্রিয়াকলাপটি আপনার প্রোগ্রামটি ক্রাশ করবে।

    আপনি নিরাপদে এর মান পরিবর্তন করতে পারেন তবে এর মান পরিবর্তন করার ক্ষেত্রে aআপনার খুব যত্নশীল হওয়া উচিত *a

  4. প্রকার void*যে এটি একটি সঙ্গতিপূর্ণ "মান টাইপ" যা ব্যবহার করা যেতে পারে (অর্থাত, আপনার কি ডিক্লেয়ার করতে পারবে না নেই মধ্যে ব্যতিক্রমী void a)। এই ঠিকানাটিতে থাকা ডেটার ধরণটি নির্দিষ্ট না করে কেবল মেমরি ঠিকানার সাধারণ পয়েন্টার হিসাবে ব্যবহৃত হয়।


7

সম্ভবত এর থেকে আরও কিছুটা পদক্ষেপ নেওয়া সহজ করে তোলে:

#include <stdio.h>

int main()
{
    int foo = 1;
    int *bar = &foo;
    printf("%i\n", foo);
    printf("%p\n", &foo);
    printf("%p\n", (void *)&foo);
    printf("%p\n", &bar);
    printf("%p\n", bar);
    printf("%i\n", *bar);
    return 0;
}

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

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

পরবর্তী ধাপে তাদের পেতে ব্যাখ্যা হয় আপনি কিভাবে i[0]সম্পর্কিত &i। যদি তারা এটি করতে পারে তবে তারা এটিকে ভুলে যাবে না এবং আপনি স্ট্রাক্ট সম্পর্কে কথা বলতে শুরু করতে পারেন, সময়ের আগে একটু আগেও, যাতে এটি ডুবে যায়।

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


এটি একটি ভাল অনুশীলন। তবে যে বিষয়টি আমি সামনে আনতে চেয়েছিলাম তা হ'ল একটি নির্দিষ্ট সিনট্যাকটিক যা শিক্ষার্থীদের তৈরি মানসিক মডেলটিতে প্রভাব ফেলতে পারে। এই বিবেচনা করুন: int foo = 1;। এখন এই ঠিক আছে: int *bar; *bar = foo;। এটি ঠিক নেই:int *bar = foo;
আর্মিন

1
@abw শিক্ষার্থীদের নিজেরাই যা বলছে তা হ'ল একমাত্র বিষয়টি বোঝা যায়। তার অর্থ "একটি দেখুন, এক করুন, একটি শেখান"। তারা জঙ্গলে কী সিনট্যাক্স বা শৈলী দেখতে পাবে তা থেকে আপনি সুরক্ষা বা ভবিষ্যদ্বাণী করতে পারবেন না (এমনকি আপনার পুরাতন রেপোও!), তাই আপনাকে পর্যাপ্ত অনুমান দেওয়াতে হবে যে প্রাথমিক ধারণাটি শৈলীর চেয়ে আলাদা বোঝা যায় - এবং তারপরে তাদের শেখানো শুরু করুন যে নির্দিষ্ট শৈলী কেন স্থির করা হয়েছে। ইংরেজি শেখানোর মতো: একটি নির্দিষ্ট প্রসঙ্গে বেসিক এক্সপ্রেশন, আইডিয়াম, শৈলী, নির্দিষ্ট শৈলী। দুর্ভাগ্যক্রমে সহজ নয়। যাই হোক, শুভকামনা!
zxq9

6

ধরণ অভিব্যক্তি *bar হয় int; সুতরাং, পরিবর্তনশীল (এবং এক্সপ্রেশন) ধরণের barহয় int *। যেহেতু ভেরিয়েবলের পয়েন্টার টাইপ থাকে তাই এর ইনিশিয়ালাইজারটিতে পয়েন্টার টাইপও থাকতে হবে।

পয়েন্টার ভেরিয়েবল ইনিশিয়েশন এবং অ্যাসাইনমেন্টের মধ্যে একটি অসঙ্গতি রয়েছে; এটি ঠিক এমন কিছু যা কঠিনভাবে শিখতে হবে।


3
এখানে উত্তরগুলি খুঁজছেন আমার অনুভূতি আছে যে অনেক অভিজ্ঞ প্রোগ্রামাররা এমনকি সমস্যাটি আর দেখতে পাচ্ছেন না। আমার ধারণা এটি "অসঙ্গতি নিয়ে বাঁচতে শেখা" এর একটি উপজাত।
আর্মন

3
@ অাবডব্লিউ: সূচনা করার নিয়মগুলি নিয়োগের নিয়মের চেয়ে পৃথক; স্ক্যালার গাণিতিক ধরণের জন্য পার্থক্যগুলি নগন্য, তবে এটি পয়েন্টার এবং সামগ্রিক প্রকারের জন্য গুরুত্বপূর্ণ। এটি এমন কিছু যা আপনাকে অন্য সমস্ত কিছুর পাশাপাশি ব্যাখ্যা করতে হবে।
জন বোদে

5

আমি বরং এটি এর চেয়ে বেশি প্রথম *প্রয়োগ হিসাবে পড়তে চাই ।intbar

int  foo = 1;           // foo is an integer (int) with the value 1
int* bar = &foo;        // bar is a pointer on an integer (int*). it points on foo. 
                        // bar value is foo address
                        // *bar value is foo value = 1

printf("%p\n", &foo);   // print the address of foo
printf("%p\n", bar);    // print the address of foo
printf("%i\n", foo);    // print foo value
printf("%i\n", *bar);   // print foo value

2
তারপরে আপনাকে তাদের ব্যাখ্যা int* a, bকরতে হবে যে তারা যা মনে করে তা কেন করে না।
ফারাপ

4
সত্য, তবে আমি int* a,bএটি ব্যবহার করি না বলে মনে করি না । আরও ভাল পছন্দসই, আপডেট করা ইত্যাদির জন্য ... প্রতি লাইনে কেবলমাত্র একটি ভেরিয়েবল ডিক্লেয়ারেশন হওয়া উচিত এবং এর চেয়ে বেশি কখনই নয়। এটি প্রবর্তকরা এটি পরিচালনা করতে পারে এমন কি, এটি প্রাথমিকের কাছেও বোঝানোর মতো কিছু।
গ্রোরেল

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

1
আমি @ গ্রোরেলের সাথে একমত *এই ধরণের অংশ হিসাবে ভাবা সহজ এবং নিরুৎসাহিত করা সহজ int* a, b। যতক্ষণ না আপনি বলার অপেক্ষা রাখে না পছন্দ যে *aধরনের হয় intবদলে aএকটি পয়েন্টার int...
কেভিন Ushey

@ গ্রোরেল সঠিক: int *a, b;ব্যবহার করা উচিত নয়। একই বিবৃতিতে বিভিন্ন ধরণের সাথে দুটি ভেরিয়েবল ঘোষণা করা বেশ নিখরচায় অনুশীলন এবং রক্ষণাবেক্ষণের বিষয়ে দৃ for় প্রার্থী down সম্ভবত এটি আমাদের মধ্যে যারা এমবেডেড ক্ষেত্রে কাজ করে তাদের ক্ষেত্রে আলাদা যেখানে একটি int*এবং intপ্রায়শই বিভিন্ন আকার থাকে এবং কখনও কখনও সম্পূর্ণ ভিন্ন মেমরির অবস্থানগুলিতে সঞ্চিত থাকে। এটি সি ভাষার অনেকগুলি দিকগুলির মধ্যে একটি যা সর্বোত্তমভাবে 'এটি অনুমোদিত, তবে এটি করবেন না' হিসাবে শেখানো হবে।
এভিল ডগ পাই

5
int *bar = &foo;

Question 1: কী bar?

Ans: এটি পয়েন্টার ভেরিয়েবল (টাইপ করতে int)। একটি পয়েন্টারটি কিছু বৈধ মেমরি অবস্থানের দিকে নির্দেশ করতে পারে এবং পরে *সেই স্থানে সঞ্চিত মানটি পড়ার জন্য একটি অমান্যিক অপারেটর ব্যবহার করে (* বার) অবলম্বন করা উচিত ।

Question 2: কী &foo?

Ans: foo হ'ল প্রকারের একটি পরিবর্তনশীল intsome যা কিছু বৈধ মেমরির স্থানে সংরক্ষণ করা হয় এবং সেই অবস্থানটি আমরা অপারেটরের কাছ থেকে &পাই তাই এখন আমাদের কাছে যা আছে তার কিছু বৈধ মেমরি অবস্থান &foo

সুতরাং উভয়ই একসাথে রাখলেন অর্থাৎ যা পয়েন্টারের প্রয়োজন তা ছিল একটি বৈধ মেমরি অবস্থান এবং এটি পেয়েছিল &fooতাই সূচনাটি ভাল।

এখন পয়েন্টারটি barবৈধ মেমরি অবস্থানের দিকে ইঙ্গিত করছে এবং এতে সঞ্চিত মানটি এটির অর্থ হ্রাস করতে পারে*bar


5

আপনার একটি শিক্ষানবিসকে নির্দেশ করা উচিত যা * ঘোষণার এবং অভিব্যক্তির পৃথক অর্থ। আপনারা জানেন যে, এক্সপ্রেশনটিতে * একটি অযৌক্তিক অপারেটর, এবং * ঘোষণায় কোনও অপারেটর হয় না এবং সংকলককে জানাতে যে টাইপের সাথে কেবল এক প্রকারের সিনট্যাক্স হয় তা এটি নির্দেশক টাইপ। একটি শিক্ষানবিসকে বলা ভাল, "* এর আলাদা অর্থ রয়েছে * * এর অর্থ বোঝার জন্য আপনার কোথায় পাওয়া উচিত * খুঁজে পাওয়া উচিত"


4

আমি মনে করি শয়তান মহাশূন্যে আছে।

আমি লিখব (কেবল শিক্ষানবিশকেই নয়, নিজের জন্যও): অন্তর্দৃষ্টি * বার = & ফু; ইন্ট * বারের পরিবর্তে = & foo;

সিনট্যাক্স এবং শব্দার্থবিজ্ঞানের মধ্যে সম্পর্ক কী তা এটি স্পষ্ট করে দেখা উচিত


4

এটি ইতিমধ্যে লক্ষ করা গেছে যে * এর একাধিক ভূমিকা রয়েছে।

আরও একটি সহজ ধারণা রয়েছে যা কোনও শিক্ষানবিশকে জিনিসগুলি বুঝতে সাহায্য করতে পারে:

ভাবুন যে "=" এর একাধিক ভূমিকা রয়েছে।

ঘোষণার সাথে যখন একই লাইনে অ্যাসাইনমেন্ট ব্যবহার করা হয়, তখন এটিকে নির্বাহী কল হিসাবে মনে করুন, কোনও স্বেচ্ছাসেবী অ্যাসাইনমেন্ট নয়।

যখন তুমি দেখ:

int *bar = &foo;

এটি প্রায় সমতুল্য বলে মনে করুন:

int *bar(&foo);

প্যারেন্টিহেসগুলি নক্ষত্রের চেয়ে বেশি প্রাধান্য পায়, সুতরাং "& বার" এর চেয়ে "বার" এর সাথে "বার" এর সাথে আরো অনেক সহজেই স্বীকৃতি দেওয়া হয়।


4

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

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

int x;

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

সুতরাং, ঘোষণা

int *p;
int a[3];

পয়েন্টটি ইন্টি পয়েন্টার হিসাবে উল্লেখ করুন কারণ '* পি' টাইপ ইনট রয়েছে, এবং এটি একটি ইনটসের অ্যারে কারণ একটি [3] (নির্দিষ্ট সূচক মানটিকে অগ্রাহ্য করে যা অ্যারের আকার হতে পারে বলে চিহ্নিত করা হয়) টাইপ রয়েছে int- এ।

(কীভাবে এই বোঝাপড়াটি ফাংশন পয়েন্টার ইত্যাদিতে প্রসারিত করা যায় তা বর্ণনা করতে চলেছে)

এটি এমন একটি উপায় যা আমি আগে এটি নিয়ে ভাবিনি, তবে এটি সিনট্যাক্সের ওভারলোডিংয়ের জন্য অ্যাকাউন্টিংয়ের বেশ সহজ সরল উপায় বলে মনে হয়।


3

যদি সমস্যাটি সিনট্যাক্স হয় তবে এটি টেমপ্লেট / ব্যবহারের সাথে সমমানের কোডটি দেখাতে সহায়ক হতে পারে।

template<typename T>
using ptr = T*;

এটি তখন হিসাবে ব্যবহার করা যেতে পারে

ptr<int> bar = &foo;

এর পরে, কেবল এই সি ++ পদ্ধতির সাথে স্বাভাবিক / সি সিনট্যাক্সটি তুলনা করুন। কনস্ট পয়েন্টারগুলি ব্যাখ্যা করার জন্য এটিও দরকারী।


2
নতুনদের জন্য এটি অনেক বেশি বিভ্রান্তিকর হবে।
কার্স্টেন

আমার যদিও আপনি পিটিআর সংজ্ঞা প্রদর্শন করবে না ছিল। এটি কেবল পয়েন্টার ঘোষণার জন্য ব্যবহার করুন।
MI3Guy

3

বিভ্রান্তির উত্সটি উত্থাপিত হয় যে *প্রতীকটি সি ব্যবহৃত হয় তার উপর নির্ভর করে সিতে বিভিন্ন অর্থ হতে পারে। কোনও শিক্ষানবিশকে নির্দেশকের ব্যাখ্যা দিতে, *বিভিন্ন প্রসঙ্গে প্রতীকটির অর্থ ব্যাখ্যা করা উচিত।

প্রজ্ঞাপনে

int *bar = &foo;  

*প্রতীক অপ্রত্যক্ষ্যতার অপারেটর না । পরিবর্তে, এটি barসংকলককে জানার ধরণ নির্দিষ্ট করতে সহায়তা করে যা কোনওটির barজন্য একটি পয়েন্টারint । অন্যদিকে, এটি যখন কোনও বিবৃতিতে উপস্থিত হয় *তখন প্রতীকটি (যখন আনরি অপারেটর হিসাবে ব্যবহৃত হয় ) ইন্ডিয়ারেশন সম্পাদন করে। সুতরাং, বিবৃতি

*bar = &foo;

এটি ভুল হবে কারণ এটি fooনিজের উদ্দেশ্যে নয় এমন বস্তুটির ঠিকানা নির্দিষ্ট barকরে barদেয়।


3

"সম্ভবত এটি ইন্ট * বার হিসাবে লেখা এটি আরও সুস্পষ্ট করে তোলে যে তারকাটি আসলে ধরণের অংশ, শনাক্তকারীর অংশ নয়" " তাই আমি করি। এবং আমি বলি যে এটি টাইপের মতো কিছু তবে কেবল একটি পয়েন্টার নামের জন্য।

"অবশ্যই এটি আপনাকে ইনটিউটিভ স্টাফ যেমন ইনট * এ, বি দিয়ে বিভিন্ন সমস্যায় ফেলেছে" "


2

এখানে আপনাকে সংকলক যুক্তি ব্যবহার করতে হবে, বুঝতে হবে এবং ব্যাখ্যা করতে হবে, মানুষের যুক্তি নয় (আমি জানি, আপনি একজন মানুষ, তবে এখানে আপনাকে কম্পিউটারের নকল করতে হবে ...)।

আপনি যখন লিখুন

int *bar = &foo;

সংকলক গ্রুপ যে হিসাবে

{ int * } bar = &foo;

যে: এখানে একটি নতুন পরিবর্তনশীল, তার নাম bar, তার ধরণ int- এ পয়েন্টার, এবং তার প্রাথমিক মান &foo

আর আপনি যোগ করতে হবে: =উপরে -এর মানে না একটি আরম্ভের একটি ভান, যেহেতু নিম্নলিখিত এক্সপ্রেশন মধ্যে *bar = 2;এটি হল একটি ভান

প্রতি মন্তব্য সম্পাদনা করুন:

সাবধান: একাধিক ঘোষণার ক্ষেত্রে *কেবলমাত্র নিম্নলিখিত ভেরিয়েবলের সাথে সম্পর্কিত:

int *bar = &foo, b = 2;

বার foo ঠিকানার দ্বারা ইনিশিয়াল্ট ইন্টের পয়েন্টার হয়, b একটি ইনট আরম্ভ হয় 2 এবং এর মধ্যে

int *bar=&foo, **p = &bar;

ইন্টি স্টিল পয়েন্টারে বার করুন, এবং পি ঠিকানা বা বারের সূচনাপ্রাপ্ত ইন্টিতে একটি পয়েন্টারটির পয়েন্টার।


2
আসলে সংকলক এটি এর মতো গোষ্ঠী দেয় না: এটিকে int* a, b;একটিকে পয়েন্টার হিসাবে ঘোষণা করে int, তবে বি হতে একটি int*প্রতীক মাত্র দুটি স্বতন্ত্র অর্থ রয়েছে: একটি ঘোষণা, এটা একটা পয়েন্টার টাইপ চিহ্নিত, এবং একটি অভিব্যক্তি এটা ইউনারী dereference অপারেটর হয়।
tmlen

@ টিম্লেইন: আমি যেটি বোঝাতে *চাইছিলাম তা হ'ল ইনিশিয়েশনে, প্রকারটিতে প্রসারিত, যাতে পয়েন্টারটি আরম্ভ করা হয় যখন একটি প্রভাবের মধ্যে পয়েন্ট মানটি প্রভাবিত হয়। তবে কমপক্ষে আপনি আমাকে একটি দুর্দান্ত টুপি দিয়েছেন :-)
বালেস্টা

0

মূলত পয়েন্টার কোনও অ্যারে ইঙ্গিত নয়। শিক্ষানবিস সহজেই মনে করেন যে পয়েন্টারটি অ্যারের মতো দেখায়। স্ট্রিংয়ের বেশিরভাগ উদাহরণ ব্যবহার করে

"চর * পিএসটি" এটি দেখতে একই রকম

"চর টিআর [80]"

তবে, গুরুত্বপূর্ণ বিষয়গুলি, পয়েন্টারকে সংকলকের নীচের স্তরে কেবল পূর্ণসংখ্যা হিসাবে বিবেচনা করা হয়।

আসুন উদাহরণগুলি দেখুন:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv, char **env)
{
    char str[] = "This is Pointer examples!"; // if we assume str[] is located in 0x80001000 address

    char *pstr0 = str;   // or this will be using with
    // or
    char *pstr1 = &str[0];

    unsigned int straddr = (unsigned int)pstr0;

    printf("Pointer examples: pstr0 = %08x\n", pstr0);
    printf("Pointer examples: &str[0] = %08x\n", &str[0]);
    printf("Pointer examples: str = %08x\n", str);
    printf("Pointer examples: straddr = %08x\n", straddr);
    printf("Pointer examples: str[0] = %c\n", str[0]);

    return 0;
}

ফলাফলগুলি এই 0x2a6b7ed0 পছন্দ করবে স্ট্রের ঠিকানা []

~/work/test_c_code$ ./testptr
Pointer examples: pstr0 = 2a6b7ed0
Pointer examples: &str[0] = 2a6b7ed0
Pointer examples: str = 2a6b7ed0
Pointer examples: straddr = 2a6b7ed0
Pointer examples: str[0] = T

সুতরাং, মূলত, পয়েন্টার মনে রাখবেন এক ধরণের পূর্ণসংখ্যা। ঠিকানা উপস্থাপন


-1

আমি ব্যাখ্যা করব যে ইনটগুলি বস্তু, যেমন ভাসমান ইত্যাদি A

আপনি যখন প্রথম কোনও পয়েন্টার ঘোষণা করেন আপনি টাইপ-পয়েন্টার-নাম সিনট্যাক্স ব্যবহার করেন। এটি একটি "পূর্ণসংখ্যার-পয়েন্টার নাম হিসাবে পরিচিত যা কোনও পূর্ণসংখ্যার অবজেক্টের ঠিকানার দিকে নির্দেশ করতে পারে" read আমরা কেবল ডিক্লেয়ারেশনের সময় এই সিনট্যাক্সটি ব্যবহার করি, আমরা কীভাবে কোনও 'int num1' হিসাবে ঘোষণা করি তার অনুরূপ তবে আমরা কেবল 'num1' ব্যবহার করি যখন আমরা সেই পরিবর্তনশীলটি ব্যবহার করতে চাই, 'int num1' না।

int x = 5; // 5 এর মান সহ একটি পূর্ণসংখ্যার অবজেক্ট

int * পিটিআর; // ডিফল্টরূপে NULL এর মান সহ একটি পূর্ণসংখ্যা

কোনও অবজেক্টের ঠিকানার দিকে নির্দেশ করার জন্য আমরা '&' চিহ্ন ব্যবহার করি যা "এর ঠিকানা" হিসাবে পড়া যায়।

ptr = & x; // এখন মান 'এক্স' এর ঠিকানা

যেহেতু পয়েন্টারটি কেবলমাত্র অবজেক্টের ঠিকানা, সেই ঠিকানায় আসল মান পেতে আমাদের অবশ্যই '*' চিহ্ন ব্যবহার করতে হবে যা যখন পয়েন্টারের আগে ব্যবহার করা হয় তখন "দ্বারা নির্দেশিত ঠিকানার মান"।

std :: cout << * পিটিআর; // ঠিকানায় মানটি প্রিন্ট করুন

আপনি সংক্ষেপে ব্যাখ্যা করতে পারেন যে ' ' একটি 'অপারেটর' যা বিভিন্ন ধরণের অবজেক্টের সাথে বিভিন্ন ফলাফল দেয় returns যখন কোনও পয়েন্টার দিয়ে ব্যবহার করা হয়, ' ' অপারেটরটির অর্থ আর "গুণিত" হয় না।

এটি ভেরিয়েবলের কীভাবে একটি নাম এবং একটি মান রয়েছে এবং একটি পয়েন্টারের একটি ঠিকানা (নাম) এবং একটি মান রয়েছে তা দেখিয়ে একটি চিত্র আঁকতে সহায়তা করে এবং নির্দেশকের মানটি ইন্টের ঠিকানা হবে তা দেখায়।


-1

একটি পয়েন্টার ঠিকানা সংরক্ষণের জন্য ব্যবহৃত একটি পরিবর্তনশীল।

একটি কম্পিউটারে মেমোরিটি বাইট (একটি বাইট 8 বিট নিয়ে গঠিত) একটি ক্রমিক পদ্ধতিতে সাজানো হয়। প্রতিটি বাইটের সাথে এটির সাথে যুক্ত থাকে ঠিক একটি অ্যারেতে সূচি বা সাবস্ক্রিপ্টের মতো, যা বাইটের ঠিকানা বলে। বাইটের ঠিকানাটি মেমরির আকারের তুলনায় 0 থেকে এক থেকে কম শুরু হয়। উদাহরণস্বরূপ, র‌্যামের একটি 64 এমবিতে বলুন, এখানে 64 * 2 2 20 = 67108864 বাইট রয়েছে। সুতরাং এই বাইটগুলির ঠিকানা 0 থেকে 67108863 থেকে শুরু হবে।

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

আসুন দেখুন যখন আপনি একটি ভেরিয়েবল ঘোষণা করেন তখন কী হয়।

int চিহ্ন;

যেহেতু আমরা জানি যে কোনও int 4 বাইট ডেটা দখল করে (ধরে নিই আমরা 32-বিট সংকলক ব্যবহার করছি), তাই সংকলক একটি পূর্ণসংখ্যার মান সঞ্চয় করতে মেমরি থেকে টানা 4 বাইট সংরক্ষণ করে। বরাদ্দকৃত 4 টি বাইটের প্রথম বাইটের ঠিকানাটি চলক চিহ্নগুলির ঠিকানা হিসাবে পরিচিত। ধরা যাক যে টানা 4 টি বাইটের ঠিকানা 5004, 5005, 5006 এবং 5007 হয় তবে চলক চিহ্নগুলির ঠিকানা 5004 হবে। এখানে চিত্র বর্ণনা লিখুন

পয়েন্টার ভেরিয়েবল ঘোষণা করা

যেমন ইতিমধ্যে বলেছে যে পয়েন্টারটি একটি ভেরিয়েবল যা একটি মেমরি ঠিকানা সঞ্চয় করে। অন্য কোনও ভেরিয়েবলের মতো আপনার পয়েন্টার ভেরিয়েবলটি ব্যবহারের আগে আপনাকে প্রথমে ঘোষণা করতে হবে to এখানে আপনি কীভাবে পয়েন্টার ভেরিয়েবল ঘোষণা করতে পারেন।

বাক্য গঠন: data_type *pointer_name;

ডেটা_ টাইপ হ'ল পয়েন্টারের প্রকার (এটি পয়েন্টারের বেস টাইপ হিসাবেও পরিচিত)। পয়েন্টার_নামটি ভেরিয়েবলের নাম, যা কোনও বৈধ সি শনাক্তকারী হতে পারে।

আসুন কিছু উদাহরণ নেওয়া যাক:

int *ip;

float *fp;

ইন্ট * আইপি মানে আইপি একটি পয়েন্টার ভেরিয়েবল যা টাইপ ইন্টের ভেরিয়েবলগুলিকে নির্দেশ করতে সক্ষম। অন্য কথায়, একটি পয়েন্টার ভেরিয়েবল আইপি কেবল টাইপ ইন্টের ভেরিয়েবলের ঠিকানা সঞ্চয় করতে পারে। একইভাবে, পয়েন্টার ভেরিয়েবল এফপি কেবলমাত্র ভাসমান টাইপের ভেরিয়েবলের ঠিকানা সঞ্চয় করতে পারে। ভেরিয়েবলের টাইপ (বেস টাইপ নামেও পরিচিত) আইপি ইন্টের একটি পয়েন্টার এবং এফপি এর টাইপ ভাসমানের পয়েন্টার। টাইপ পয়েন্টার টু ইন্টের পয়েন্টার ভেরিয়েবলটি প্রতীকীভাবে (ইন্ট *) হিসাবে উপস্থাপিত হতে পারে। একইভাবে, টাইপ পয়েন্টার টু ফ্লোটের পয়েন্টার ভেরিয়েবল (ফ্লোট *) হিসাবে উপস্থাপন করা যেতে পারে

পয়েন্টার ভেরিয়েবল ঘোষণার পরে পরবর্তী পদক্ষেপটি এর জন্য কিছু বৈধ মেমরি ঠিকানা বরাদ্দ করা হয়। আপনাকে কোনও বৈধ মেমরি ঠিকানা বরাদ্দ না করে কখনও পয়েন্টার ভেরিয়েবল ব্যবহার করা উচিত নয়, কারণ ঘোষণার পরে এটিতে আবর্জনার মান রয়েছে এবং এটি মেমরির যে কোনও জায়গায় নির্দেশ করতে পারে। একটি অচিহ্নযুক্ত পয়েন্টার ব্যবহার একটি অনির্দেশ্য ফলাফল দিতে পারে। এটি এমনকি প্রোগ্রাম ক্রাশ হতে পারে।

int *ip, i = 10;
float *fp, f = 12.2;

ip = &i;
fp = &f;

উত্স: Thecguru হ'ল আমি কখনও খুঁজে পেয়েছি সহজতম কিন্তু বিস্তারিত ব্যাখ্যা।

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