C में एरो ऑपरेटर (->) का उपयोग


257

मैं 21 दिनों में "टीच योरसेल्फ सी" (मैं पहले से ही जावा और सी # सीख चुका हूं, नामक एक किताब पढ़ रहा हूं इसलिए मैं बहुत तेज गति से आगे बढ़ रहा हूं)। मैं बिंदुओं और ->तीर पर अध्याय पढ़ रहा था ऑपरेटर स्पष्टीकरण के बिना आया था। मुझे लगता है कि इसका उपयोग सदस्यों और कार्यों को कॉल करने के लिए किया जाता है (जैसे कि .(डॉट के बराबर ) ऑपरेटर, लेकिन सदस्यों के बजाय संकेत के लिए)। लेकिन मुझे पूरा यकीन नहीं है।

क्या मुझे एक स्पष्टीकरण और एक कोड नमूना मिल सकता है?


90
एक बेहतर पुस्तक प्राप्त करें। norvig.com/21-days.html
joshperry

9
qrdl सही है - "Learn X in Y days" किताबें आमतौर पर कचरा हैं। K & R के अलावा, मैं Prata के "C प्राइमर प्लस" की भी सिफारिश करूंगा, जो K & R की तुलना में अधिक गहराई में जाता है।
जे। टेलर

3
@ यह प्रश्न C ++ से संबंधित है। इसे कॉल करना मेरे लिए कुछ भ्रम पैदा कर गया जब मैंने ऑपरेटर को उस दूसरे उत्तर में ओवरलोडिंग के बारे में पढ़ना शुरू किया, जो सी में प्रासंगिक नहीं है
जोहान

1
@ बेल्टन कठिन रास्ता श्रृंखला खराब है, आदमी कहता है कि सामान तब भी प्रासंगिक नहीं था जब उसने किताब लिखी थी और वह अच्छे अभ्यासों की परवाह नहीं करता है।
1925 में बैलिंट

1
पीटर नॉरविग लिंक "टीच योरसेल्फ प्रोग्रामिंग इन द टेन ईयर्स", मेरे पसंदीदा में से एक है। यहाँ कॉमिक संस्करण है जो बताता है कि 21 दिनों में यह कैसे करना है, जिसे मुझे दुर्भाग्य से एक XKCD के रूप में याद किया गया था लेकिन मैं गलत था: abstrusegoose.com/249
Ted

जवाबों:


462

foo->barके समतुल्य है (*foo).bar, अर्थात इसे barउस संरचना से बुलाया गया है जो fooइंगित करता है।


51
यह ध्यान देने योग्य है कि यदि अनुमापन ऑपरेटर को पोस्टफ़िक्स बनाया गया है, जैसा कि पास्कल में, ->ऑपरेटर को बिल्कुल भी ज़रूरत नहीं होगी, क्योंकि यह बहुत अधिक सुपाठ्य के बराबर होगा foo*.bar। सभी अतिरिक्त कोष्ठकों के साथ टाइप-एफई-इन कार्यों की पूरी गड़बड़ी से भी बचा जाता था।
लोर्ने

1
तो होगा foo*.barऔर (*foo).barदोनों के बराबर हो foo->bar? किस बारे में Foo myFoo = *foo; myFoo.bar?
एरॉन फ्रेंके

9
नहीं, वह सिर्फ यह कह रहा है कि यदि C के रचनाकारों ने PREIFT के बजाय Dereference ऑपरेटर को POSTfix ऑपरेटर बनाया होता तो यह और अधिक आसान होता। लेकिन यह सी। में एक उपसर्ग ऑपरेटर है
पुनर्निर्मित

@ user207421 Coulfd कृपया आप "सभी अतिरिक्त कोष्ठक के साथ टाइप किए गए एफआईएफ फ़ंक्शन के लिए एक संक्षिप्त विवरण या लिंक दें" जिसका आप उल्लेख करते हैं? धन्यवाद।
RoG

1
@ user207421 नाह, यह अधिक माता-पिता का कारण होगा .. अब तक, बाईं ओर * () और [ऊपर] के दाईं ओर प्राथमिकता है। यदि वे सभी एक तरफ हैं, तो आपने अधिक माता-पिता को रखा होगा। अभिव्यक्ति में समान, गुणन ऑपरेटर के साथ संघर्ष के कारण। पास्कल ^ एक विकल्प हो सकता है लेकिन यह बिट ऑपरेशन के लिए आरक्षित था, फिर भी अधिक माता-पिता।
स्विफ्ट - शुक्रवार पाई

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?
CMCDragonkai

प्रश्न विशेष रूप से सी के बारे में था, जिसमें कक्षाएं या संदर्भ चर नहीं हैं।
ओक

1
हम्म आपको पवार स्ट्रक्चर फू * पंवार को लिखने से पहले एक मॉलॉक नहीं करना चाहिए; ?? pvar-> y बिना लिखी जगह पर लिखें!
जिब्री

Pvar आरंभीकरण: सभी सदस्यों को मैन्युअल रूप से कुछ डिफॉल्ट्स के लिए प्रारंभ करें जिन्हें आप कॉलोक () जैसे कुछ का उपयोग करना चाहते हैं या करना चाहते हैं यदि शून्य भरण आपके लिए ठीक होगा।
रिछारट

2
ऐसा नहीं होना चाहिए: pvar = malloc (sizeof (स्ट्रक्चर फू)) या malloc (sizeof (* pvar)) ??
यूरी एप्स

33

a->bबस के लिए कम है (*a).bहर तरह से (कार्यों के लिए एक ही: a->b()के लिए कम है (*a).b())।


1
वहाँ प्रलेखन है जो कहता है कि यह तरीकों के लिए भी काम करता है?
एशकेचम

28

मैं सिर्फ "क्यों?" उत्तरों में जोड़ दूँगा।

.मानक सदस्य अभिगम संचालक है जो *सूचक संचालक की तुलना में एक उच्च मिसाल है ।

जब आप किसी संरचना के इंटर्न को एक्सेस करने की कोशिश कर रहे होते हैं और आपने इसे लिखा होता है, *foo.barतब कंपाइलर 'फू' (जो कि स्मृति में एक पता है) का 'बार' तत्व चाहता है और जाहिर है कि केवल पते का कोई सदस्य नहीं है।

इस प्रकार आपको कंपाइलर को पहले डेरेक्शन व्हिथ में पूछने (*foo)और फिर सदस्य तत्व तक पहुंचने की आवश्यकता है: (*foo).barजो लिखने के लिए थोड़ा अनाड़ी है, इसलिए अच्छे लोग शॉर्टहैंड संस्करण के साथ आए हैं: foo->barजो कि पॉइंटर ऑपरेटर द्वारा सदस्य की पहुंच का प्रकार है।



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लेकिन पता संरचना के बगल में भी एक है डेटा का हिस्सा ( ! )! डेटा के चंक के पहले सदस्य के पास संरचना की तुलना में एक ही पता है और आप इसे केवल इस तरह *ptr (कोई ब्रेसिज़) एक पॉइंटर को डीरफेरिंग करके डेटा प्राप्त कर सकते हैं ।

लेकिन आप पहले एक के अलावा कोई अन्य सदस्य तक पहुंचने चाहते हैं, आप की तरह एक डेसिग्नेटर जोड़ने के लिए .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 पॉइंटर को पॉजिटिव करने के लिए मजबूर करते हैं और एसेस को डेटा और 2 के चंक को सक्षम करते हैं आप सदस्य को चुनने के लिए ऑफ़सेट (डिज़ाइनर) जोड़ते हैं।

इस छवि की जाँच करें जो मैंने बनाई थी:

यहां छवि विवरण दर्ज करें

लेकिन अगर आपके पास नेस्टेड सदस्य होते हैं तो यह सिंटैक्स अपठनीय हो जाएगा और इसलिए ->इसे पेश किया गया था। मुझे लगता है कि पठनीयता इसका उपयोग करने का एकमात्र औचित्य है क्योंकि यह 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 II परियोजना से उद्धृत )

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

Dot एक dereference संचालक है और इसका उपयोग संरचना के एक विशेष रिकॉर्ड के लिए संरचना चर को जोड़ने के लिए किया जाता है। जैसे:

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

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

ऐसे में हम स्ट्रक्चर वेरिएबल तक पहुंचने के लिए डॉट ऑपरेटर का उपयोग कर सकते हैं


6
यह किस मूल्य को जोड़ता है? उदाहरण अन्य उत्तरों की तुलना में थोड़ा खराब है जो वास्तव में इसकी तुलना करते हैं ->। साथ ही इस सवाल का जवाब 4.5 साल पहले ही दिया जा चुका है।
EW15
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.