2008-10-13 19 views
33

मैं संकेत के साथ कुछ समझने की कोशिश कर रहा था, इसलिए मैं इस कोड लिखा है: जब जीसीसी के साथ संकलनमुद्रण संकेत

#include <stdio.h> 

int main(void) 
{ 
    char s[] = "asd"; 
    char **p = &s; 

    printf("The value of s is: %p\n", s); 
    printf("The direction of s is: %p\n", &s); 

    printf("The value of p is: %p\n", p); 
    printf("The direction of p is: %p\n", &p); 

    printf("The direction of s[0] is: %p\n", &s[0]); 
    printf("The direction of s[1] is: %p\n", &s[1]); 
    printf("The direction of s[2] is: %p\n", &s[2]); 

    return 0; 
} 

मैं इन चेतावनियों मिलती है:

$ gcc main.c -o main-bin -ansi -pedantic -Wall -lm 
main.c: In function ‘main’: 
main.c:6: warning: initialization from incompatible pointer type 
main.c:9: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char (*)[4]’ 
main.c:11: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char **’ 
main.c:12: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char ***’ 

(झंडे के लिए जीसीसी हैं क्योंकि मुझे सी 8 9 होना चाहिए)

सूचक के असंगत प्रकार क्यों? किसी सरणी का नाम उसके पहले तत्व के लिए सूचक नहीं है? तो यदि एस 'ए' के ​​लिए सूचक है, &schar ** होना चाहिए, नहीं? और मुझे अन्य चेतावनियां क्यों मिलती हैं? क्या उन्हें मुद्रित करने के लिए पॉइंटर्स (void *) के साथ डालना है?

और जब मैं कुछ इस तरह मिल चलाने:

$ ./main-bin 
The value of s is: 0xbfb7c860 
The direction of s is: 0xbfb7c860 
The value of p is: 0xbfb7c860 
The direction of p is: 0xbfb7c85c 
The direction of s[0] is: 0xbfb7c860 
The direction of s[1] is: 0xbfb7c861 
The direction of s[2] is: 0xbfb7c862 

कैसे कर सकता है रों के मूल्य और यह दिशा (और निश्चित रूप से p का मूल्य) एक ही हो सकता है?

उत्तर

24

"एस" एक "char *" नहीं है, यह एक "char [4]" है। और इसलिए, "& एस" एक "char **" नहीं है, लेकिन वास्तव में "4 characater की एक सरणी के लिए एक सूचक"। आपका कंपाइलर "&" का इलाज कर सकता है जैसे कि आपने "& s [0]" लिखा था, जो मोटे तौर पर एक ही चीज़ है, लेकिन एक "char *" है।

जब आप "char ** p = & s;" लिखते हैं आप यह कहने की कोशिश कर रहे हैं "मैं चाहता हूं कि पी को उस चीज़ के पते पर सेट किया जाए जो वर्तमान में" asd "को इंगित करता है। लेकिन वर्तमान में अंक" asd "में कुछ भी नहीं है। केवल एक सरणी है जो रखती है" asd ";। अनावश्यक रूप से करने के लिए (शून्य *) संकेत कास्ट करने के लिए

char s[] = "asd"; 
char *p = &s[0]; // alternately you could use the shorthand char*p = s; 
char **pp = &p; 
+0

आपको बहुत धन्यवाद जेम्स ... – alcuadrado

+0

एक सरणी का अर्थ है कि एक सूचक के लिए 's' decays के बाद से विशेष प्रकार का एक संगत स्मृति पता, हम कह सकते हैं कि यह 'char *' [सरणी का पहला तत्व] –

+0

@ CholthiPaulTtiopic - नहीं सबसे पहले, यह होना चाहिए "हम कह सकते हैं कि यह 'char'' ('char *' नहीं) के लिए एक सूचक है। लेकिन, आप इसे कुछ मामलों में 'char' के सूचक के रूप में उपयोग कर सकते हैं, लेकिन यह इसे एक नहीं बनाता है। "5.0" एक पूर्णांक हो सकता है, लेकिन यह 'int' नहीं है, हालांकि आप इसे कुछ स्थानों पर उपयोग कर सकते हैं जो' int 'लेते हैं। –

0

आप का इस्तेमाल किया है:

char s[] = "asd"; 

यहाँ वास्तव में है बाइट्स "asd" के लिए अंक। एस का पता, इस स्थान को भी इंगित करेगा।

यदि आप प्रयोग किया है:

char *s = "asd"; 

रों के मूल्य और & रों, अलग होगा के रूप में वास्तव में बाइट्स "asd" करने के लिए एक सूचक होगा।

आप प्रयोग किया है: बाइट्स "asd" करने के लिए

char s[] = "asd"; 
char **p = &s; 

यहाँ है इंगित करता है। पी वर्णकों के लिए एक सूचक के लिए एक सूचक है, और पात्रों के पते पर सेट किया गया है। दूसरे शब्दों में आपके पास पी में बहुत से संकेत हैं। यदि आपने char * s = "asd" का उपयोग किया है, तो आप इस अतिरिक्त संकेत का उपयोग कर सकते हैं।

+0

लेकिन मैं पी एस के लिए एक सूचक होना चाहता हूँ, नहीं करने के लिए ' ए'। – alcuadrado

+0

@alcuadrado: लेकिन एस आईएस 'ए' है। इसकी मूल गलतफहमी मूल समस्या है। –

+0

ओह - मैं संदेश पोस्ट करते समय व्यस्त टाइपिंग करता हूं। – selwyn

13

हां, आपका कंपाइलर शून्य * की अपेक्षा कर रहा है। बस उन्हें रद्द करने के लिए *।

/* for instance... */ 
printf("The value of s is: %p\n", (void *) s); 
printf("The direction of s is: %p\n", (void *) &s); 
+0

यह गलत है। शून्य करने के लिए कास्टिंग * समस्या को छिपा रहा है, इसे हल नहीं कर रहा है। –

+1

मेरा पहला विचार यह था कि वह सिर्फ उन मानों को मुद्रित करना चाहता था जो संकलक ने असाइन किए गए मानों को देखने के लिए प्रिंट किया था, और शून्य को कास्टिंग करने से उन्हें उनकी घोषणाओं में किसी भी समस्या के बावजूद उसे छोड़ दिया जाएगा। लेकिन हाँ, यह निश्चित रूप से इस मुद्दे से परहेज कर रहा है। – indiv

+7

एक वैरिएडिक फ़ंक्शन में '% p' प्रारूप में तर्कों के लिए' शून्य * 'पर कास्टिंग वास्तव में भाषा मानक द्वारा __required__ है। – Jens

1

परिवर्तन लाइन:

चार रों [] = "asd";

रहे हैं:

चार * रों = "asd"; यदि आप एक समारोह के लिए एक तर्क के रूप एक सरणी के नाम पार कर लेते हैं

और चीजों को और अधिक स्पष्ट

+2

त्रुटि दूर हो जाएगी, लेकिन कुछ भी स्पष्ट नहीं होगा, क्योंकि आप मूल समस्या के स्पष्टीकरण से बचाते हैं। –

4

मिल जाएगा, यह इलाज किया जैसे कि आप सरणी के पते पारित किया था है। तो & एस और एस समान तर्क हैं। के & आर 5.3 देखें। & एस [0] & एस जैसा ही है, क्योंकि यह सरणी के पहले तत्व का पता लेता है, जो सरणी का पता लेने जैसा ही है।

अन्य सभी के लिए, हालांकि सभी पॉइंटर्स अनिवार्य रूप से स्मृति स्थान हैं जिन्हें वे अभी भी टाइप कर रहे हैं, और संकलक एक प्रकार के पॉइंटर को दूसरे को असाइन करने के बारे में चेतावनी देगा।

  • void* p; कहते पी एक स्मृति पता है, लेकिन मैं क्या स्मृति
  • char* s; कहते हैं एक स्मृति पता है में नहीं जानता, और पहली बाइट एक चरित्र
  • char** ps; कहते ps एक होता है मेमोरी एड्रेस, और चार बाइट्स (32-बिट सिस्टम के लिए) में चार प्रकार का पॉइंटर होता है *।

सीएफ http://www.oberon2005.ru/paper/kr_c.pdf (K & आर के ई बुक संस्करण)

1

आप मूल्य नहीं बदल सकते (अर्थात्, पता) एक स्थिर सरणी। तकनीकी शर्तों में, एक सरणी का लवण अपने पहले तत्व का पता है। इसलिए s == &s। यह सिर्फ भाषा का एक quirk है।

1

आम तौर पर, यह गरीब शैली माना जाता है यहाँ, तथापि, आप printf तर्कों पर (* शून्य) को डाले जरूरत है क्योंकि printf variadic है प्रोटोटाइप। संकलक को यह नहीं बताता कि पॉइंटर्स को कॉल साइट पर किस प्रकार परिवर्तित करना है।

2

यह char* चरित्र के लिए सूचक नहीं है लेकिन एक सूचक के लिए एक सूचक 4 वर्ण: char* [4]।जी के साथ ++ यह संकलन नहीं करता है:

main.cpp: In function ‘int main(int, char**)’: main.cpp:126: error: cannot convert ‘char (*)[4]’ to ‘char**’ in initialization

इसके अलावा, linux आदमी पृष्ठों says:

char* s = "asd"; 
char** p = &s; 

printf("The value of s is: %p\n", s); 
printf("The address of s is: %p\n", &s); 

printf("The value of p is: %p\n", p); 
printf("The address of p is: %p\n", &p); 

printf("The address of s[0] is: %p\n", &s[0]); 
printf("The address of s[1] is: %p\n", &s[1]); 
printf("The address of s[2] is: %p\n", &s[2]); 

परिणाम:

p

The void * pointer argument is printed in hexadecimal (as if by %#x or %#lx). It shoud be pointer to void.

आप अपने कोड को बदल सकते हैं एस का मान है: 0x403f00

रों का पता है: 0x7fff2df9d588

पी का मान: 0x7fff2df9d588

पी का पता है: 0x7fff2df9d580

के पते [0] है: 0x403f00

एस के पते [1] है: 0x403f01

के पते [2] है: 0x403f02

+0

हाय, इस पुराने प्रश्न का उत्तर देने के लिए धन्यवाद। सौभाग्य से मैंने पिछले 4 वर्षों में प्रोग्रामिंग के बारे में बहुत कुछ सीख लिया है। लेकिन मुझे लगता है कि आपका इरादा उन लोगों को बेहतर अंतर्दृष्टि देना है जो इस प्रश्न पर पहुंचते हैं। इसे ध्यान में रखते हुए, मुझे यह कहना होगा कि एक सी ++ कंपाइलर के साथ सी कोड संकलित करना एक अच्छी बात नहीं है, वे एक ही भाषा नहीं हैं, और भ्रमित करने से यह बग को ले जाता है। पीएस: यह टिप्पणी बॉक्स हाहा – alcuadrado

+0

@alcuadrado ओह बेकार है, तारीख को नहीं देखा, यह प्रागैतिहासिक है! – 4pie0

+0

मुझे लगता है, कोई समस्या नहीं! – alcuadrado

संबंधित मुद्दे