পয়েন্টার ঘোষণায় নক্ষত্রের স্থান


95

আমি সম্প্রতি সিদ্ধান্ত নিয়েছি যে অবশেষে আমাকে কেবল সি / সি ++ শিখতে হবে, এবং এমন একটি জিনিস আছে যা আমি পয়েন্টারগুলি সম্পর্কে বা আরও স্পষ্টভাবে বুঝতে পারি না, তাদের সংজ্ঞা।

এই উদাহরণগুলি সম্পর্কে কীভাবে:

  1. int* test;
  2. int *test;
  3. int * test;
  4. int* test,test2;
  5. int *test,test2;
  6. int * test,test2;

এখন, আমার বোঝার জন্য, প্রথম তিনটি কেস সব একই কাজ করছে: টেস্ট কোনও ইনট নয়, তবে একটিতে পয়েন্টার।

উদাহরণগুলির দ্বিতীয় সেটটি আরও জটিল। ৪ এর ক্ষেত্রে, পরীক্ষা এবং টেস্ট 2 উভয়ই একটি পূর্বনির্ধারিত পয়েন্টার হবে, যেখানে 5 এর ক্ষেত্রে কেবল পরীক্ষাটি পয়েন্টার হয়, যেখানে টেস্ট 2 একটি "বাস্তব" অন্তর্নিহিত হয়। কেস? এর কী হবে? মামলা 5 হিসাবে একই?


10
সি / সি ++ শ্বেত স্পেসে অর্থ পরিবর্তন হয় না।
সুলতান

19
7. int*test;?
জিন কওন

4
+1 কারণ আমি কেবল 1 - 3 সম্পর্কে জিজ্ঞাসা করার চিন্তাভাবনা করেছি এই প্রশ্নটি পড়া আমাকে 4 - 6 সম্পর্কে এমন কিছু শিখিয়েছে যা আমি কখনই ভাবিনি।
ਵਿਸ਼ਾਲভাবে সুপিরিয়রম্যান

@ সুলতান এটি সময়ের 99% সত্য, তবে সবসময় নয়। আমার মাথার উপরের অংশে টেম্প্লেটেড ধরণের স্থান প্রয়োজনের প্রকারে টেম্প্লেটেড ধরণের ধরণ ছিল (প্রাক সি ++ 11)। ইন লিখিত করা হয়েছিল যাতে একটি ডান-শিফট হিসাবে গণ্য করা হবে না। Foo<Bar<char>>>>> >
আনোরজাকেন

4
@ অ্যানোরজাকেন আপনি ঠিক বলেছেন, এটি একটি পুরানো মন্তব্য। একাধিক পরিস্থিতি রয়েছে যখন কোনও স্থান অর্থ পরিবর্তিত হয়, উদাহরণস্বরূপ, ইনক্রিমেন্ট ++অপারেটরকে একটি স্পেস দ্বারা বিভক্ত করা যায় না, সনাক্তকারীকে একটি স্পেস দ্বারা বিভক্ত করা যায় না (এবং ফলাফলটি এখনও সংকলকটির জন্য আইনী হতে পারে তবে অনির্ধারিত রানটাইম আচরণের সাথে)। সি / সি ++ এর সিনট্যাক্সের জগাখিচুড়ি বিবেচনা করে সঠিক পরিস্থিতি নির্ধারণ করা খুব কঠিন।
সুলতান

উত্তর:


128

4, 5 এবং 6 একই জিনিস, কেবল পরীক্ষাটি পয়েন্টার। আপনি যদি দুটি পয়েন্টার চান তবে আপনার ব্যবহার করা উচিত:

int *test, *test2;

বা, আরও ভাল (সমস্ত কিছু পরিষ্কার করার জন্য):

int* test;
int* test2;

4
তাহলে কেস 4 আসলে একটি মৃত্যুর ফাঁদ? কোন স্পেসিফিকেশন বা আরও পড়া আছে যা ব্যাখ্যা করে যে ইনট * টেস্ট, টেস্ট 2 শুধুমাত্র প্রথম পরিবর্তনশীলকে পয়েন্টার করে তোলে?
মাইকেল স্টাম

8
@ মাইকেল স্টাম এটি সি ++ তাই আপনি কি সত্যিই ভাবেন যে কোনও যৌক্তিক ব্যাখ্যা আছে?
জো ফিলিপস 21

6
কে অ্যান্ড আর (সি প্রোগ্রামিং ল্যাঙ্গুয়েজ) পড়ুন Read এটি খুব স্পষ্টভাবে এই সমস্ত ব্যাখ্যা করে।
ফেরুক্সিও

8
4, 5 এবং 6 কেস "মৃত্যুর ফাঁদ" ps অনেকগুলি সি / সি ++ স্টাইলের গুরুদের প্রতি বিবৃতিতে কেবল একটি ঘোষণার পরামর্শ দেওয়ার কারণ এটি reason
মাইকেল বুড় 21

14
হোয়াইটস্পেস একটি সি সংকলক (প্রাক প্রসেসর উপেক্ষা করে) এর কাছে তুচ্ছ। সুতরাং যতই ফাঁকা স্থান এবং তার আশেপাশের জায়গাগুলির মধ্যে না থাকুক না কেন, এর ঠিক একই অর্থ রয়েছে has
পূর্বসূরী 21

45

তারকাচিহ্নের চারপাশে সাদা জায়গার কোনও তাত্পর্য নেই। তিনটিই একই জিনিস বোঝায়:

int* test;
int *test;
int * test;

" int *var1, var2" একটি দুষ্টু বাক্য গঠন যা কেবলমাত্র মানুষকে বিভ্রান্ত করার জন্যই বোঝানো হয় এবং এড়ানো উচিত। এটি প্রসারিত:

int *var1;
int var2;

16
ভুলবেন না int*test
মতিন উলহাক

4
তারকাচিহ্নের আগে বা পরে স্থানটি কেবল নান্দনিকতার বিষয়। তবে গুগল কোডিং স্ট্যান্ডার্ডটি int *test( google-styleguide.googlecode.com/svn/trunk/… ) এর সাথে চলে । কেবল সামঞ্জস্যপূর্ণ

@ সেবাস্তিয়ানআরশকা গুগল সি ++ স্টাইল গাইড স্পষ্টভাবে হয় নক্ষত্র স্থাপনের অনুমতি দেয়। আপনি এটি পড়ার পরে সম্ভবত এটি পরিবর্তন হয়েছে।
জারেড বেক

33

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


আমি জানি কিছুটা হলেও, তবে আমার যে জিনিসটি দরকারী মনে হয়েছে তা হল পিছনের দিকে ঘোষণাগুলি পড়া read

int* test;   // test is a pointer to an int

এটি খুব ভালভাবে কাজ করা শুরু করে, বিশেষত যখন আপনি কনস্ট পয়েন্টারগুলি ঘোষণা করতে শুরু করেন এবং এটি পয়েন্টারটি যে কনস্টেন্ট, এটিই পয়েন্টার কিনা বা এটি পয়েন্টারটি যে কনটেন্টটি ইঙ্গিত করছে তা নিশ্চিত হওয়া কঠিন।

int* const test; // test is a const pointer to an int

int const * test; // test is a pointer to a const int ... but many people write this as  
const int * test; // test is a pointer to an int that's const

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

দুর্ভাগ্যক্রমে আমার দু: সাহসিক কাজ থেকে শুরু করে বন্য পর্যন্ত আমি প্রচুর দুটি স্টাইলই দেখতে পাচ্ছি। আমার দলে আমরা এখন এমন এক শৈলীর সাথে ঝাঁকুনি-ফর্ম্যাট ব্যবহার করি যা আমরা সম্মত হয়েছি। এটি কমপক্ষে এর অর্থ হ'ল হোয়াইটস্পেস যেখানে চলে তার জন্য আমাদের টিম সমস্ত কোডের কোডের একই স্টাইল রয়েছে।
স্কট ল্যাংহাম

33

সি / সি ++ ঘোষণাগুলি পার্স করতে সহায়তা করতে "ক্লকওয়াইজ স্পাইরাল বিধি" ব্যবহার করুন ;

অনুসরণ করার জন্য তিনটি সহজ পদক্ষেপ রয়েছে:

  1. অজানা উপাদান দিয়ে শুরু করে, একটি সর্পিল / ঘড়ির কাঁটার দিকে এগিয়ে যান; যখন নিম্নলিখিত উপাদানগুলির মুখোমুখি হয় তখন তাদের সাথে সম্পর্কিত ইংরেজি বিবৃতি দিয়ে প্রতিস্থাপন করুন:

    [X]বা []: অ্যারের এক্স আকার ... বা অ্যারের অপরিবর্তিত আকার ...

    (type1, type2): ফাংশন পাসিং টাইপ 1 এবং টাইপ 2 ফিরে ...

    *: পয়েন্টার (গুলি) থেকে ...

  2. সমস্ত টোকেন coveredেকে না দেওয়া পর্যন্ত এটি সর্পিল / ঘড়ির কাঁটার দিকে চালিয়ে যান।
  3. সর্বদা প্রথম বন্ধনে যেকোন কিছু সমাধান করুন!

এছাড়াও, ঘোষণাগুলি যখন সম্ভব হয় তখন পৃথক বিবৃতিতে হওয়া উচিত (যা বেশিরভাগ সময় সত্য)।


4
এটি দেখতে ভয়ঙ্কর এবং বেশ ভয়াবহ, দুঃখের সাথে বলতে চাই।
জো ফিলিপস

7
এটি করে তবে কিছু জটিল জটিল নির্মাণের পক্ষে এটি বেশ ভাল ব্যাখ্যা বলে মনে হচ্ছে
মাইকেল স্টাম

@ d03boy: কোনও প্রশ্ন নেই - সি / সি ++ ঘোষণা একটি দুঃস্বপ্ন হতে পারে।
মাইকেল বুড়

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

আমি এটি "ডান-বাম-ডান" নিয়ম হিসাবে শিখেছি। সি ++ ভাবেন লোকেরা প্রায়শই সমস্ত ধরণের তথ্য বাম দিকে থাকে, যা int* x;প্রচলিত int *x;শৈলীর পরিবর্তে শৈলীতে নিয়ে যায়। অবশ্যই, স্পেসিংটি সংকলকটির সাথে কিছু যায় আসে না, তবে এটি মানুষের উপর প্রভাব ফেলে। প্রকৃত বাক্য গঠন অস্বীকার স্টাইলের নিয়মের দিকে নিয়ে যায় যা পাঠকদের বিরক্ত করতে ও বিভ্রান্ত করতে পারে।
অ্যাড্রিয়ান ম্যাকার্থি

12

অন্যরা যেমন উল্লেখ করেছে, 4, 5 এবং 6 একই রকম। প্রায়শই, লোকেরা এই উদাহরণগুলি ব্যবহার করে যুক্তিটি তৈরি করে যে *প্রকারটির পরিবর্তে ভেরিয়েবলের সাথে সম্পর্কিত। এটি শৈলীর ইস্যু করার সময়, আপনার এইভাবে চিন্তা করা এবং এটি লেখার উচিত কিনা তা নিয়ে কিছুটা বিতর্ক রয়েছে:

int* x; // "x is a pointer to int"

বা এইভাবে:

int *x; // "*x is an int"

এফডাব্লুআইডাব্লু আমি প্রথম শিবিরে আছি, তবে অন্যরা দ্বিতীয় ফর্মটির পক্ষে যুক্তি তৈরি করার কারণটি হ'ল এটি (বেশিরভাগ ক্ষেত্রে) এই বিশেষ সমস্যাটি সমাধান করে:

int* x,y; // "x is a pointer to int, y is an int"

যা সম্ভবত বিভ্রান্তিকর; পরিবর্তে আপনি হয় লিখতে হবে

int *x,y; // it's a little clearer what is going on here

অথবা আপনি যদি সত্যিই দুটি পয়েন্টার চান,

int *x, *y; // two pointers

ব্যক্তিগতভাবে, আমি বলছি এটি প্রতি লাইনে একটি পরিবর্তনশীল রাখুন, তবে আপনি কোন স্টাইলটি পছন্দ করেন তা বিবেচ্য নয়।


6
এই বোগাস, আপনি কি কল int *MyFunc(void)? একটি *MyFuncএকটি ফাংশন একটি ফিরে int? না স্পষ্টতই আমাদের লেখা উচিত int* MyFunc(void), এবং বলা MyFuncএকটি ফাংশন ফিরে int*। সুতরাং আমার কাছে এটি পরিষ্কার, সি এবং সি ++ ব্যাকরণ পার্সিংয়ের নিয়মগুলি পরিবর্তনশীল ঘোষণার জন্য কেবল ভুল। সম্পূর্ণ কমা ক্রমের জন্য তাদের ভাগ করা প্রকারের অংশ হিসাবে পয়েন্টার যোগ্যতা অন্তর্ভুক্ত করা উচিত ছিল।
v.oddou

4
তবে *MyFunc() এটি একটি int। সি সিনট্যাক্সের সাথে সমস্যাটি প্রিফিক্স এবং পোস্টফিক্স সিনট্যাক্সের মিশ্রণ করছে - যদি কেবল পোস্টফিক্স ব্যবহার করা হত তবে কোনও বিভ্রান্তি হবে না।
অ্যান্টি হাপালা

4
প্রথম শিবিরটি ভাষার সিনট্যাক্সের সাথে লড়াই করে এবং এর মতো বিভ্রান্তিকর কনস্ট্রাক্টের দিকে নিয়ে যায় int const* x;যা আমি বিভ্রান্তিমূলক বলে মনে করি a * x+b * y
অ্যাড্রিয়ান ম্যাকার্থি


5

4, 5 এবং 6 testএ সর্বদা পয়েন্টার এবং test2কোনও পয়েন্টার নয়। সাদা স্থান (প্রায়) সি ++ তে কখনও তাৎপর্যপূর্ণ নয়।


3

সি এর যুক্তি হ'ল আপনি যেভাবে ভেরিয়েবলগুলি ব্যবহার করেন তা ঘোষণা করে। উদাহরণ স্বরূপ

char *a[100];

যে *a[42]একটি হবে বলে char। এবং a[42]একটি চর পয়েন্টার। এবং এইভাবে aচর পয়েন্টারগুলির একটি অ্যারে।

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


তবুও লেখার char* a[100]; এছাড়াও deduces যে *a[42];একটি হতে হবে charএবং a[42];একটি গৃহস্থালি পয়েন্টার।
yyny

ঠিক আছে, আমরা সকলেই একই সিদ্ধান্তে অনুমান করি, কেবল ক্রমটি ভিন্ন হয়।
মিশেল বিলাউড

উক্তি: "বলেছে যে * ক [42] একটি চর হবে এবং একটি [42] একটি চর পয়েন্টার"। আপনি কি নিশ্চিত যে এটি অন্যভাবে নয়?
ডিএলক

আপনি যদি অন্যভাবে পছন্দ করেন তবে বলুন a[42]যে একটি charপয়েন্টার, এবং *a[42]একটি গৃহস্থালি।
মিশেল বিলাউড

3

আমার মতে, উত্তর পরিস্থিতিটির উপর নির্ভর করে উভয়ই। সাধারণত, আইএমও, টাইপের পরিবর্তে পয়েন্টার নামের পাশে তারকাচিহ্ন স্থাপন করা ভাল। যেমন তুলনা করুন:

int *pointer1, *pointer2; // Fully consistent, two pointers
int* pointer1, pointer2;  // Inconsistent -- because only the first one is a pointer, the second one is an int variable
// The second case is unexpected, and thus prone to errors

দ্বিতীয় মামলাটি কেন বেমানান? কারণ যেমন int x,y;একই ধরণের দুটি ভেরিয়েবল ঘোষণা করে তবে প্রকারটি কেবলমাত্র ঘোষণায় একবার উল্লেখ করা হয়। এটি নজির এবং প্রত্যাশিত আচরণ তৈরি করে। এবং এর int* pointer1, pointer2;সাথে অসঙ্গতিপূর্ণ কারণ এটি pointer1পয়েন্টার হিসাবে ঘোষণা করে তবে pointer2একটি পূর্ণসংখ্যার পরিবর্তনশীল। পরিষ্কারভাবে ত্রুটিগুলির প্রবণ এবং এইভাবে, এড়ানো উচিত (টাইপের পরিবর্তে পয়েন্টার নামের পাশে নক্ষত্রটি রেখে)।

তবে কিছু ব্যতিক্রম রয়েছে যেখানে অযাচিত ফলাফল না পেয়ে আপনি কোনও অজানা নামের (এবং এটি যেখানে রেখেছেন সেখানে গুরুত্বপূর্ণ) এটি স্থাপন করতে সক্ষম নাও হতে পারে - উদাহরণস্বরূপ:

MyClass *volatile MyObjName

void test (const char *const p) // const value pointed to by a const pointer

শেষ অবধি, কিছু ক্ষেত্রে, টাইপ নামের পাশে অষ্টকটি স্থাপন করা যুক্তিযুক্তভাবে পরিষ্কার হতে পারে যেমন:

void* ClassName::getItemPtr () {return &item;} // Clear at first sight


2

আমি বলব যে প্রাথমিক কনভেনশনটি ছিল তারাটিকে পয়েন্টার নামের পাশে (ঘোষণার ডান দিকে) লাগানো

  • মধ্যে C প্রোগ্রামিং ভাষা ডেনিস এম রিচি দ্বারা তারার ঘোষণা ডান দিকে আছে।

  • লিনাক্স উত্স কোডটি https://github.com/torvalds/linux/blob/master/init/main.c এ দেখে আমরা দেখতে পাচ্ছি যে তারাটিও ডানদিকে রয়েছে।

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


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

1

পয়েন্টারটি টাইপের পরিবর্তক। নক্ষত্রটি কীভাবে টাইপটি সংশোধন করে তা আরও ভালভাবে বুঝতে তাদের ডান থেকে বামে পড়া ভাল। 'int *' "পয়েন্টার টু ইনট 'হিসাবে পড়া যায় can একাধিক ঘোষণায় আপনাকে অবশ্যই উল্লেখ করতে হবে যে প্রতিটি ভেরিয়েবল একটি পয়েন্টার বা এটি একটি আদর্শ ভেরিয়েবল হিসাবে তৈরি হবে।

1,2 এবং 3) পরীক্ষাটি টাইপ হয় (int *)। হোয়াইটস্পেসে কিছু যায় আসে না।

4,5 এবং 6) পরীক্ষাটি টাইপ (ইনট *)। টেস্ট 2 টাইপ ইন্টের হয়। আবার হোয়াইটস্পেস অপ্রয়োজনীয়।


1

এই ধাঁধা তিনটি টুকরা আছে।

প্রথম টুকরাটি হ'ল সি এবং সি ++ এর শ্বেত স্পেসটি সংলগ্ন টোকেনগুলি পৃথক করার বাইরে সাধারণত তাত্পর্যপূর্ণ নয় যা অন্যথায় অবিচ্ছেদ্য।

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

inttest;

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

int test;

*চরিত্র কোন শনাক্তকারীর অংশ নয়; এটি নিজস্বভাবে একটি পৃথক টোকেন (বিরামচিহ্ন)। সুতরাং আপনি যদি লিখুন

int*test;

কম্পাইলার 4 পৃথক টোকেন উদ্ধার - int, *, test, এবং ;। সুতরাং, পয়েন্টার ঘোষণাপত্রগুলিতে সাদা স্থান স্পষ্টতই গুরুত্বপূর্ণ নয় এবং সবগুলিই

int *test;
int* test;
int*test;
int     *     test;

একইভাবে ব্যাখ্যা করা হয়।


ধাঁধার দ্বিতীয় টুকরোটি হ'ল ঘোষণা কীভাবে বাস্তবে সি এবং সি ++ 1 তে কাজ করে । ঘোষণাগুলি দুটি প্রধান টুকরো টুকরো টুকরো হয়ে গেছে - ঘোষণা স্পেসিফায়ারগুলির একটি ক্রম (স্টোরেজ ক্লাস স্পেসিফায়ার, টাইপ স্পেসিফায়ার, টাইপ কোয়ালিফায়ার ইত্যাদি) এর পরে (সম্ভবত আরম্ভীকৃত) ঘোষণাকারীদের কমা-বিচ্ছিন্ন তালিকা তৈরি করা হবে । প্রজ্ঞাপনে

unsigned long int a[10]={0}, *p=NULL, f(void);

ঘোষণা নির্দিষ্টকরী হয় unsigned long intএবং declarators হয় a[10]={0}, *p=NULLএবং f(void)। Declarator প্রবর্তন জিনিস নাম ঘোষিত হওয়ার ( a, p, এবং f) যে জিনিস এর অ্যারে-Ness, পয়েন্টার-অন্তরীপ, এবং ফাংশন-অন্তরীপ সম্পর্কে তথ্য সহ। একটি ঘোষণাকারীর একটি সম্পর্কিত সূচক থাকতে পারে।

প্রকারটি aহ'ল "10-উপাদানের অ্যারে unsigned long int"। এই ধরণেরটি সম্পূর্ণরূপে ঘোষণাপত্রের স্পেসিফায়ার এবং ডিক্লেয়ারের সংমিশ্রণ দ্বারা নির্দিষ্ট করা হয় এবং প্রাথমিক মানটি আরম্ভকারী সহ নির্দিষ্ট করা হয় ={0}। একইভাবে, প্রকারটি p"পয়েন্টার টু unsigned long int", এবং আবার সেই ধরণেরটি ঘোষণাপত্রের স্পেসিফায়ার এবং ডিক্লেয়ারের সংমিশ্রণ দ্বারা নির্দিষ্ট করা হয় এবং এতে আরম্ভ হয় NULL। এবং প্রকারভেদ একই যুক্তি দ্বারা f"ফাংশন রিটার্নিং unsigned long int"।

এটি কী - কোনও "ফাংশন-রিটার্নিং" টাইপ স্পেসিফার নেই ঠিক তেমন কোনও "পয়েন্টার-টু" টাইপ স্পেসিফায়ার নেই , ঠিক তেমন কোনও "অ্যারে-অফ" টাইপ স্পেসিফায়ার নেই। আমরা আরে হিসাবে ঘোষণা করতে পারি না

int[10] a;

কারণ []অপারেটরের অপারেন্ড a, না int। একইভাবে ঘোষণাপত্রে

int* p;

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

সুতরাং, আপনি যদি লিখুন

int* p, q;

অপরেন্ড *হয় p, তাই এটি হিসাবে ব্যাখ্যা করা হবে

int (*p), q;

সুতরাং, সব

int *test1, test2;
int* test1, test2;
int * test1, test2;

একই জিনিসটি করুন - তিনটি ক্ষেত্রেই এটির test1অপারেন্ড *এবং সুতরাং "পয়েন্টার টু int" test2টাইপ রয়েছে , যখন টাইপ রয়েছে int

ঘোষকগণ যথেচ্ছ জটিল হয়ে উঠতে পারেন। আপনার পয়েন্টারের অ্যারে থাকতে পারে:

T *a[N];

অ্যারেগুলিতে আপনার পয়েন্টার থাকতে পারে:

T (*a)[N];

আপনি পয়েন্টার রিটার্ন ফাংশন থাকতে পারে:

T *f(void);

ফাংশনগুলিতে আপনার পয়েন্টার থাকতে পারে:

T (*f)(void);

ফাংশনে আপনার পয়েন্টারের অ্যারে থাকতে পারে:

T (*a[N])(void);

অ্যারেগুলিতে পয়েন্টার ফেরত দেওয়ার জন্য আপনার ফাংশন থাকতে পারে:

T (*f(void))[N];

পয়েন্টারগুলিতে ফাংশনগুলিতে পয়েন্টারগুলির অ্যারেগুলিতে রিটার্নিং ফাংশন থাকতে পারে T:

T *(*(*f(void))[N])(void); // yes, it's eye-stabby.  Welcome to C and C++.

এবং তারপরে আপনার কাছে রয়েছে signal:

void (*signal(int, void (*)(int)))(int);

যা পড়ছে

       signal                             -- signal
       signal(                 )          -- is a function taking
       signal(                 )          --   unnamed parameter
       signal(int              )          --   is an int
       signal(int,             )          --   unnamed parameter
       signal(int,      (*)    )          --   is a pointer to
       signal(int,      (*)(  ))          --     a function taking
       signal(int,      (*)(  ))          --       unnamed parameter
       signal(int,      (*)(int))         --       is an int
       signal(int, void (*)(int))         --     returning void
     (*signal(int, void (*)(int)))        -- returning a pointer to
     (*signal(int, void (*)(int)))(   )   --   a function taking
     (*signal(int, void (*)(int)))(   )   --     unnamed parameter
     (*signal(int, void (*)(int)))(int)   --     is an int
void (*signal(int, void (*)(int)))(int);  --   returning void
    

এবং এটি সবেমাত্র যা সম্ভব তার পৃষ্ঠকে স্ক্র্যাচ করে। তবে লক্ষ্য করুন যে অ্যারে-নেস, পয়েন্টার-নেস এবং ফাংশন-নেস সর্বদা ঘোষকের অংশ, না টাইপ স্পেসিফায়ার।

নজর রাখার জন্য একটি জিনিস - constপয়েন্টার টাইপ এবং পয়েন্ট-টু টাইপ উভয়কে সংশোধন করতে পারে:

const int *p;  
int const *p;

উপরের উভয়ই pএকটি const intবস্তুর পয়েন্টার হিসাবে ঘোষণা করে । আপনি pএটির জন্য একটি নতুন মান লিখতে পারেন এটি কোনও ভিন্ন অবজেক্টের দিকে নির্দেশ করতে:

const int x = 1;
const int y = 2;

const int *p = &x;
p = &y;

তবে আপনি পয়েন্ট-টু অবজেক্টে লিখতে পারবেন না:

*p = 3; // constraint violation, the pointed-to object is const

যাহোক,

int * const p;

অ-কনস্ট্যান্টকে পয়েন্টার pহিসাবে ঘোষণা করে ; আপনি জিনিসটি নির্দেশ করতে পারেনconstintp

int x = 1;
int y = 2;
int * const p = &x;

*p = 3;

তবে আপনি pকোনও ভিন্ন অবজেক্টের দিকে নির্দেশ করতে পারবেন না :

p = &y; // constraint violation, p is const

যা আমাদের ধাঁধার তৃতীয় অংশে নিয়ে আসে - কেন ঘোষণাগুলি এইভাবে গঠন করা হয়।

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

printf( "%d", *ap[i] );

অভিব্যক্তি *ap[i] টাইপ হয়েছে int; সুতরাং, ঘোষণা apহিসাবে লেখা হয়

int *ap[N]; // ap is an array of pointer to int, fully specified by the combination
            // of the type specifier and declarator

ঘোষণাকারীর *ap[N]মত প্রকাশের মতো কাঠামো থাকে *ap[i]। অপারেটার *এবং []ঘোষণা করে যে তারা একটি অভিব্যক্তি না একই এইরকম আচরণ - []ইউনারী বেশী প্রাধান্য রয়েছে *, তাই এর প্রতীক *হল ap[N](এটা যেমন পার্স এর *(ap[N]))।

অন্য একটি উদাহরণ হিসাবে, ধরুন আমাদের intনামের একটি অ্যারের কাছে একটি পয়েন্টার রয়েছে paএবং আমরা i'তম উপাদানটির মানটি অ্যাক্সেস করতে চাই । আমরা যে হিসাবে লিখতে চাই

printf( "%d", (*pa)[i] );

মত প্রকাশের টাইপ (*pa)[i]হয় int, তাই ঘোষণা হিসেবে লেখা হয়

int (*pa)[N];

আবার, প্রাধান্য এবং সাহসিকতার একই নিয়ম প্রযোজ্য। এই ক্ষেত্রে, আমরা এর i'তম উপাদানটির অবলম্বন করতে চাই না pa, আমরা iকীসের দিকে pa ইঙ্গিত করব তার ' তম উপাদানটি অ্যাক্সেস করতে চাই , সুতরাং আমাদের *অপারেটরটিকে স্পষ্টভাবে গ্রুপিং করতে হবে pa

*, []এবং ()অপারেটরদের সমস্ত অংশ অভিব্যক্তি কোডে, তাই তারা সমস্ত অংশ declarator ঘোষণায়। ঘোষণাকারী আপনাকে কীভাবে একটি অভিব্যক্তিতে অবজেক্টটি ব্যবহার করতে হয় তা বলে। যদি আপনার মতো কোনও ঘোষণা থাকে int *p;, তবে এটি আপনাকে বলে যে *pআপনার কোডে প্রকাশটি একটি intমান অর্জন করবে। এক্সটেনশন দ্বারা, এটা আপনাকে বলে যে অভিব্যক্তি p"থেকে পয়েন্টার ধরনের একটি মান উৎপাদ int", বা int *


সুতরাং, castালাই এবং sizeofএক্সপ্রেশনগুলির মতো জিনিসগুলির বিষয়ে কী , যেখানে আমরা এই জাতীয় জিনিস (int *)বা এর মতো জিনিস ব্যবহার sizeof (int [10])করি? আমি কীভাবে এমন কিছু পড়ি

void foo( int *, int (*)[10] );

কোনও ঘোষক নেই, *এবং []অপারেটররা কি সরাসরি টাইপটি পরিবর্তন করছে?

ঠিক আছে, না - খালি শনাক্তকারী (একটি বিমূর্ত ঘোষণাকারী হিসাবে পরিচিত ) সহ এখনও একটি ঘোষক রয়েছে । আমরা যদি প্রতীক λ সহ একটি খালি আইডেন্টিফায়ার প্রতিনিধিত্ব, তাহলে আমরা সেগুলো পড়তে পারেন যেমন (int *λ), sizeof (int λ[10])এবং

void foo( int *λ, int (*λ)[10] );

এবং তারা অন্য কোনও ঘোষণার মতোই আচরণ করে। int *[10]10 টি পয়েন্টারের অ্যারে উপস্থাপন করে, যখন int (*)[10]একটি অ্যারেতে একটি পয়েন্টার উপস্থাপন করে।


এবং এখন এই উত্তর মতামত অংশ। আমি সাধারণ পয়েন্টার হিসাবে ঘোষণা করার সি ++ কনভেনশন পছন্দ করি না

T* p;

এবং নিম্নলিখিত কারণে এটি খারাপ অভ্যাস বিবেচনা করুন :

  1. এটি সিনট্যাক্সের সাথে সামঞ্জস্যপূর্ণ নয়;
  2. এটি বিভ্রান্তির পরিচয় দেয় (এই প্রশ্নের প্রমাণ হিসাবে, এই প্রশ্নের সমস্ত সদৃশ, এর অর্থ সম্পর্কে প্রশ্নগুলি, সেই সমস্ত প্রশ্নের T* p, q;নকল ইত্যাদি);
  3. এটি অভ্যন্তরীণভাবে সামঞ্জস্যপূর্ণ নয় - পয়েন্টারগুলির একটি অ্যারে হিসাবে T* a[N]ব্যবহারের সাথে অসম্পূর্ণ হিসাবে ঘোষণা করা (আপনি লেখার অভ্যাস না থাকলে * a[i]);
  4. এটি পয়েন্টার-থেকে-অ্যারে বা পয়েন্টার-টু-ফাংশন প্রকারগুলিতে প্রয়োগ করা যাবে না (আপনি যদি টাইপডেফ তৈরি না করেন তবে আপনি T* pকনভেনশনটি পরিষ্কারভাবে প্রয়োগ করতে পারেন , যা ... না );
  5. এটি করার কারণ - "এটি বস্তুর পয়েন্টার-নেসে জোর দেয়" - উত্সাহিত। এটি অ্যারে বা ফাংশন ধরণের ক্ষেত্রে প্রয়োগ করা যায় না এবং আমি মনে করি যে এই গুণগুলি জোর দেওয়া ঠিক ততটাই গুরুত্বপূর্ণ।

শেষ পর্যন্ত, এটি কেবল দুটি ভাষার টাইপ সিস্টেমগুলি কীভাবে কাজ করে সে সম্পর্কে বিভ্রান্ত চিন্তার ইঙ্গিত দেয়।

আইটেমগুলি আলাদাভাবে ঘোষণার উপযুক্ত কারণ রয়েছে; একটি খারাপ অনুশীলন ( T* p, q;) এর মধ্যে কাজ করা তাদের মধ্যে একটি নয়। আপনি যদি আপনার ডিক্লেটারকে সঠিকভাবে লিখেন ( T *p, q;) তবে আপনার বিভ্রান্তির সম্ভাবনা কম।

আমি আপনার সমস্ত সরল forলুপগুলি ইচ্ছাকৃতভাবে লেখার অনুরূপ হিসাবে বিবেচনা করি

i = 0;
for( ; i < N; ) 
{ 
  ... 
  i++ 
}

কৃত্রিমভাবে বৈধ, তবে বিভ্রান্তিকর, এবং উদ্দেশ্যটি ভুল ব্যাখ্যা করা হতে পারে। যাইহোক, T* p;কনভেনশনটি সি ++ সম্প্রদায়ে আবদ্ধ এবং আমি এটি নিজের সি ++ কোডে ব্যবহার করি কারণ কোড বেস জুড়ে ধারাবাহিকতা একটি ভাল জিনিস, তবে আমি যতবার করি ততবারে এটি আমাকে চুলকায়।


  1. আমি সি পরিভাষা ব্যবহার করব - সি ++ পরিভাষাটি কিছুটা আলাদা তবে ধারণাগুলি মূলত একই রকম।

-3

থাম্বের একটি ভাল নিয়ম, প্রচুর লোকেরা এই ধারণাগুলি উপলব্ধি করে বলে মনে হচ্ছে: সি ++ তে প্রচুর অর্থবোধক অর্থ কীওয়ার্ড বা শনাক্তকারীদের বাম-বাঁধাই দ্বারা উদ্ভূত।

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

int const bla;

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


4
এটি প্রশ্নের উত্তর দেয় না। সবচেয়ে খারাপ, যদি আমরা এটি থেকে কোনও উত্তর অনুমান করার চেষ্টা করি, তবে এটি তারের বামে থাকা টাইপের সাথে সংক্ষিপ্ত বাঁধনকে বোঝায় যা অন্যরা যেমন বলেছে, এটি মিথ্যা। এটি তার ডানদিকে একক পরিবর্তনশীল নামের সাথে আবদ্ধ হয়।
আন্ডারস্কোর_২
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.