बहुत कम उत्तर:
बदलें इस:
char **str;
इस होने के लिए:
char (*str)[10];
और उसके बाद अपने कोड में कोई भी त्रुटि ठीक। str
का प्रकार आपके दो आयामी सरणी के प्रकार के साथ संगत नहीं है। मैंने रिटर्न प्रकार को int
main()
(सी मानक के अनुसार शून्य की अनुमति नहीं है) को ठीक करने की स्वतंत्रता ली।मैं भी स्रोत जहां तकनीकी रूप से अपरिभाषित व्यवहार है चिह्नित:
#include <stdio.h>
int main()
{
char a[5][10]={"one","two","three","four","five"};
char (*str)[10] = a;
printf("%p ", &a[0]);
printf("\n%p ", &str[0]);
printf("\n%p ", &str[3]);
printf("\n%p ", &str[1][56]); // this is undefined behaviour
printf("\n%p ", &(*(*(str+4)+1)));
return 0;
}
तुम भी ध्यान देना चाहिए पिछले printf()
बयान एक ज़रूरत से ज़्यादा &(*(...))
कि जरूरत नहीं है है। यह इस तरह से देखने के लिए है, जो बराबर है छीन लिया जा सकता है:
printf("\n%p ", *(str+4)+1);
आउटपुट (सिस्टम आश्रित)
0x7fff5fbff900
0x7fff5fbff900
0x7fff5fbff91e
0x7fff5fbff942
0x7fff5fbff929
बहुत (बहुत, बहुत) लांग उत्तर
आप अपनी धारणा में गलत हैं कि दो आयाम अल सरणी एक पॉइंटर-टू-पॉइंटर के बराबर है। वे केवल उपयोग वाक्यविन्यास में समान हैं। निम्नलिखित कैसे सरणी a
स्मृति में चित्रित किया है
char a[5][10]
0 1 2 3 4 5 6 7 8 9
-----------------------------------------
0 | o | n | e | 0 | | | | | | |
-----------------------------------------
1 | t | w | o | 0 | | | | | | |
-----------------------------------------
2 | t | h | r | e | e | 0 | | | | |
-----------------------------------------
3 | f | o | u | r | 0 | | | | | |
-----------------------------------------
4 | f | i | v | e | 0 | | | | | |
-----------------------------------------
ध्यान दें कि दूसरी पंक्ति के शुरू करने से पता है, जो &a[1]
है, दस बाइट्स पिछले पहली पंक्ति के शुरू पता है का एक मोटा लेआउट है, &a[0]
(जो पूरी तरह से सरणी का प्रारंभिक पता नहीं है)। निम्नलिखित को दर्शाता है यह:
int main()
{
char a[5][10] = { "one", "two", "three", "four", "five" };
printf("&a = %p\n", &a);
printf("&a[0] = %p\n", &a[0]);
printf("a[0] = %p\n", a[0]);
printf("&a[1] = %p\n", &a[1]);
printf("a[1] = %p\n", a[1]);
return 0;
}
आउटपुट
&a = 0x7fff5fbff8e0
&a[0] = 0x7fff5fbff8e0
a[0] = 0x7fff5fbff8e0
&a[1] = 0x7fff5fbff8ea
a[1] = 0x7fff5fbff8ea
ध्यान दें कि a[1]
पर पता 10 बाइट (0x0a
हेक्स) सरणी की शुरुआत पिछले है। पर क्यों? इसका उत्तर देने के लिए टाइप किए गए पॉइंटर अंकगणित की मूल बातें समझनी चाहिए।
कैसे करता है टाइप-सूचक अंकगणित काम?
सी और सी ++ में, void
को छोड़कर सभी पॉइंटर्स टाइप किए गए हैं। पॉइंटर से जुड़े एक मौलिक डेटा प्रकार है। उदाहरण के लिए। पाँच पूर्णांकों का आकार होने के लिए आबंटित स्मृति का एक क्षेत्र है
int *iptr = malloc(5*sizeof(int));
iptr
ऊपर अंक। यह संबोधित करते के रूप में हम आम तौर पर सरणियों को संबोधित इस तरह दिखता है:
iptr[1] = 1;
लेकिन हम बस के रूप में आसानी से इस तरह उसे संबोधित कर सकते हैं:
*(iptr+1) = 1;
और परिणाम एक ही हो सकता है; दूसरे सरणी स्लॉट में मान 1 का भंडारण (0-स्लॉट पहले होना)। हम जानते हैं कि dereference ऑपरेटर *
किसी पते (सूचक में संग्रहीत पता) के माध्यम से पहुंच की अनुमति देता है। लेकिन (iptr+1)
कैसे चार बाइट्स को छोड़ना जानता है (यदि आपका int
प्रकार 32 बिट है, तो आठ बिट्स यदि वे 64 बिट हैं) तो अगले पूर्णांक स्लॉट तक पहुंचने के लिए?
उत्तर: टाइप-पॉइंटर अंकगणित की वजह से।संकलक जानता है कि कितने चौड़े, बाइट्स में अंतर्निहित सूचक पॉइंटर है (इस मामले में, int
प्रकार की चौड़ाई)। जब आप पॉइंटर्स से/स्केलर मानों को जोड़ते या घटाते हैं, तो संकलक उचित "कोड" के लिए उपयुक्त कोड उत्पन्न करता है। यह उपयोगकर्ता प्रकारों के साथ भी काम करता है। यह नीचे दर्शाया गया है:
#include <stdio.h>
typedef struct Data
{
int ival;
float fval;
char buffer[100];
} Data;
int main()
{
int ivals[10];
int *iptr = ivals;
char str[] = "Message";
char *pchr = str;
Data data[2];
Data *dptr = data;
printf("iptr = %p\n", iptr);
printf("iptr+1 = %p\n", iptr+1);
printf("pchr = %p\n", pchr);
printf("pchr+1 = %p\n", pchr+1);
printf("dptr = %p\n", dptr);
printf("dptr+1 = %p\n", dptr+1);
return 0;
}
आउटपुट
iptr = 0x7fff5fbff900
iptr+1 = 0x7fff5fbff904
pchr = 0x7fff5fbff8f0
pchr+1 = 0x7fff5fbff8f1
dptr = 0x7fff5fbff810
dptr+1 = 0x7fff5fbff87c
सूचना iptr
और iptr+1
के बीच पता अंतर नहीं एक बाइट है; यह चार बाइट्स है (मेरे सिस्टम पर int
की चौड़ाई)। इसके बाद, एक char
की चौड़ाई pchr
और pchr+1
के साथ एक बाइट के रूप में प्रदर्शित की जाती है। अंत में, हमारे कस्टम डेटा प्रकार Data
इसके दो सूचक मान, dptr
और dptr+1
दिखाते हैं कि यह 0x6C, या 108 बाइट चौड़ा है। (यह संरचना पैकिंग और फील्ड संरेखण के कारण बड़ा हो सकता था, लेकिन हम इस उदाहरण के साथ भाग्यशाली थे कि यह नहीं था)। यह समझ में आता है, क्योंकि संरचना में दो 4-बाइट डेटा फ़ील्ड्स (int
और float
) और एक चार बफर 100 तत्व चौड़े हैं।
रिवर्स भी सच है, और अक्सर अनुभवी सी/सी ++ प्रोग्रामर द्वारा विचार किया जाता है। यह टाइप किया गया पॉइंटर differencing है। आप एक निर्दिष्ट प्रकार के दो वैध संकेत दिए गए वैध स्मृति का एक सन्निहित क्षेत्र के भीतर है:
int ar[10];
int *iptr1 = ar+1;
int *iptr5 = ar+5;
क्या करें क्या आप से एक परिणाम के रूप मिलता है लगता है:
printf("%lu", iptr5 - iptr1);
जवाब है .. 4
। हूपे, आप कहते हैं। कोई बड़ी बात नहीं? क्या आपको विश्वास नहीं है कि यह है। यह अत्यंत एक विशिष्ट तत्व के बफर में ऑफसेट निर्धारित करने के लिए पॉइंटर अंकगणितीय का उपयोग करते समय आसान है।
सारांश में, आप इस तरह एक अभिव्यक्ति है जब:
int ar[5];
int *iptr = ar;
iptr[1] = 1;
आप यह पता कर सकते हैं के बराबर है:
*(iptr+1) = 1;
कौन सा, सामान्य-आदमी की दृष्टि से, का अर्थ है "पता ले लो iptr
चर में आयोजित, 1 * (int
बाइट्स में बाइट्स) बाइट्स जोड़ें, फिर लौटाए गए पते के माध्यम से स्मृति स्मृति में 1
को संग्रहीत करें। "
साइट बार: यह भी काम करेगा।यदि आप के बारे में सोच क्यों
1[iptr] = 1;
अपने (हमारे) नमूना सरणी वापस, अब क्या होता है जब हम a
का एक ही पते का उल्लेख पर एक नज़र ले जा सकते हैं देखते हैं, लेकिन एक डबल सूचक के माध्यम से (जो पूरी तरह से गलत है और अपने संकलक आप काम के बारे में कम से कम चेतावनी दी है चाहिए):
char **str = a; // Error: Incompatible pointer types: char ** and char[5][10]
खैर वह काम नहीं करता। लेकिन ऐसा करने के लिए एक पल के लिए मान लें। char **
एक पॉइंटर-टू-चार के लिए एक सूचक है। इसका मतलब यह है कि परिवर्तनीय स्वयं को पॉइंटर से ज्यादा कुछ नहीं रखता है। इसमें आधार पंक्ति चौड़ाई आदि की कोई अवधारणा नहीं है, इसलिए मानते हैं कि आप डबल-पॉइंटर str
में a
का पता डालते हैं।
char **str = (char **)(a); // Should NEVER do this, here for demonstration only.
char *s0 = str[0]; // what do you suppose this is?
हमारे परीक्षण कार्यक्रम के लिए थोड़ा सा अद्यतन:
int main()
{
char a[5][10] = { "one", "two", "three", "four", "five" };
char **str = (char **)a;
char *s0 = str[0];
char *s1 = str[1];
printf("&a = %p\n", &a);
printf("&a[0] = %p\n", &a[0]);
printf("a[0] = %p\n", a[0]);
printf("&a[1] = %p\n", &a[1]);
printf("a[1] = %p\n", a[1]);
printf("str = %p\n", str);
printf("s0 = %p\n", s0);
printf("s1 = %p\n", s1);
return 0;
}
हमें निम्न परिणाम देता है:
&a = 0x7fff5fbff900
&a[0] = 0x7fff5fbff900
a[0] = 0x7fff5fbff900
&a[1] = 0x7fff5fbff90a
a[1] = 0x7fff5fbff90a
str = 0x7fff5fbff900
s0 = 0x656e6f
s1 = 0x6f77740000
खैर, str
लगता है कि यह हम क्या चाहते है, लेकिन यह बात क्या है s0
में? क्यों, अक्षरों के लिए ASCII चरित्र मान है। कौन सा? एक सभ्य ASCII table की एक त्वरित जांच से पता चलता हैं:
0x65 : e
0x6e : n
0x6f : o
शब्द "एक" रिवर्स में (रिवर्स अपने सिस्टम पर बहु बाइट मूल्यों की endian से निपटने के कारण होता है, लेकिन मुझे आशा है कि समस्या यह है Thats स्पष्ट क्या है कि दूसरी मूल्य के बारे में:।
0x6f : o
0x77 : w
0x74 : t
हाँ, thats "दो" तो क्यों न हम संकेत के रूप में हमारे सरणी में बाइट्स हो रही है
हममम .. हाँ, के रूप में मैं में कहा।? मेरी टिप्पणी। जो भी आपको या हिन बताता है आपको बताता है कि डबल पॉइंटर्स और दो आयामी सरणी समानार्थी गलत हैं। टाइप किए गए सूचक अंकगणित में हमारे अंतराल को याद करें। याद रखें, यह:
str[1]
और इस:
*(str+1)
पर्याय बन गया है। कुंआ। सूचक के टाइप करें? जिस प्रकार से यह इंगित करता है वह char
पॉइंटर है। इसलिए, इस बीच बाइट गिनती अंतर:
str + 0
और इस
str + 1
एक char*
के आकार होगा। मेरे सिस्टम पर जो 4 बाइट्स है (मेरे पास 32 बिट पॉइंटर्स हैं)। यह बताता है कि क्यों पताstr[1]
में डेटा हमारे मूल सरणी के आधार पर चार बाइट्स है।
इसलिए, अपने पहले मौलिक प्रश्न का उत्तर दें (हां, हम अंततः उस पर पहुंचे)। यह:
&str[3]
इस के बराबर है:
0xbf7f6292
जवाब क्यों str[3]
है
(str + 3)
लेकिन हम (str + 3)
ऊपर से पता अभी पता str
में जमा हो जाती है, फिर str
अंक की 3x चौड़ाई जोड़ना, जोहै, उस पते पर बाइट्स में। कुंआ। हम जानते हैं से अपने दूसरे printf
क्या है कि पता है:
0xbf7f6286
और हम जानते हैं कि आपके सिस्टम पर एक सूचक की चौड़ाई 4 बाइट (32 बिट संकेत) है। इसलिए ...
0xbf7f6286 + (3 * 4)
या ....
0xbf7f6286 + 0x0C = 0xbf7f6292
आपका सरणी 'A', यहां तक कि दो आयामों के साथ, नहीं सूचक के लिए सूचक का पर्याय है। – WhozCraig