निम्नलिखित घोषणाओं में क्या अंतर है:
int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);
अधिक जटिल घोषणाओं को समझने के लिए सामान्य नियम क्या है?
const
और volatile
क्वालिफायर, जो महत्वपूर्ण और मुश्किल दोनों हैं, उस लेख में गायब हैं।
निम्नलिखित घोषणाओं में क्या अंतर है:
int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);
अधिक जटिल घोषणाओं को समझने के लिए सामान्य नियम क्या है?
const
और volatile
क्वालिफायर, जो महत्वपूर्ण और मुश्किल दोनों हैं, उस लेख में गायब हैं।
जवाबों:
int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers
तीसरा वाला पहले जैसा ही है।
सामान्य नियम ऑपरेटर पूर्वता है । यह और भी अधिक जटिल हो सकता है क्योंकि फ़ंक्शन पॉइंटर्स चित्र में आते हैं।
( ) [ ]
को दाएं से बाएं छोड़ दिया गया है और आकार की एक सरणी के रूप में *
पढ़ने की तुलना में अधिक पूर्वता है, int* arr[8]
जहां प्रत्येक तत्व एक इंट की ओर इशारा करता है और int (*arr)[8]
आकार 8 की एक सरणी के लिए एक संकेतक के रूप में है जो पूर्णांक रखता है
केडीसीएल कार्यक्रम का उपयोग करें , जैसा कि कश्मीर एंड आर द्वारा सुझाया गया है।
$ 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 )
मुझे नहीं पता कि इसका कोई आधिकारिक नाम है, लेकिन मैं इसे राइट-लेफ्ट थिंगी (टीएम) कहता हूं।
चर पर शुरू करें, फिर दाएं, और बाएं, और दाएं ... और इतने पर जाएं।
int* arr1[8];
arr1
पूर्णांक के लिए 8 पॉइंटर्स की एक सरणी है।
int (*arr2)[8];
arr2
8 पूर्णांक की एक सरणी के लिए एक पॉइंटर (कोष्ठक दाएं-बाएं ब्लॉक करता है)।
int *(arr3[8]);
arr3
पूर्णांक के लिए 8 पॉइंटर्स की एक सरणी है।
इससे आपको जटिल घोषणाओं में मदद मिलेगी।
int *a[][10]
, जबकि दूसरा सफल होता है।
( ) [ ]
और बाएं से दाएं के बाएं * &
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
[5]
) आंतरिक आयाम का प्रतिनिधित्व करता है। इसका मतलब है कि (*a[8])
पहला आयाम है, और इस प्रकार यह सरणी का बाहरी प्रतिनिधित्व है। a
अंकों के भीतर प्रत्येक तत्व आकार का एक अलग पूर्णांक सरणी है 5.
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 < 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 पूर्णांकों की एक सीमा के लिए एक संकेतक के रूप में सीमा की घोषणा करता है जो तब तक मूल्य नहीं बदलेगा जब तक कि चर मौजूद नहीं है। हालाँकि, उस पॉइंटर को किसी भी समय ऐसे किसी अन्य ऐरे से इंगित किया जा सकता है। हम तर्क के लिए उस तरह का व्यवहार चाहते हैं, बजाय (क्योंकि यह फ़ंक्शन उन पूर्णांकों में से कोई भी परिवर्तन नहीं करता है)। घोषणा का उपयोग करता है।
(पीएस: इस नमूने को बेहतर बनाने के लिए स्वतंत्र महसूस करें!)
typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];
एक सामान्य नियम के, सही एकल ऑपरेटरों (जैसे के रूप में []
, ()
, आदि) बाईं लोगों की तुलना में प्राथमिकता ले। तो, int *(*ptr)()[];
एक ऐसा पॉइंटर होगा जो एक ऐसे फंक्शन की ओर इशारा करता है जो पॉइंटर्स की एक सरणी को इंट में लौटाता है (जैसे ही आप कोष्ठक से बाहर निकल सकते हैं सही ऑपरेटर प्राप्त करें)
error: ‘foo’ declared as function returning an array int foo(int arr_2[5][5])[5];
जीसीसी 8 के तहत$ gcc -std=c11 -pedantic-errors test.c
int *(*ptr)();
एक अभिव्यक्ति p()[3]
(या (*p)()[3]
) का उपयोग करने की अनुमति देता है बाद में।
int *foo(int arr_2[5][5]) { return &(arr_2[2][0]); }
और इसे इस तरह कहें: foo(arr)[4];
जिसमें सम्मिलित होना चाहिए arr[2][4]
, है ना?
मुझे लगता है कि हम सरल नियम का उपयोग कर सकते हैं।
example int * (*ptr)()[];
start from ptr
" ptr
एक पॉइंटर है" राइट राइट की ओर जाएं .. "" "अब लेफ्ट लेफ्ट ए" ("बाहर जाओ राइट" ") (" तो "एक फंक्शन में जाए जो कोई तर्क नहीं लेता" लेफ्ट "और एक पॉइंटर लौटाता है) दाएं "पूर्णांक के" एक बाएं "पर जाएं"
)
, अब लेफ्ट गो ... *
इट्स "पाइंटर टू" राईट राइट ... इट्स )
, अब लेफ्ट गो ... इट्स एक (
बाहर आ सही जाना, ()
... इसलिए सही जाओ "एक समारोह जो कोई तर्क लेता है करने के लिए" []
"और रिटर्न की एक सरणी" सही जाना ;
अंत, इसलिए छोड़ दिया जाने ... *
"संकेत करने के लिए" जाना छोड़ दिया ... int
"पूर्णांक"
यहाँ एक दिलचस्प वेबसाइट है जो बताती है कि सी में जटिल प्रकार कैसे पढ़ें: http://www.unixwiz.net/techtips/reading-cdecl.html
यहां बताया गया है कि मैं इसकी व्याख्या कैसे करता हूं:
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)
हमें एक एरे दिया गया है, जो किसी चीज़ को एक व्यूह के बराबर बनाता है ।
मुझे लगता है कि दूसरी घोषणा कई लोगों को भ्रमित कर रही है। यहां इसे समझने का एक आसान तरीका है।
चलो पूर्णांक की एक सरणी है, यानी int B[8]
।
चलो एक चर A भी है जो B को इंगित करता है। अब A पर मान B है, अर्थात (*A) == B
। इसलिए पूर्णांक की एक सरणी के लिए एक अंक। आपके प्रश्न में, गिरफ्तार A के समान है।
इसी तरह, में int* (*C) [8]
, C पूर्णांक के लिए संकेत की एक सरणी के लिए एक सूचक है।
int *arr1[5]
इस घोषणा में, arr1
पूर्णांक के लिए 5 बिंदुओं की एक सरणी है। कारण: वर्ग कोष्ठक में (dereferncing संचालक) से अधिक पूर्वता है। और इस प्रकार में, पंक्तियों की संख्या निश्चित है (5 यहाँ), लेकिन स्तंभों की संख्या परिवर्तनशील है।
int (*arr2)[5]
इस घोषणा में, arr2
5 तत्वों के पूर्णांक सरणी के लिए एक सूचक है। कारण: यहां, () कोष्ठक में [] की तुलना में अधिक पूर्वता है। और इस प्रकार में, पंक्तियों की संख्या परिवर्तनशील है, लेकिन स्तंभों की संख्या निश्चित है (5 यहाँ)।