सी सूचक बिंदुओं के सरणी / सरणी को असंतोष


463

निम्नलिखित घोषणाओं में क्या अंतर है:

int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);

अधिक जटिल घोषणाओं को समझने के लिए सामान्य नियम क्या है?


54
यहाँ सी में जटिल घोषणाओं को पढ़ने के बारे में एक शानदार लेख है: unixwiz.net/techtips/reading-cdecl.html
jesper

@jesper दुर्भाग्य से, constऔर volatileक्वालिफायर, जो महत्वपूर्ण और मुश्किल दोनों हैं, उस लेख में गायब हैं।
नहीं-एक-उपयोगकर्ता

@ नहीं-ए-उपयोगकर्ता जो इस प्रश्न के लिए प्रासंगिक नहीं हैं। आपकी टिप्पणी प्रासंगिक नहीं है। कृपया मना करें।
user64742

जवाबों:


439
int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers

तीसरा वाला पहले जैसा ही है।

सामान्य नियम ऑपरेटर पूर्वता है । यह और भी अधिक जटिल हो सकता है क्योंकि फ़ंक्शन पॉइंटर्स चित्र में आते हैं।


4
तो, 32 बिट सिस्टम के लिए: int * arrest [8]; / * 8x4 बाइट्स आवंटित, प्रत्येक सूचक / इंट (* गिरफ्तारी) [8] के लिए; / 4 बाइट्स आवंटित, केवल एक पॉइंटर * /
जॉर्ज

10
नहीं। int * arrest [8]: 8x4 बाइट्स कुल , 4 बाइट्स प्रत्येक पॉइंटर के लिए आवंटित । int (* arrest) [is] सही है, ४ बाइट्स।
मेहरदाद अफशरी

2
मैंने जो लिखा है उसे फिर से पढ़ना चाहिए। मेरा मतलब प्रत्येक सूचक के लिए 4 था। सहायता के लिए धन्यवाद!
जॉर्ज

4
कारण यह है कि पहले वाला अंतिम जैसा ही है, यह हमेशा घोषणाकर्ताओं के आसपास कोष्ठक को लपेटने की अनुमति है। पी [एन] एक सरणी घोषणाकर्ता है। P (....) एक फ़ंक्शन घोषणाकर्ता है और * P एक पॉइंटर घोषणाकर्ता है। तो निम्नलिखित में सब कुछ बिना किसी कोष्ठक के समान है (कार्यों में से एक को छोड़कर "") (): int (((* p))); शून्य ((g (शून्य))); int * (a) [१]); शून्य (* (पी ())
जोहानस शाउब -

2
अच्छी तरह से अपने स्पष्टीकरण में किया। ऑपरेटरों की पूर्वता और सहूलियत पर गहराई से संदर्भ के लिए ब्रायन केर्निघन और डेनिस रिची द्वारा द सी प्रोग्रामिंग लैंग्वेज (एएनएसआई सी सेकेंड एडिशन) के पृष्ठ ५३ का संदर्भ लें। ऑपरेटरों ( ) [ ] को दाएं से बाएं छोड़ दिया गया है और आकार की एक सरणी के रूप में *पढ़ने की तुलना में अधिक पूर्वता है, int* arr[8]जहां प्रत्येक तत्व एक इंट की ओर इशारा करता है और int (*arr)[8]आकार 8 की एक सरणी के लिए एक संकेतक के रूप में है जो पूर्णांक रखता है
Mushy

267

केडीसीएल कार्यक्रम का उपयोग करें , जैसा कि कश्मीर एंड आर द्वारा सुझाया गया है।

$ cdecl
Type `help' or `?' for help
cdecl> explain int* arr1[8];
declare arr1 as array 8 of pointer to int
cdecl> explain int (*arr2)[8]
declare arr2 as pointer to array 8 of int
cdecl> explain int *(arr3[8])
declare arr3 as array 8 of pointer to int
cdecl>

यह दूसरे तरीके से भी काम करता है।

cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )

@ankii अधिकांश लिनक्स वितरण में एक पैकेज होना चाहिए। आप अपना खुद का बाइनरी भी बना सकते हैं।
सिगाजाइस

यहाँ उल्लेख नहीं करने के लिए खेद है, macOS अगर उपलब्ध है तो देखेंगे, अन्यथा वेबसाइट भी ठीक है। ^ ^ मुझे इस बारे में बताने के लिए धन्यवाद .. एनएलएन को फ्लैग करने के लिए स्वतंत्र महसूस करें।
अंकी

2
@ankii आप Homebrew (और शायद MacPorts?) से इंस्टॉल कर सकते हैं। यदि वे आपके स्वाद के लिए नहीं हैं, तो cdecl.org के शीर्ष दाईं ओर गिथब लिंक से अपना स्वयं का निर्माण करना तुच्छ है (मैंने अभी इसे macOS Mojave पर बनाया है)। तो बस अपने PATH को cdecl बाइनरी कॉपी करें। मैं $ PATH / बिन की सलाह देता हूं, क्योंकि इसमें कुछ भी सरल होने के साथ जड़ को शामिल करने की कोई आवश्यकता नहीं है।
सिगाजाइस

ओह, readme में स्थापना के बारे में थोड़ा पैराग्राफ नहीं पढ़ा था। निर्भरता से निपटने के लिए बस कुछ आदेश और झंडे .. का उपयोग करके स्थापित। :)
अंकी

1
जब मैंने पहली बार इसे पढ़ा तो मैंने सोचा: "मैं इस स्तर तक कभी नहीं आऊंगा"। अगले दिन, मैंने इसे डाउनलोड किया।
सिरो सेंटिल्ली 37 iro iro i 法轮功 '

126

मुझे नहीं पता कि इसका कोई आधिकारिक नाम है, लेकिन मैं इसे राइट-लेफ्ट थिंगी (टीएम) कहता हूं।

चर पर शुरू करें, फिर दाएं, और बाएं, और दाएं ... और इतने पर जाएं।

int* arr1[8];

arr1 पूर्णांक के लिए 8 पॉइंटर्स की एक सरणी है।

int (*arr2)[8];

arr2 8 पूर्णांक की एक सरणी के लिए एक पॉइंटर (कोष्ठक दाएं-बाएं ब्लॉक करता है)।

int *(arr3[8]);

arr3 पूर्णांक के लिए 8 पॉइंटर्स की एक सरणी है।

इससे आपको जटिल घोषणाओं में मदद मिलेगी।


19
मैंने इसे "द स्पिरल रूल" के नाम से जाना है, जिसे यहाँ पाया जा सकता है
चार

6
@ इंकबेंडेंड: सर्पिल नियम दाएं-बाएं नियम से अलग है । पूर्व में विफल रहता है जैसे मामलों में int *a[][10], जबकि दूसरा सफल होता है।
लीजेंड्स 2k

1
@dogeen मुझे लगा कि शब्द का ब्रेज़ेन स्ट्रॉस्ट्रुप के साथ कुछ करना है :)
अनिरुद्ध रामनाथन

1
जैसा कि InkBlend और किंवदंतियों 2k ने कहा, यह सर्पिल नियम है जो अधिक जटिल है और सभी मामलों में काम नहीं करता है, इसलिए इसका उपयोग करने का कोई कारण नहीं है।
kotlomoy

करने के लिए सही सहानुभूति ( ) [ ]और बाएं से दाएं के बाएं * &
लेफ्टिनेंट

28
int *a[4]; // Array of 4 pointers to int

int (*a)[4]; //a is a pointer to an integer array of size 4

int (*a[8])[5]; //a is an array of pointers to integer array of size 5 

नहीं होना चाहिए 3 एक: एक आकार की पूर्णांक सरणी 8 के लिए संकेत की एक सरणी है? मेरा मतलब है कि पूर्णांक सरणियों में से प्रत्येक का आकार 8 सही होगा?
रशिल पॉल

2
@Rushil: नहीं, अंतिम सबस्क्रिप्ट ( [5]) आंतरिक आयाम का प्रतिनिधित्व करता है। इसका मतलब है कि (*a[8])पहला आयाम है, और इस प्रकार यह सरणी का बाहरी प्रतिनिधित्व है। a अंकों के भीतर प्रत्येक तत्व आकार का एक अलग पूर्णांक सरणी है 5.
zeboidlund

तीसरे के लिए धन्यवाद। मैं देख रहा हूँ कि कैसे व्यूअर की सरणी को अरेंज करें।
Deqing

15

C में सुनहरे नियम से अंतिम दो का उत्तर भी काटा जा सकता है:

घोषणा का उपयोग करता है।

int (*arr2)[8];

क्या होता है अगर आप दखल देते हैं arr2? आपको 8 पूर्णांक की एक सरणी मिलती है।

int *(arr3[8]);

यदि आप एक तत्व लेते हैं तो क्या होता है arr3? आपको एक पूर्णांक के लिए एक संकेतक मिलता है।

यह पॉइंटर्स के साथ फ़ंक्शंस पर काम करने में भी मदद करता है। सिगाजिस का उदाहरण लेने के लिए:

float *(*x)(void )

क्या होता है जब आप dereference x? आपको एक फ़ंक्शन मिलता है जिसे आप बिना किसी तर्क के कॉल कर सकते हैं। जब आप इसे कहते हैं तो क्या होता है? यह एक सूचक को लौटा देगा a float

हालांकि, ऑपरेटर की प्रक्रिया हमेशा पेचीदा होती है। हालाँकि, कोष्ठक का उपयोग करना वास्तव में भ्रमित करने वाला हो सकता है क्योंकि घोषणा निम्नानुसार है। कम से कम, मेरे लिए, सहज रूप arr2से 8 पॉइंटर्स की एक सरणी की तरह दिखता है, लेकिन यह वास्तव में चारों ओर का दूसरा तरीका है। बस कुछ करने की आदत होती है। इन घोषणाओं में हमेशा एक टिप्पणी जोड़ने के लिए पर्याप्त कारण है, अगर आप मुझसे पूछें :)

संपादित करें: उदाहरण

वैसे, मैं सिर्फ निम्नलिखित स्थिति में ठोकर खाई है: एक फ़ंक्शन जिसमें एक स्थिर मैट्रिक्स होता है और यह इंगित करने के लिए कि पंक्ति सूचक बाहर है, यह देखने के लिए सूचक अंकगणितीय का उपयोग करता है। उदाहरण:

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

#define NUM_ELEM(ar) (sizeof(ar) / sizeof((ar)[0]))

int *
put_off(const int newrow[2])
{
    static int mymatrix[3][2];
    static int (*rowp)[2] = mymatrix;
    int (* const border)[] = mymatrix + NUM_ELEM(mymatrix);

    memcpy(rowp, newrow, sizeof(*rowp));
    rowp += 1;
    if (rowp == border) {
        rowp = mymatrix;
    }

    return *rowp;
}

int
main(int argc, char *argv[])
{
    int i = 0;
    int row[2] = {0, 1};
    int *rout;

    for (i = 0; i &lt; 6; i++) {
        row[0] = i;
        row[1] += i;
        rout = put_off(row);
        printf("%d (%p): [%d, %d]\n", i, (void *) rout, rout[0], rout[1]);
    }

    return 0;
}

आउटपुट:

0 (0x804a02c): [0, 0]
1 (0x804a034): [0, 0]
2 (0x804a024): [0, 1]
3 (0x804a02c): [1, 2]
4 (0x804a034): [2, 4]
5 (0x804a024): [3, 7]

ध्यान दें कि बॉर्डर का मान कभी नहीं बदलता है, इसलिए कंपाइलर उस दूर का अनुकूलन कर सकता है। यह उस चीज़ से अलग है जिसे आप शुरू में उपयोग करना चाहते हैं const int (*border)[3]:: जो कि 3 पूर्णांकों की एक सीमा के लिए एक संकेतक के रूप में सीमा की घोषणा करता है जो तब तक मूल्य नहीं बदलेगा जब तक कि चर मौजूद नहीं है। हालाँकि, उस पॉइंटर को किसी भी समय ऐसे किसी अन्य ऐरे से इंगित किया जा सकता है। हम तर्क के लिए उस तरह का व्यवहार चाहते हैं, बजाय (क्योंकि यह फ़ंक्शन उन पूर्णांकों में से कोई भी परिवर्तन नहीं करता है)। घोषणा का उपयोग करता है।

(पीएस: इस नमूने को बेहतर बनाने के लिए स्वतंत्र महसूस करें!)



3

एक सामान्य नियम के, सही एकल ऑपरेटरों (जैसे के रूप में [], (), आदि) बाईं लोगों की तुलना में प्राथमिकता ले। तो, int *(*ptr)()[];एक ऐसा पॉइंटर होगा जो एक ऐसे फंक्शन की ओर इशारा करता है जो पॉइंटर्स की एक सरणी को इंट में लौटाता है (जैसे ही आप कोष्ठक से बाहर निकल सकते हैं सही ऑपरेटर प्राप्त करें)


यह सच है, लेकिन यह भी ilegal है। आपके पास एक फ़ंक्शन नहीं हो सकता है जो एक सरणी देता है। मैंने कोशिश की और इसे मिला: error: ‘foo’ declared as function returning an array int foo(int arr_2[5][5])[5];जीसीसी 8 के तहत$ gcc -std=c11 -pedantic-errors test.c
काकाहुइट फ्रिटो

1
संकलक को उस त्रुटि को देने का कारण यह है कि यह एक सरणी को वापस करने के रूप में फ़ंक्शन की व्याख्या कर रहा है, जैसा कि पूर्ववर्ती शासन राज्यों की सही व्याख्या है। यह घोषणा के रूप में ilegal है, लेकिन कानूनी घोषणा int *(*ptr)();एक अभिव्यक्ति p()[3](या (*p)()[3]) का उपयोग करने की अनुमति देता है बाद में।
लुइस कोलोराडो

ठीक है, अगर मैं इसे समझता हूं, तो आप एक फ़ंक्शन बनाने के बारे में बात कर रहे हैं जो एक सरणी के पहले तत्व को पॉइंटर लौटाता है (खुद एक सरणी नहीं), और बाद में उस फ़ंक्शन का उपयोग करें जैसे कि वह एक सरणी लौटा रहा था? दिलचस्प विचार। मैं इसे आजमाऊंगा। int *foo(int arr_2[5][5]) { return &(arr_2[2][0]); }और इसे इस तरह कहें: foo(arr)[4];जिसमें सम्‍मिलित होना चाहिए arr[2][4], है ना?
काकाहुइट फ्रिटो

सही ... लेकिन आप सही भी थे, और घोषणा ilegal थी। :)
लुइस कोलोराडो

2

मुझे लगता है कि हम सरल नियम का उपयोग कर सकते हैं।

example int * (*ptr)()[];
start from ptr 

" ptrएक पॉइंटर है" राइट राइट की ओर जाएं .. "" "अब लेफ्ट लेफ्ट ए" ("बाहर जाओ राइट" ") (" तो "एक फंक्शन में जाए जो कोई तर्क नहीं लेता" लेफ्ट "और एक पॉइंटर लौटाता है) दाएं "पूर्णांक के" एक बाएं "पर जाएं"


मैं थोड़ा सुधार करूंगा: "ptr एक ऐसा नाम है जो संदर्भित करता है" गो राईट ... इट्स ), अब लेफ्ट गो ... *इट्स "पाइंटर टू" राईट राइट ... इट्स ), अब लेफ्ट गो ... इट्स एक (बाहर आ सही जाना, ()... इसलिए सही जाओ "एक समारोह जो कोई तर्क लेता है करने के लिए" []"और रिटर्न की एक सरणी" सही जाना ;अंत, इसलिए छोड़ दिया जाने ... *"संकेत करने के लिए" जाना छोड़ दिया ... int"पूर्णांक"
14


2

यहां बताया गया है कि मैं इसकी व्याख्या कैसे करता हूं:

int *something[n];

पूर्वता पर ध्यान दें: सरणी सबस्क्रिप्ट ऑपरेटर ( []) में डेरेफेरेंस ऑपरेटर ( *) की तुलना में अधिक प्राथमिकता है ।

इसलिए, यहां हम []पहले वाले को लागू करेंगे *, जो कथन के समतुल्य होगा:

int *(something[i]);

इस बात पर ध्यान दें कि एक घोषणा कैसे समझ में आती है: int numसाधन numएकint , int *ptrया int (*ptr)साधन है, (मूल्य पर ptr) एक है int, जो ptrएक सूचक बनाता है int

इसे इस रूप में पढ़ा जा सकता है, (किसी वस्तु के ith सूचकांक पर मान) एक पूर्णांक है। तो, (कुछ के ith सूचकांक पर मूल्य) एक (पूर्णांक सूचक) है, जो कुछ को पूर्णांक सूचक का एक सरणी बनाता है।

दूसरे में,

int (*something)[n];

इस कथन से समझ बनाने के लिए, आपको इस तथ्य से परिचित होना चाहिए:

सरणी के सूचक प्रतिनिधित्व पर ध्यान दें: somethingElse[i]के बराबर है*(somethingElse + i)

तो, के somethingElseसाथ की जगह (*something), हम प्राप्त करते हैं *(*something + i), जो घोषणा के अनुसार पूर्णांक है। इसलिए, (*something)हमें एक एरे दिया गया है, जो किसी चीज़ को एक व्यूह के बराबर बनाता है ।


0

मुझे लगता है कि दूसरी घोषणा कई लोगों को भ्रमित कर रही है। यहां इसे समझने का एक आसान तरीका है।

चलो पूर्णांक की एक सरणी है, यानी int B[8]

चलो एक चर A भी है जो B को इंगित करता है। अब A पर मान B है, अर्थात (*A) == B । इसलिए पूर्णांक की एक सरणी के लिए एक अंक। आपके प्रश्न में, गिरफ्तार A के समान है।

इसी तरह, में int* (*C) [8], C पूर्णांक के लिए संकेत की एक सरणी के लिए एक सूचक है।


0
int *arr1[5]

इस घोषणा में, arr1पूर्णांक के लिए 5 बिंदुओं की एक सरणी है। कारण: वर्ग कोष्ठक में (dereferncing संचालक) से अधिक पूर्वता है। और इस प्रकार में, पंक्तियों की संख्या निश्चित है (5 यहाँ), लेकिन स्तंभों की संख्या परिवर्तनशील है।

int (*arr2)[5]

इस घोषणा में, arr25 तत्वों के पूर्णांक सरणी के लिए एक सूचक है। कारण: यहां, () कोष्ठक में [] की तुलना में अधिक पूर्वता है। और इस प्रकार में, पंक्तियों की संख्या परिवर्तनशील है, लेकिन स्तंभों की संख्या निश्चित है (5 यहाँ)।


-7

एक पूर्णांक के लिए सूचक में अगर सूचक बढ़ा हुआ है तो यह अगले पूर्णांक में जाता है।

पॉइंटर की सरणी में यदि पॉइंटर को बढ़ाया जाता है तो वह अगले ऐरे में कूदता है


" पॉइंटर की सरणी में अगर पॉइंटर को बढ़ाया जाता है तो वह अगले ऐरे से कूदता है " यह स्पष्ट गलत है।
अल्क
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.