তীর অপারেটর (->) সি তে ব্যবহার করুন


257

আমি "21 দিনের মধ্যে নিজেকে সি শিখি" নামে একটি বই পড়ছি (আমি ইতিমধ্যে জাভা এবং সি শিখেছি তাই আমি আরও দ্রুত গতিতে এগিয়ে যাচ্ছি)। আমি পয়েন্টারগুলিতে অধ্যায়টি পড়ছিলাম এবং ->(তীর) অপারেটরটি ব্যাখ্যা ছাড়াই উঠে এল। আমি মনে করি এটি সদস্য এবং ফাংশনগুলিতে .(ডট) অপারেটরের সমতুল্য , তবে সদস্যের পরিবর্তে পয়েন্টারগুলির জন্য) ব্যবহৃত হয়। তবে আমি পুরোপুরি নিশ্চিত নই।

আমি দয়া করে একটি ব্যাখ্যা এবং একটি কোড নমুনা পেতে পারি?


90
একটি ভাল বই পান। norvig.com/21-days.html
জোশপুরি

9
qrdl সঠিক - "ওয়াই দিনগুলিতে এক্স শিখুন" বইগুলি সাধারণত আবর্জনা। কেএন্ডআর ছাড়াও, আমি প্রতার "সি প্রিমার প্লাস" সুপারিশ করব, যা কেএন্ডআর থেকে আরও গভীরতায় যায়।
জে টেইলর

3
@ স্টিভ এই প্রশ্নটি সি ++ এর সাথে সম্পর্কিত। এটিকে অন্য উত্তরে অপারেটর ওভারলোডিং সম্পর্কে পড়তে শুরু করে এটিকে আমার জন্য কিছুটা বিভ্রান্তির কারণ হিসাবে বর্ণনা করা হয়েছে, যা সি
জোহান

1
@ বেল্টন হার্ড ওয়ে সিরিজটি খারাপ, লোকটি এমন জিনিস বলে যা বইটি লেখার সময় এমনকি প্রাসঙ্গিক ছিল না এবং ভাল অভ্যাসের জন্য সে যত্ন করে না।
বুলিন্ট

1
পিটার নরভিগ লিঙ্কটি "দশ বছরের মধ্যে নিজেকে শিখিয়ে দিন" দুর্দান্ত, আমার অন্যতম প্রিয়। এখানে কমিক সংস্করণটি এখানে ব্যাখ্যা করবে যে এটি 21 দিনের মধ্যে কীভাবে করা যায়, যা আমি দুর্ভাগ্যক্রমে একটি এক্সকেসিডি হিসাবে স্মরণ করি কিন্তু আমি ভুল ছিল: abstrusegoose.com/249
টেড

উত্তর:


462

foo->barএর সমতুল্য (*foo).bar, যেমন এটি barস্ট্রাক্ট থেকে নির্দেশিত সদস্যকে fooপয়েন্ট দেয়।


51
এটি লক্ষণীয় যে, যদি পাস্কালের মতো ডেরিফারেন্স অপারেটরকে পোস্টফিক্স তৈরি করা ->হত তবে অপারেটরের মোটেই প্রয়োজন হত না, কারণ এটি আরও অনেক সুগঠিতের সমতুল্য হত foo*.bar। সমস্ত অতিরিক্ত বন্ধনীগুলির সাথে টাইপডেফিং-এর ফাংশনগুলির পুরো গণ্ডগোলটিও এড়ানো যেত।
লার্নের মারকুইস

1
সুতরাং foo*.barএবং (*foo).barউভয় সমতুল্য হবে foo->bar? কি হবে Foo myFoo = *foo; myFoo.bar?
অ্যারন ফ্রেঙ্ক

9
না, তিনি কেবল বলছেন যে সি এর নির্মাতারা যদি ড্রেইফারেন্স অপারেটরটিকে প্রিফিক্সের পরিবর্তে পোস্টফিক্স অপারেটর হিসাবে তৈরি করতেন তবে আরও সহজ হত। তবে এটি সি
16:59

@ user207421 আপনি কি উল্লেখ করেছেন আপনি দয়া করে একটি সংক্ষিপ্ত বিবরণ দিন বা "অতিরিক্ত অতিরিক্ত প্রথম বন্ধনীর সাথে টাইপডেফ-ইন ফাংশন" এর লিঙ্ক দিয়েছেন? ধন্যবাদ।
RoG

1
@ ব্যবহারকারী 207421 না, এটি আরও বেশি পিতামাতার কারণ হতে পারে .. এখন পর্যন্ত, () এবং [] এর বামদিকে ডানদিকে * অগ্রাধিকার রয়েছে। যদি তারা সবাই একদিকে থাকে তবে আপনি আরও বাবা-মা'কে রেখেছেন। এক্সপ্রেশন একই, কারণ গুণ অপারেটর সঙ্গে বিরোধ। পাস্কাল an একটি বিকল্প হতে পারে তবে এটি বিট অপারেশনের জন্য সংরক্ষিত ছিল, আরও বেশি বাবা-মা।
সুইফ্ট - শুক্রবার পাই

129

হ্যাঁ, এটা।

এটি কেবল বিন্দু সংস্করণ যখন আপনি কোনও কাঠামো / শ্রেণীর উপাদানগুলিতে অ্যাক্সেস করতে চান যা কোনও রেফারেন্সের পরিবর্তে পয়েন্টার হয়।

struct foo
{
  int x;
  float y;
};

struct foo var;
struct foo* pvar;
pvar = malloc(sizeof(pvar));

var.x = 5;
(&var)->y = 14.3;
pvar->y = 22.4;
(*pvar).x = 6;

এটাই!


3
যেহেতু pvar অবিবেচনাযুক্ত, আপনি যদি pvar একটি নতুন কাঠামোর দিকে নির্দেশ করতে চান, আপনি এটি কীভাবে সূচনা করবেন pvar = &var?
সিএমসিডিগ্রাগনকাই

প্রশ্নটি বিশেষত সি সম্পর্কে ছিল, যার ক্লাস বা রেফারেন্স ভেরিয়েবল নেই।
ওক

1
এইচএমএম আপনি পিভিআর স্ট্রাক্ট foo * pvar এ লেখার আগে কোনও মালক করবেন না; ?? pvar-> y লিখুন অনিবন্ধিত স্থান!
জিব্রি

পিভিআর ইনিশিয়ালাইজেশন: সমস্ত সদস্যকে ম্যানুয়ালি আপনি যে কিছু ডিফল্ট রাখতে চান তা শুরু করুন বা কলোকের মতো কিছু ব্যবহার করুন () যদি শূন্য পূরণ আপনার পক্ষে ভাল হয়।
রিচার্ট

2
এটি হওয়া উচিত নয়: pvar = malloc (আকারের (স্ট্রাক্ট foo)) বা malloc (মাপের (* pvar)) ??
ইউরি এপস

33

a->b(*a).bপ্রতিটি উপায়ে কেবল সংক্ষিপ্ত (ফাংশনগুলির জন্য একই: এর a->b()জন্য সংক্ষিপ্ত (*a).b())।


1
ডকুমেন্টেশন আছে যা বলে যে এটি পদ্ধতিগুলির জন্য সেভাবে কাজ করে?
আশেকেটচম

28

আমি উত্তরগুলিতে কেবল "কেন?" যুক্ত করব।

.হ'ল স্ট্যান্ডার্ড সদস্য অ্যাক্সেস অপারেটর যা *পয়েন্টার অপারেটরের চেয়ে উচ্চতর প্রাধান্য পায় ।

যখন আপনি কোনও স্ট্রাক্টের অভ্যন্তরীণ অ্যাক্সেসের চেষ্টা করছেন এবং আপনি এটি লিখেছিলেন *foo.barতখনই সংকলকটি 'foo' (যা স্মৃতিতে একটি ঠিকানা) এর একটি 'বার' উপাদান চাইবে এবং স্পষ্টতই যে ঠিকানার কোনও সদস্য নেই।

সুতরাং আপনাকে প্রথমে সংকলকটি প্রথমে ডিগ্রিফিকেশন উইথ (*foo)এবং তারপরে সদস্য উপাদানটি অ্যাক্সেস করতে হবে: (*foo).barএটি লেখার জন্য কিছুটা আনাড়ি কারণ ভাল লোকেরা একটি শর্টহ্যান্ড সংস্করণ নিয়ে এসেছে: foo->barযা পয়েন্টার অপারেটরের দ্বারা সদস্য অ্যাক্সেসের ধরণ sort



10
struct Node {
    int i;
    int j;
};
struct Node a, *p = &a;

এখানে মান অ্যাক্সেস করতে iএবং jআমরা পরিবর্তনশীল ব্যবহার করতে পারেন aএবং পয়েন্টার pনিম্নরূপ: a.i, (*p).iএবং p->iসবাই একই রকম।

এখানে .একটি "সরাসরি নির্বাচক" এবং ->এটি একটি "পরোক্ষ নির্বাচক"।


2

ওয়েল আমি পাশাপাশি কিছু যোগ করতে হবে। অ্যারের চেয়ে স্ট্রাকচারটি কিছুটা আলাদা কারণ অ্যারে একটি পয়েন্টার এবং কাঠামো নয়। তাই সতর্কতা অবলম্বন করা!

বলি আমি কোডটির এই অকেজো টুকরোটি লিখি:

#include <stdio.h>

typedef struct{
        int km;
        int kph;
        int kg;
    } car;

int main(void){

    car audi = {12000, 230, 760};
    car *ptr = &audi;

}

এখানে পয়েন্টারটি কাঠামোর ভেরিয়েবলের ptrঠিকানা ( ! ) নির্দেশ করে audiতবে ঠিকানার কাঠামোর পাশেও ডেটা রয়েছে ( ! )! প্রথম সদস্য ডেটার খণ্ড গঠন নিজেই চেয়ে একই ঠিকানা আছে এবং আপনি শুধুমাত্র এই মত একটি পয়েন্টার dereferencing দ্বারা এটি এর ডাটা পেতে পারেন *ptr (কোন ধনুর্বন্ধনী)

কিন্তু আপনি প্রথম এক ছাড়া অন্য সদস্য acess করতে চান তাহলে, তোমার মত designator যোগ আছে .km, .kph, .kgযা বেস ঠিকানায় অফসেট ছাড়া আর কিছুই হয় ডেটার খণ্ড ...

কিন্তু অগ্রাধিকারের কারণে আপনি লিখতে পারবেন না *ptr.kgযেমন অ্যাক্সেস অপারেটরের .মূল্য নির্ধারণ করা হয় ডিসিফারেন্স অপারেটরের আগে *এবং আপনি পাবেন *(ptr.kg)যা পয়েন্টারের কোনও সদস্য না হওয়ায় এটি সম্ভব নয়! এবং সংকলক এটি জানে এবং অতএব একটি ত্রুটি প্রদান করবে যেমন:

error: ptr is a pointer; did you mean to use ‘->’?
  printf("%d\n", *ptr.km);

পরিবর্তে আপনি এটি ব্যবহার করেন (*ptr).kgএবং আপনি পয়েন্টারটিকে 1 ম শ্রদ্ধার জন্য সংকলককে বাধ্য করেন এবং ডেটা বিভাজনে অ্যাক্সেস সক্ষম করেন এবং ২ য় বার আপনি সদস্য চয়ন করতে একটি অফসেট (ডিজাইনার) যুক্ত করেন।

আমি তৈরি এই চিত্রটি দেখুন:

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

তবে আপনি যদি নেস্টেড সদস্য থাকতেন তবে এই সিনট্যাক্সটি অপঠনযোগ্য হয়ে উঠবে এবং সুতরাং ->এটি চালু হয়েছিল। আমি মনে করি পাঠযোগ্যতা এটি ব্যবহারের একমাত্র ন্যায়সঙ্গত কারণ এটি ptr->kgলেখার চেয়ে অনেক সহজ (*ptr).kg

এখন আসুন আমরা এটিকে অন্যভাবে লিখি যাতে আপনি সংযোগটি আরও পরিষ্কার করে দেখতে পান। (*ptr).kg(*&audi).kgaudi.kg। এখানে আমি প্রথম যে ব্যবহৃত ptrএকটি হল "এর ঠিকানা audi" অর্থাত &audiএবং সত্য যে "রেফারেন্স" & এবং "ডি-রেফারেন্স" * অপারেটরদের eachother বাদ গেল।


1

এটি চালানোর জন্য আমাকে জ্যাকের প্রোগ্রামে একটি ছোট পরিবর্তন করতে হয়েছিল। স্ট্রাক্ট পয়েন্টার pvar ঘোষণার পরে, এটি var এর ঠিকানায় নির্দেশ করুন। আমি এই সমাধানটি সি-তে স্টিফেন কোচানের প্রোগ্রামিংয়ের 242 পৃষ্ঠায় পেয়েছি

#include <stdio.h>

int main()
{
  struct foo
  {
    int x;
    float y;
  };

  struct foo var;
  struct foo* pvar;
  pvar = &var;

  var.x = 5;
  (&var)->y = 14.3;
  printf("%i - %.02f\n", var.x, (&var)->y);
  pvar->x = 6;
  pvar->y = 22.4;
  printf("%i - %.02f\n", pvar->x, pvar->y);
  return 0;
}

নিম্নলিখিত কমান্ডের সাথে এটি ভিএম চালান:

:!gcc -o var var.c && ./var

আউটপুট দেবে:

5 - 14.30
6 - 22.40

3
ভিএম টিপ: %বর্তমান ফাইলের নাম উপস্থাপন করতে ব্যবহার করুন । লাইক যেমন:!gcc % && ./a.out
জিবেরিয়া

1
#include<stdio.h>

int main()
{
    struct foo
    {
        int x;
        float y;
    } var1;
    struct foo var;
    struct foo* pvar;

    pvar = &var1;
    /* if pvar = &var; it directly 
       takes values stored in var, and if give  
       new > values like pvar->x = 6; pvar->y = 22.4; 
       it modifies the values of var  
       object..so better to give new reference. */
    var.x = 5;
    (&var)->y = 14.3;
    printf("%i - %.02f\n", var.x, (&var)->y);

    pvar->x = 6;
    pvar->y = 22.4;
    printf("%i - %.02f\n", pvar->x, pvar->y);

    return 0;
}

1

->অপারেটর চেয়ে কোড আরো পাঠযোগ্য *কিছু পরিস্থিতিতে অপারেটর।

যেমন: ( দ্বিতীয় EDK প্রকল্প থেকে উদ্ধৃত )

typedef
EFI_STATUS
(EFIAPI *EFI_BLOCK_READ)(
  IN EFI_BLOCK_IO_PROTOCOL          *This,
  IN UINT32                         MediaId,
  IN EFI_LBA                        Lba,
  IN UINTN                          BufferSize,
  OUT VOID                          *Buffer
  );


struct _EFI_BLOCK_IO_PROTOCOL {
  ///
  /// The revision to which the block IO interface adheres. All future
  /// revisions must be backwards compatible. If a future version is not
  /// back wards compatible, it is not the same GUID.
  ///
  UINT64              Revision;
  ///
  /// Pointer to the EFI_BLOCK_IO_MEDIA data for this device.
  ///
  EFI_BLOCK_IO_MEDIA  *Media;

  EFI_BLOCK_RESET     Reset;
  EFI_BLOCK_READ      ReadBlocks;
  EFI_BLOCK_WRITE     WriteBlocks;
  EFI_BLOCK_FLUSH     FlushBlocks;

};

_EFI_BLOCK_IO_PROTOCOLStruct হয় 4 ফাংশন পয়েন্টার সদস্যদের রয়েছে।

মনে করুন আপনার একটি পরিবর্তনশীল রয়েছে struct _EFI_BLOCK_IO_PROTOCOL * pStructএবং আপনি *এর সদস্য ফাংশন পয়েন্টারটিকে কল করতে ভাল পুরাতন অপারেটরটি ব্যবহার করতে চান । আপনি এর মতো কোড দিয়ে শেষ করবেন:

(*pStruct).ReadBlocks(...arguments...)

তবে ->অপারেটরের সাহায্যে আপনি এটি লিখতে পারেন:

pStruct->ReadBlocks(...arguments...)

কোনটি আরও ভাল দেখাচ্ছে?


1
আমি মনে করি কোডটি যদি সমস্ত ক্যাপগুলিতে না থাকে তবে এটি 90 এর দশক থেকে এওএল চ্যাটে কিশোর-কিশোরদের দ্বারা টাইপ করা হয়েছে।
থ্যাং করুন

1
#include<stdio.h>
struct examp{
int number;
};
struct examp a,*b=&a;`enter code here`
main()
{
a.number=5;
/* a.number,b->number,(*b).number produces same output. b->number is mostly used in linked list*/
   printf("%d \n %d \n %d",a.number,b->number,(*b).number);
}

আউটপুট 5 5 5


0

বিন্দু একটি dereferences অপারেটর এবং কাঠামোর নির্দিষ্ট রেকর্ডের জন্য কাঠামো পরিবর্তনশীল সংযোগ করতে ব্যবহৃত হয়। যেমন:

struct student
    {
      int s.no;
      Char name [];
      int age;
    } s1,s2;

main()
    {
      s1.name;
      s2.name;
    }

স্ট্রাকচার ভেরিয়েবলটি অ্যাক্সেস করতে আমরা এইভাবে কোনও ডট অপারেটর ব্যবহার করতে পারি


6
এটি কোন মূল্য যুক্ত করে? অন্যান্য উত্তরগুলির তুলনায় উদাহরণটি কিছুটা দুর্বল যা আসলে এর তুলনায় আসলে তুলনা করে ->। এছাড়াও এই প্রশ্নের উত্তর ইতিমধ্যে 4.5 বছর ধরে দেওয়া হয়েছে।
EWit
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.