2010-02-08 19 views
5

इस कोड का उत्पादन "पी = हैलो दुनिया":हम स्ट्रेटर पॉइंटर को स्ट्रिंग क्यों नहीं कॉपी कर सकते हैं जब हम सीधे स्ट्रिंग असाइन कर सकते हैं?

#include "stdio.h" 
#include "string.h" 

int main(){ 
    char *p; 
    p="hello world"; 
    printf("p is %s \n",p); 
    return 0; 
} 

लेकिन इस कोड एक विभाजन गलती का उत्पादन:

#include "stdio.h" 
#include "string.h" 

int main() { 
    char *p; 
    strcpy(p,"hello"); 
    printf("p is %s \n",p); 
    return 0; 
} 

और इस कोड को "पी = हैलो"

#include "stdio.h" 
#include "string.h" 
#include "stdlib.h" 
int main() { 
    char *p; 
    p=(char*)malloc (10); 
    strcpy(p,"hello"); 
    printf("p is %s \n",p); 
    return 0; 

का उत्पादन }

उत्तर

10

मामले में जहां p="hello world"; (टी पर पहला मामला वह इस संपादन का समय), p को को केवल स्मृति क्षेत्र को इंगित करने के लिए प्रारंभ किया जा रहा है जिसमें स्ट्रिंग "हैलो वर्ल्ड" (स्ट्रिंग शाब्दिक) है। यह केवल पढ़ने के लिए स्मृति क्षेत्र संकलित समय पर बनाया गया है।

मामले कि विभाजन गलती (यदि संपादन के समय में 2 मामले) का कारण बनता है में, p अप्रारंभीकृत है और यह करने के लिए कुछ भी कॉपी करने अप्रत्याशित परिणाम क्योंकि स्मृति में स्थान कि p इशारा कर रही है करने के लिए द्वारा निर्दिष्ट नहीं है का उत्पादन करेगा कोड।

इससे पहले कि आप स्ट्रिंग को p पर कॉपी कर सकें, आपको उस स्मृति को निर्दिष्ट करना होगा जो p इंगित कर रहा है।

आप ढेर

char *buf = malloc(BUFSIZ); /* don't forget to free */

पर या __DATA सेगमेंट में ढेर

char buf[BUFSIZ] = ""; /* local variable */

पर इस स्मृति को आबंटित कर सकते हैं।

static char buf[BUFSIZ] = ""; /* global variable */

फिर आप स्मृति बफर में बात करने के लिए p प्रारंभ कर सकते हैं।

char *p = buf;

यह p आरंभ स्ट्रिंग केवल पढ़ने के लिए स्मृति में शाब्दिक को इंगित करने के लिए अवधारणा में इसी तरह की है। उस मामले के विपरीत जहां p स्ट्रिंग शाब्दिक को इंगित करता है, अब आप एक स्ट्रिंग को चरित्र सूचक में कॉपी कर सकते हैं क्योंकि यह को केवल मेमोरी को इंगित नहीं करता है।

नोट: मैंने जानबूझकर एक अलग बफर बनाया और p शुरू किया ताकि यह मेरी बात बनाने में मदद के लिए इंगित किया जा सके।

+0

फिर, यह क्यों काम करेगा? # शामिल # शामिल पूर्णांक main() { चार * p; पी = "हैलो वर्ल्ड"; printf ("पी% s \ n", पी); वापसी 0; } आउटपुट: पी हैलो वर्ल्ड – aks

+3

आप पहले पी में कुछ भी नहीं कर रहे हैं। आप उस स्ट्रिंग का पता शाब्दिक पी को संबोधित कर रहे हैं। यही कारण है कि यह काम करता है। – Amy

+0

पी के लिए शाब्दिक स्ट्रिंग का पता निर्दिष्ट करके, आप स्मृति में उस स्थान को निर्दिष्ट कर रहे हैं जो पी इंगित कर रहा है। – jschmier

2

कोई मुफ्त भोजन नहीं है - आपको & मेमोरी प्रबंधित करने की आवश्यकता है। यदि आप बस मानते हैं कि आपके पास पॉइंटर मेमोरी तक पहुंच है तो वहां अनिश्चित व्यवहार (संभवतः segfault) में भाग लेंगे।

5

कारण यह है कि जब आप एक सूचक घोषित करते हैं, तो यह वास्तव में उपयोगी कुछ भी इंगित नहीं करता है। स्ट्रिंग के लिए strcpy को स्मृति की एक ब्लॉक की आवश्यकता होती है। यह आपके लिए स्वचालित रूप से ऐसा नहीं करेगा।

प्रलेखन (जोर मेरा) से

:

प्रतियां सी स्ट्रिंग सरणी समाप्त अशक्त चरित्र सहित गंतव्य, द्वारा बताया में स्रोत से इशारा किया।

अतिप्रवाह से बचने के लिए सरणी गंतव्य से बताया के आकार काफी लंबे समय स्रोत के रूप में एक ही सी स्ट्रिंग ( अशक्त चरित्र समाप्त करना शामिल) को रोकने के लिए किया जाएगा, और के साथ स्मृति में ओवरलैप नहीं करना चाहिए स्रोत।

आपको यह सच करने की आवश्यकता है, क्योंकि यह फ़ंक्शन की पूर्व शर्त है।

इसके अलावा, पैरामीटर खंड में:

गंतव्य

Pointer to the destination array where the content is to be copied. 

तुम्हें यकीन destination बनाने की जरूरत है एक सरणी के लिए सूचक है।

+4

"जब आप एक सूचक घोषित करते हैं, तो यह वास्तव में कुछ भी इंगित नहीं करता है - केवल नल" असल में यह कहीं भी इंगित कर सकता है। Uninitialized मतलब नहीं है 0. – sepp2k

+0

@ sepp2k: धन्यवाद, यह थोड़ी देर हो गया है क्योंकि मैंने किसी भी सी/सी ++ को कोड किया है। फिक्स्ड। – danben

2

क्योंकि पहले उदाहरण में पॉइंटर p में कुछ यादृच्छिक कचरा होता है जो उस समय ढेर पर होता है, शून्य हो सकता है, कुछ और हो सकता है, इसलिए यह इंगित करता है ... कोई भी नहीं जानता कि आपका कोड सेगमेंट कहां है , उदाहरण के लिए। ओएस सही काम करता है और आपको बताता है कि आप नियम तोड़ रहे हैं और स्मृति में लिखने की कोशिश कर रहे हैं जो आपके नहीं हैं। the fine description of segmentation faults here पढ़ें।

आप संकलन समय पर स्रोत स्ट्रिंग के आकार पता है कि तुम पूरी तरह से गतिशील स्मृति आवंटन और से बचना चाहते हैं तो आप इस तरह उचित ढेर अंतरिक्ष हड़पने कर सकते हैं:

char buffer[6]; /* strlen("hello") + 1 for zero terminator */ 
strcpy(buffer, "hello"); 

लेकिन यह एक खतरनाक है सड़क buffer overruns की ओर अग्रसर है।

1

स्मृति प्रतिलिपि में दो अलग-अलग हिस्सों हैं। सबसे पहले उस आइटम द्वारा कब्जा कर लिया गया है जिसे आप प्रतिलिपि बनाना चाहते हैं (जिसे आप malloc() फ़ंक्शन का उपयोग करके अपने उदाहरण में बनाते हैं), और दूसरा स्मृति के उस ब्लॉक (जिसे आप पी कहते हैं) के लिए एक सूचक है। एक प्रतिलिपि करने से पहले, इन दो इकाइयों को गंतव्य के लिए भी स्थापित किया जाना चाहिए। आपके पहले उदाहरण में विफल रहता है, आपके पास नहीं गंतव्य के लिए मेमोरी ब्लॉक सेट अप करता है (लेकिन यह स्ट्रिंग hello स्ट्रिंग घोषित करते समय स्रोत के लिए निश्चित रूप से सेट किया गया है)।

1

हां यह कष्टप्रद है। आप इसे कम करने के लिए strdup उपयोग कर सकते हैं:

char *p = strdup("hello"); 
printf("p is %s \n",p); 
2

सूचना क्या दो कार्य करने वाले उदाहरणों में क्या समानता है: वे एक p = लाइन है कि p के लिए कुछ प्रदान करती है की है। गैर-कामकाजी उदाहरण ऐसा नहीं करता है।

p = "hello world"; 

हालांकि यह ऐसा लगता है जैसे "एक चार सूचक के लिए एक स्ट्रिंग को कॉपी" है लग सकता है, यह नहीं है:

इस लाइन (पहला उदाहरण से) पर विचार करें। यह की स्थिति को एक पॉइंटर-टू-चार के लिए एक स्ट्रिंग की प्रतिलिपि बना रहा है। p स्टोर्स जैसे पॉइंटर-टू-char क्या है - char एस के एक संगत ब्लॉक का स्थान।

इसी प्रकार, तीसरी उदाहरण से इस लाइन पर विचार करें:

p = malloc(10); 

यह भी एक स्थान को प्रतिलिपि है - यह p में 10 unintialised char रों के एक ब्लॉक के स्थान को प्रतिलिपि है।

strcpy(dest, source) द्वारा दिए गए स्थान से dest पर दिए गए स्थान से वर्णों की प्रतियां कॉपी करता है। यह स्पष्ट होना चाहिए कि यदि आपने किसी वैध स्थान पर p सेट नहीं किया है, तो strcpy(p, "hello") कुछ भी समझदार नहीं कर सकता - आपके दूसरे उदाहरण में, p एक अनिवार्य रूप से यादृच्छिक स्थान है, और फिर आप उस स्थान पर कुछ कॉपी करने के लिए strcpy() से पूछें।

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