কেন পরিবর্তনের পরিবর্তে পরিবর্তকের নামের পরিবর্তে তারকাচিহ্ন?


187

বেশিরভাগ সি প্রোগ্রামাররা কেন এর মতো ভেরিয়েবলের নাম রাখে:

int *myVariable;

এর চেয়ে বরং:

int* myVariable;

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


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

উত্তর:


250

এগুলি হুবহু সমতুল্য। তবে, ইন

int *myVariable, myVariable2;

এটি সুস্পষ্ট myVariable আছে টাইপ মনে হয় int- * , যখন myVariable2 টাইপ হয়েছে int- এ । ভিতরে

int* myVariable, myVariable2;

এটি উভয়ই টাইপ ইন্ট * এর মতো বলে সুস্পষ্ট বলে মনে হতে পারে তবে myVariable2টাইপ ইন্টের মতো এটি সঠিক নয় ।

অতএব, প্রথম প্রোগ্রামিং শৈলী আরও স্বজ্ঞাত।


135
সম্ভবত তবে আমি এক ঘোষণায় মিশ্রিত ও প্রকারের মিশ্রণ করব না।
ববিশ্যাফটয়ে

15
নিবন্ধন করুন এমনকি এখানে প্রতিটি যুক্তি পড়ার পরেও আমি int* someVarব্যক্তিগত প্রকল্পগুলির সাথে যুক্ত আছি । এটি আরও বোধগম্য হয়।
অ্যালিসা হ্যারল্ডসেন

30
@ কুপিয়াকোস আপনি "ঘোষণাপত্র অনুসরণ করুন অনুসরণ" এর উপর ভিত্তি করে সি এর ঘোষণামূলক বাক্য গঠন না শিখলে এটি আরও বেশি অর্থবোধ করে। ঘোষণাগুলি ঠিক একই সিনট্যাক্স ব্যবহার করে যা একই টাইপযুক্ত ভেরিয়েবলগুলি ব্যবহার করে। যখন আপনি ints একটি অ্যারের ঘোষণা, এটা মত দেখাচ্ছে না: int[10] x। এটি কেবল সি এর বাক্য গঠন নয়। ব্যাকরণটি স্পষ্টভাবে পার্স করে:: int (*x)এবং হিসাবে নয় (int *) x, তাই বামদিকে তারকাচিহ্ন স্থাপন করা কেবল বিভ্রান্তিকর এবং সি ডিক্লেয়ারেশন সিনট্যাক্সের একটি ভুল বোঝাবুঝির উপর ভিত্তি করে।
পিকার

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

6
এই কারণেই আমি প্রতি পয়েন্টার ঘোষণায় প্রতি পরিবর্তনশীলকে আটকে থাকি। আপনি যদি এর int* myVariable; int myVariable2;পরিবর্তে করেন তবে একেবারেই কোনও বিভ্রান্তি নেই ।
প্যাট্রিক রবার্টস

122

আপনি যদি এটি অন্য কোনও উপায়ে দেখে থাকেন তবে তা *myVariableটাইপের int, যা কিছুটা বোধগম্য।


6
এটি আমার প্রিয় ব্যাখ্যা, এবং ভালভাবে কাজ করে কারণ এটি সাধারণভাবে সি এর ঘোষণাপূর্ণ প্রশ্নগুলি ব্যাখ্যা করে - এমনকি জঘন্য এবং ঘৃণ্য ফাংশন পয়েন্টার সিনট্যাক্স।
বেনিয়ামিন পোল্যাক 19

12
এটি এক ধরণের ঝরঝরে, যেহেতু আপনি কল্পনা করতে পারেন যে কোনও আসল পয়েন্টার প্রকার নেই। কেবলমাত্র ভেরিয়েবলগুলি রয়েছে যখন যথাযথভাবে রেফারেন্স দেওয়া হয় বা ডিরিফারেন্স করা হয় তবে আপনাকে আদিম ধরণের একটি দেয়।
বায়োজিঙ্ক

1
প্রকৃতপক্ষে, '* মাইভেরিয়েবল' টাইপ নুল হতে পারে L বিষয়গুলি আরও খারাপ করার জন্য এটি কেবল একটি এলোমেলো মেমরি মেমরি অবস্থান হতে পারে।
Qonf

4
কনফ: নুল একটি প্রকার নয়। myVariableNULL হতে পারে, *myVariableএক্ষেত্রে সেগমেন্টেশন ত্রুটি সৃষ্টি করে তবে কোনও প্রকার NULL নেই।
ড্যানিয়েল রোথলিসবার্গার

28
এই পয়েন্টটি এ জাতীয় প্রসঙ্গে বিভ্রান্তিকর হতে পারে: int x = 5; int *pointer = &x;কারণ এটি সুপারিশ করে যে আমরা *pointerকিছুটা মান নির্ধারণ করি না, pointerনিজেই।
rafalcieslak

40

কারণ সেই লাইনের * প্রকারের চেয়ে চলকটির সাথে আরও ঘনিষ্ঠভাবে আবদ্ধ হয়:

int* varA, varB; // This is misleading

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

int* varA;
int varB;

স্পষ্ট কোড এবং সংক্ষিপ্ত কোডের মধ্যে ভারসাম্য রোধ করা শক্ত - এক ডজন অপ্রয়োজনীয় লাইন এর লাইনও int a;ভাল নয়। তবুও, আমি প্রতি লাইনে একটি ঘোষণায় ডিফল্ট এবং পরে কোড সংমিশ্রণ করার বিষয়ে চিন্তা করি।


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

1
"* টাইপের চেয়ে চলকটির সাথে আরও ঘনিষ্ঠভাবে আবদ্ধ হয়" এটি একটি নিষ্পাপ আর্গুমেন্ট। বিবেচনা করুন int *const a, b;। * "বাঁধাই" কোথায়? প্রকারটি aহ'ল int* const, সুতরাং আপনি কীভাবে বলতে পারেন যে * যখন এটি টাইপের অংশ হয় তখন এটি ভেরিয়েবলের হয়?
লন্ডিন

1
প্রশ্নের সুনির্দিষ্ট, বা সমস্ত কেস কভার করে: একটি বেছে নিন। আমি একটি নোট করব, তবে এটি আমার শেষ পরামর্শের জন্য আরেকটি ভাল যুক্তি: প্রতি লাইনে একটি ঘোষণার ফলে এই গোলযোগের সুযোগ হ্রাস পায়।
ওজরাক

36

এখনও অবধি এখানে কেউ কিছু উল্লেখ করেনি তা হ'ল এই নক্ষত্রটি আসলে সি এর " ডিরিফারেন্স অপারেটর " is

*a = 10;

উপরের লাইনটির অর্থ এই নয় যে আমি বরাদ্দ 10করতে চাই a, এর অর্থ 10মেমরির অবস্থান যা নির্দিষ্ট করে তা আমি নির্ধারণ করতে চাই a। আর কাউকে লিখতে দেখিনি

* a = 10;

তোমার আছে? সুতরাং ডেরেফারেন্স অপারেটর প্রায় সবসময় একটি স্থান ছাড়া লেখা হয়। এটি সম্ভবত এটি একাধিক লাইনে বিভক্ত একটি গুণ থেকে আলাদা করতে পারে:

x = a * b * c * d
  * e * f * g;

এখানে *eবিভ্রান্তিকর হবে, তাই না?

ঠিক আছে, এখন নীচের লাইনের আসলে কী বোঝায়:

int *a;

বেশিরভাগ লোক বলতেন:

এর অর্থ হ'ল এটি aএকটি intমানের পয়েন্টার ।

এটি প্রযুক্তিগতভাবে সঠিক, বেশিরভাগ লোকেরা এটি দেখতে / পড়তে পছন্দ করে এবং এটি আধুনিক সি স্ট্যান্ডার্ডগুলি কীভাবে এটি সংজ্ঞায়িত করবে (নোট করুন যে ভাষা সি নিজেই সমস্ত এএনএসআই এবং আইএসও মানকে পূর্বাভাস দেয়)। তবে এটি দেখার একমাত্র উপায় এটি নয়। আপনি এই লাইনটি নিম্নরূপ পড়তে পারেন:

এর dereferencesd মান aটাইপ হয় int

সুতরাং প্রকৃতপক্ষে এই ঘোষণাপত্রে নক্ষত্রটিকে একটি অবৈধ অপারেটর হিসাবেও দেখা যেতে পারে, যা এর স্থান নির্ধারণের ব্যাখ্যাও দেয়। এবং এটি aহ'ল একটি পয়েন্টারটি আসলেই ঘোষিত হয় না, এটি প্রকৃতপক্ষে ঘোষিত হয় যে আপনি কেবলমাত্র অবলম্বন করতে পারেন কেবলমাত্র পয়েন্টার।

সি স্ট্যান্ডার্ড *অপারেটরের কাছে কেবল দুটি অর্থ সংজ্ঞা দেয় :

  • ইন্ডিয়ারেশন অপারেটর
  • গুণক অপারেটর

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


6
এখানে আরও একটি উত্তর লেখার হাত থেকে বাঁচানোর জন্য ধন্যবাদ। বিটিডব্লিউ আমি সাধারণত int a, *b, (*c)();"নীচের বিষয়গুলি যেমন ঘোষণা করুন int: অবজেক্ট a, অবজেক্টটি ইশারা করে bএবং অবজেক্টটি ফাংশন দ্বারা নির্দেশিত c" দ্বারা এমন কিছু হিসাবে পড়ি ।
অ্যান্টি হাপালা

1
*মধ্যে int *a;একটি অপারেটর নয়, এবং এটি dereferencing করা হয় না a(যা এমনকি এখনো সংজ্ঞায়িত করা হয় না)
এম এম

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

1
@MM 6.7.6.1 শুধুমাত্র উদাহরণ দ্বারা ঘোষণা দেখায় ঠিক মত আমি বললাম, এটা কোন দেয় অর্থ থেকে *(এটা না, মোট অভিব্যক্তি একমাত্র একটি অর্থ দেয় *অভিব্যক্তি মধ্যে!)। এটি বলে যে "int a;" একটি পয়েন্টার, যা এটা আছে, অন্যথায় না বলে দাবি করেন, কিন্তু একটি অর্থ দেওয়া ছাড়া ঘোষণা *, যেমন * এর dereferenced মান এটা পড়া aকোন int , যে একই তথ্যসংক্রান্ত অর্থ এখনও সম্পূর্ণভাবে বৈধ। কিছুই নয়, 6..7..6.১ তে লিখিত কিছু কিছুই এই বক্তব্যের বিরোধিতা করবে না।
মক্কি

2
কোনও "সম্পূর্ণ অভিব্যক্তি" নেই। int *a;একটি ঘোষণা, একটি অভিব্যক্তি নয়। aদ্বারা dereferences হয় না int *a;aএমনকি *প্রক্রিয়াটি হচ্ছে পয়েন্টে এখনও উপস্থিত নেই । আপনি কি মনে করেন যে int *a = NULL;এটি একটি বাগ কারণ এটি একটি নাল পয়েন্টারকে অবজ্ঞা করে?
এমএম

17

আমি এখানে অবয়ব বেরিয়ে যান এবং বলে যে যাচ্ছি এই প্রশ্নের সোজা উত্তর হল সেখানে পরিবর্তনশীল ঘোষণা এবং পরামিতি এবং বিনিময়ে ধরনের জন্য উভয়, যা যে তারকাচিহ্ন নামের পাশে যেতে হবে: int *myVariable;। কেন তা বোঝার জন্য, আপনি কীভাবে সিতে অন্যান্য ধরণের প্রতীক ঘোষণা করেন তা দেখুন:

int my_function(int arg); একটি ফাংশন জন্য;

float my_array[3] একটি অ্যারের জন্য।

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

int a_return_value = my_function(729);

float an_element = my_array[2];

এবং: int copy_of_value = *myVariable;

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


12

এটি কেবল পছন্দের বিষয়।

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

আমি সংখ্যার সাথে টাইপ নামের সাথে সম্পর্কিত সংকেত দিয়ে পয়েন্টারগুলি ঘোষণা করতে পছন্দ করি

int* pMyPointer;

3
প্রশ্নটি সি সম্পর্কে, যেখানে কোনও উল্লেখ নেই।
অ্যান্টি হাপালা

এটি নির্দেশ করার জন্য ধন্যবাদ, যদিও প্রশ্নটি মূলত: পয়েন্টার বা রেফারেন্স সম্পর্কে নয়, কোড ফরম্যাটিং সম্পর্কে।
ম্যাকবার্ডি

8

একজন মহান গুরু একবার বলেছিলেন "এটি সংকলকের উপায়টি পড়ুন, আপনার অবশ্যই হবে।"

http://www.drdobbs.com/conversationsa-midsummer-nights-madness/184403835

মঞ্জুরি দেওয়া হয়েছে এটি কনস্ট প্লেসমেন্টের বিষয়টিতে ছিল তবে এখানে একই বিধি প্রযোজ্য।

সংকলক এটি পড়েন:

int (*a);

যেমন না:

(int*) a;

আপনি যদি ভেরিয়েবলের পাশে তারকা রাখার অভ্যাসে পড়ে থাকেন তবে এটি আপনার ঘোষণাগুলি পড়তে সহজ করে তুলবে। এটি চোখের পাতাকে এড়ানো যেমন:

int* a[10];

- সম্পাদনা করুন -

ঠিক ব্যাখ্যা আমি কি বলতে চাচ্ছি যখন আমি বলতে এটা পার্স এর int (*a), তার মানে যে *আরও অনেক কিছু শক্তভাবে বেঁধে aচেয়ে এটা আছে করার int, খুব পদ্ধতিতে যে এক্সপ্রেশনে 4 + 3 * 7 3আরও অনেক কিছু শক্তভাবে বেঁধে 7চেয়ে এটা আছে করার 4উচ্চতর প্রাধান্য কারণে *

এসকি শিল্পের জন্য ক্ষমা চেয়ে, পার্সিংয়ের জন্য এএসটির একটি সংক্ষিপ্ত বিবরণ int *aমোটামুটি এরকম দেখাচ্ছে:

      Declaration
      /         \
     /           \
Declaration-      Init-
Secifiers       Declarator-
    |             List
    |               |
    |              ...
  "int"             |
                Declarator
                /       \
               /        ...
           Pointer        \
              |        Identifier
              |            |
             "*"           |
                          "a"

যেমনটি পরিষ্কারভাবে দেখানো হয়েছে, তাদের সাধারণ পূর্বপুরুষ যেহেতু *আরও দৃly়ভাবে বাঁধেন , আপনি যখন জড়িত তখন একটি সাধারণ পূর্বপুরুষের সন্ধানের জন্য গাছের উপরে যেতে হবে ।aDeclaratorDeclarationint


না, সংকলকটি অবশ্যই স্পষ্টভাবে টাইপটি পড়ে (int*) a
লন্ডিন

@ লন্ডিন এটি বেশিরভাগ আধুনিক সি ++ প্রোগ্রামারদের দারুণ ভুল বোঝাবুঝি। একটি ভেরিয়েবল ঘোষণার পার্সিং করা এরকম কিছু হয়। পদক্ষেপ 1. প্রথম টোকেনটি পড়ুন, এটি ঘোষণার "বেস টাইপ" হয়ে যায়। intএক্ষেত্রে. পদক্ষেপ 2. কোনও প্রকার সজ্জা সহ একটি ঘোষণা পড়ুন। *aএক্ষেত্রে. পদক্ষেপ 3 পরবর্তী অক্ষর পড়ুন। যদি কমা হয় তবে এটি গ্রহণ করুন এবং ২ য় ধাপে ফিরে যান se যদি সেমিকোলন বন্ধ হয়ে যায়। অন্য কিছু যদি একটি সিনট্যাক্স ত্রুটি নিক্ষেপ করে। ...
Dgnuff

@ লন্ডিন ... পার্সার যদি আপনার প্রস্তাব অনুসারে এটি পড়েন তবে আমরা লিখতে int* a, b;এবং পয়েন্টারগুলির একটি জোড়া পেতে সক্ষম হব । আমি যে বিন্দুটি তৈরি করছি তা হ'ল *ভেরিয়েবলের সাথে বাঁধাই এবং এটি দিয়ে পার্স করা হয়, ঘোষণার "বেস টাইপ" গঠনের ধরণের সাথে নয়। এটি বেশ typedef int *iptr; iptr a, b;কয়েকটি পয়েন্টার তৈরি করতে টাইপেইফগুলি চালু করার কারণটিরও একটি অংশ । একটি typedef ব্যবহার করে আপনি করতে পারেন বাঁধে *করতে int
dgnuff

1
... অবশ্যই, সংকলকটি প্রতিটি ভেরিয়েবলের জন্য চূড়ান্ত প্রকারে পৌঁছানোর জন্য Declaration-Specifier"সজ্জা" সহ বেস টাইপটিকে "সংযুক্ত" করে Declarator। তবে এটি সজ্জাটিকে ঘোষণাপত্রের স্পেসিফায়ারে "সরানো" না করে অন্যথায় int a[10], b;সম্পূর্ণ হাস্যকর ফলাফল আনবে, এটি পার্স int *a, b[10];করে int *a , b[10] ;। এটি বোঝার জন্য অন্য কোনও উপায় নেই that
dgnuff

1
হ্যাঁ, এখানে গুরুত্বপূর্ণ অংশটি প্রকৃতপক্ষে সংকলক পার্সিংয়ের বাক্য গঠন বা ক্রম নয়, তবে int*aশেষের ধরণটি সংকলক দ্বারা শেষ পর্যন্ত পড়তে হবে: " aটাইপ আছে int*"। আমার আসল মন্তব্যে এটাই বোঝা গেল।
লুডিন

3

কারণ আপনার যখন ঘোষণাগুলি থাকে তখন এটি আরও অর্থবোধ করে:

int *a, *b;

5
এটি আক্ষরিক অর্থেই প্রশ্নটি ভিক্ষার একটি উদাহরণ। না, এটি সেভাবে আরও বোঝায় না। "ইনট * এ, বি" উভয়কেই পয়েন্টার হিসাবে তৈরি করতে পারে।
মাইকেলগিজি

1
@ মিচেলজিজি আপনি সেখানে কুকুরটিকে লেগেছে। নিশ্চিত করুন K & আর পারে নির্দিষ্ট করেছেন যে int* a, b;প্রণীত bএকটি পয়েন্টার int। কিন্তু তারা তা করেনি। এবং সঙ্গত কারণ সঙ্গে। আপনার প্রস্তাবিত ব্যবস্থায় ধরণ কি bনিম্নলিখিত ঘোষণায়: int* a[10], b;?
Dgnuff

2

এক লাইনে একাধিক পয়েন্টার ঘোষণার জন্য, আমি পছন্দ করি int* a, * b;কোনটি আরও স্বজ্ঞাতভাবে একটি পূর্ণসংখ্যার পয়েন্টার হিসাবে "a" ঘোষণা করে এবং একইভাবে "বি" ঘোষণা করার সাথে শৈলীর মিশ্রণ হয় না। যেমন কেউ বলেছেন, আমি একই বিবৃতিতে যাইহোক দুটি ভিন্ন ধরণের ঘোষণা করব না।


2

যে সমস্ত ব্যক্তিরা পছন্দ করেন int* x;তারা তাদের কোডটি একটি কাল্পনিক বিশ্বে জোর করার চেষ্টা করছেন যেখানে টাইপটি বাম দিকে রয়েছে এবং সনাক্তকারী (নাম) ডানদিকে রয়েছে।

আমি "কাল্পনিক" বলি কারণ:

সি এবং সি ++ এ, সাধারণ ক্ষেত্রে, ঘোষিত শনাক্তকারী ধরণের তথ্য দ্বারা ঘিরে থাকে।

এটি পাগল মনে হতে পারে, তবে আপনি এটি সত্য জানেন। এখানে কিছু উদাহরন:

  • int main(int argc, char *argv[])মানে " mainএমন একটি ফাংশন যা intএকটিতে পয়েন্টারগুলির একটি অ্যারে নিয়ে যায় charএবং একটিকে ফেরত দেয় int" " অন্য কথায়, বেশিরভাগ টাইপের তথ্য ডানদিকে থাকে। কিছু লোক মনে করে যে ফাংশন ঘোষণাগুলি গণনা করা হয় না কারণ তারা কোনওভাবে "বিশেষ"। ঠিক আছে, আসুন একটি ভেরিয়েবল চেষ্টা করি।

  • void (*fn)(int)মানে fnএমন কোনও ফাংশনের পয়েন্টার যা একটি নেয় intএবং কিছুই দেয় না।

  • int a[10]10 এ intএর অ্যারে হিসাবে 'এ' ঘোষণা করে ।

  • pixel bitmap[height][width]

  • স্পষ্টতই, আমি চেরি-বাছাই করা উদাহরণগুলি পেয়েছি যেগুলিতে আমার বক্তব্যটি বানাতে ডানদিকে প্রচুর তথ্য রয়েছে। এমন অনেকগুলি ঘোষণা রয়েছে যেখানে বেশিরভাগ - যদি না হয় তবে - টাইপটি বাম দিকে থাকে, যেমন struct { int x; int y; } center

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

সি যথেষ্ট সহজ যে অনেক সি প্রোগ্রামাররা এই স্টাইলটি আলিঙ্গন করে এবং হিসাবে সাধারণ ঘোষণাপত্র লেখেন int *p

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

পারেন ভাষা, আপনি করতে পারেন সবসময় বামদিকে প্রকার থাকা পরিবর্তনশীল দ্বারা ঘোষণা (1) কখনও একই বিবৃতিতে একাধিক ভেরিয়েবল ঘোষণা, এবং (2) ব্যবহার করে typedefগুলি (বা ওরফে ঘোষণা, যা, ব্যঙ্গ করে ওরফে করা প্রকারের বামে শনাক্তকারী)। উদাহরণ স্বরূপ:

typedef int array_of_10_ints[10];
array_of_10_ints a;

ছোট প্রশ্ন, কেন অকার্যকর হতে পারে না (* এফএন) (ইনট) এর অর্থ "এফএন হ'ল একটি ফাংশন যা কোনও প্রকার গ্রহণ করে, এবং ফিরে আসে (শূন্য *)?
সোহম দোঙ্গারগাঁওকার

1
@ a3y3: কারণ প্যারেন্টেসিসগুলি (*fn)পয়েন্টারটি fnরিটার্নের ধরণের পরিবর্তে যুক্ত রাখে ।
অ্যাড্রিয়ান ম্যাকার্থি

বুঝেছি. আপনার উত্তরে এটি যুক্ত করা যথেষ্ট গুরুত্বপূর্ণ বলে আমি মনে করি, আমি শীঘ্রই একটি সম্পাদনার পরামর্শ দেব।
সোহম দঙ্গারগাঁওকার

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

1

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


1

এই বিষয়টিতে প্রচুর যুক্তি সরল বিষয়গত এবং "তারাটি পরিবর্তনশীল নামের সাথে বাঁধা" সম্পর্কে যুক্তিটি নিষ্পাপ na এখানে কয়েকটি যুক্তি যা কেবল মতামত নয়:


ভুলে যাওয়া পয়েন্টার ধরণের যোগ্যতা

আনুষ্ঠানিকভাবে, "তারা" না কোনও প্রকারের বা ভেরিয়েবল নামের সাথে সম্পর্কিত, এটি পয়েন্টার নামক নিজস্ব ব্যাকরণগত আইটেমের অংশ । আনুষ্ঠানিক সি সিনট্যাক্স (আইএসও 9899: 2018) হ'ল:

(7.7) ঘোষণা:
ঘোষণাপত্র-সুনির্দিষ্ট সূচনা-ঘোষক-তালিকার বিকল্প ;

যেখানে ডিক্লেয়ারেশন-স্পেসিফায়ারে টাইপ (এবং স্টোরেজ) থাকে এবং আরআর-ডিক্লেয়ার-তালিকায় পয়েন্টার এবং ভেরিয়েবলের নাম থাকে। আমরা যদি দেখি যে আমরা এই ঘোষণাকারী তালিকার সিনট্যাক্সটি আরও ছড়িয়ে দিই:

(7.7..6) ঘোষক:
পয়েন্টার অপ্ট সরাসরি-ঘোষক
...
(7.7.ter) পয়েন্টার:
* টাইপ-কোয়ালিফায়ার-তালিকা অপ্ট
* টাইপ-কোয়ালিফায়ার-তালিকা অপ্ট পয়েন্টার

যেখানে কোনও ঘোষক পুরো ঘোষণা, সরাসরি ঘোষক হ'ল শনাক্তকারী (পরিবর্তনশীল নাম) এবং পয়েন্টারটি তারা হয় তারপরে পয়েন্টারের সাথে সম্পর্কিত একটি alচ্ছিক ধরণের যোগ্যতা অর্জনকারী তালিকা।

"তারকাটি চলকটির সাথে সম্পর্কিত" সম্পর্কে বিভিন্ন স্টাইলের যুক্তিগুলি কী অসামঞ্জস্য করে তোলে তা হ'ল তারা এই পয়েন্টার ধরণের যোগ্যতা সম্পর্কে ভুলে গেছেন। int* const x, int *const xবা int*const x?

বিবেচনা করুন int *const a, b;, প্রকার ও কি কি aএবং b? "তারকাটি ভেরিয়েবলের অন্তর্ভুক্ত" এতটা স্পষ্ট নয় " পরিবর্তে, এক যেখানে বিবেচনা করতে শুরু করবে const

আপনি অবশ্যই একটি দৃ argument় আর্গুমেন্ট তৈরি করতে পারেন যে তারকাটি পয়েন্টার ধরণের কোয়ালিফায়ার সম্পর্কিত, তবে এর বেশি নয়।

পয়েন্টারের জন্য টাইপ যোগ্যতা অর্জনকারী তালিকাটি int *aশৈলী ব্যবহার করে তাদের জন্য সমস্যা তৈরি করতে পারে । যারা একটি typedef(যা আমাদের খুব খারাপ অনুশীলন করা উচিত নয়!) এর ভিতরে পয়েন্টার ব্যবহার করে এবং "তারাটি পরিবর্তনশীল নামের সাথে সম্পর্কিত" বলে মনে করে তারা খুব সূক্ষ্ম বাগটি লিখতে ঝোঁক:

    /*** bad code, don't do this ***/
    typedef int *bad_idea_t; 
    ...
    void func (const bad_idea_t *foo);

এটি পরিষ্কারভাবে সংকলন করে। এখন আপনার মনে হতে পারে কোডটি সঠিকভাবে করা হয়েছে। তাই না! এই কোডটি দুর্ঘটনাক্রমে একটি নকল দৃ const়তা।

প্রকারটি fooআসলে int*const*- বাইরের সর্বাধিক পয়েন্টারটি কেবল পঠনযোগ্য তৈরি হয়েছিল, ডেটা এট পয়েন্ট নয়। সুতরাং এই ফাংশনের ভিতরে আমরা করতে পারি **foo = n;এবং এটি কলারের পরিবর্তনশীল মান পরিবর্তন করবে।

এর কারণ হল অভিব্যক্তিতে const bad_idea_t *foo, *এখানে পরিবর্তনশীল নামের সাথে সম্পর্কিত নয়! সিউডো কোডে, এই পরামিতি ঘোষণাটি পড়তে হয় const (bad_idea_t *) fooএবং হিসাবে হয় না(const bad_idea_t) *foo । তারকা জন্যে এই ক্ষেত্রে গোপন পয়েন্টার টাইপ - টাইপ একটি পয়েন্টার এবং একটি const-যোগ্যতাসম্পন্ন পয়েন্টার হিসেবে লেখা হয় *const

কিন্তু তারপর উপরোক্ত উদাহরণের সমস্যার মূল একটি পিছনে লুকিয়ে পয়েন্টার অভ্যাস typedefএবং *শৈলী।


একক লাইনে একাধিক ভেরিয়েবল ঘোষণার বিষয়ে

একক লাইনে একাধিক ভেরিয়েবল ঘোষণা করা খারাপ অভ্যাস 1) হিসাবে ব্যাপকভাবে স্বীকৃত । সিইআরটি-সি এটিকে সুন্দরভাবে যোগ করে:

DCL04-সি। ঘোষণাপত্রে একাধিক ভেরিয়েবল ঘোষণা করবেন না

শুধু পড়া ইংরেজি, তারপর সাধারণ জ্ঞান সম্মত হয় যে একটি ঘোষণা হওয়া উচিত এক ঘোষণা।

এবং ভেরিয়েবলগুলি পয়েন্টার হয় কিনা তা বিবেচ্য নয়। একক লাইনে প্রতিটি ভেরিয়েবল ঘোষণা করা কোডকে প্রায় প্রতিটি ক্ষেত্রেই পরিষ্কার করে দেয়।

সুতরাং প্রোগ্রামার সম্পর্কে বিভ্রান্ত হওয়ার int* a, bবিষয়ে তর্কটি খারাপ। সমস্যার মূলটি হ'ল একাধিক ডিক্লেয়ারার ব্যবহার, এর স্থান নির্ধারণ নয় *। শৈলী নির্বিশেষে, আপনি পরিবর্তে এটি লিখতে হবে:

    int* a; // or int *a
    int b;

আর একটি শব্দযুক্ত কিন্তু বিষয়গত যুক্তিটি হ'ল int* aযে ধরণের প্রকারটি aপ্রশ্নবিদ্ধ নয় int*এবং তাই তারা এই টাইপের বাছাইয়ের সাথে সম্পর্কিত।

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


1) সিইআরটি-সি ডিসিএল 04-সি


বরং মজাদারভাবে, আপনি যে নিবন্ধটি যুক্ত করেছেন তা যদি আপনি পড়ে থাকেন typedef int *bad_idea_t; void func(const bad_idea_t bar); তবে মহান নবী ড্যান সাকস শেখানোর বিষয়টির একটি সংক্ষিপ্ত বিভাগ রয়েছে "যদি আপনি constশব্দার্থক অর্থ পরিবর্তন না করে সর্বদা যথাসম্ভব ডানদিকে রাখেন" এটি সম্পূর্ণভাবে বন্ধ হয়ে যায় একটি ইস্যু হতে। এটি আপনার constঘোষণাগুলি পড়ার ক্ষেত্রে আরও সুসংগত করে তোলে । "কনস্ট শব্দের ডানদিকের সমস্ত কিছু যা কনস্টেন্ট, বামে সমস্ত কিছু তার টাইপ।" এটি একটি ঘোষণায় সমস্ত কনসেটের জন্য প্রযোজ্য। এটি ব্যবহার করে দেখুনint const * * const x;
ডিসিউনফ

-1

বিবেচনা

int *x = new int();

এটি অনুবাদ করে না

int *x;
*x = new int();

এটি আসলে অনুবাদ করে

int *x;
x = new int();

এটি int *xস্বরলিপি কিছুটা বেমানান করে তোলে ।


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