2009-09-21 20 views
7

निम्न कोड पर विचार करें।सी स्ट्रिंग को संशोधित नहीं कर सकता

 
int main(void) { 
    char * test = "abcdefghijklmnopqrstuvwxyz"; 
    test[5] = 'x'; 
    printf("%s\n", test); 
    return EXIT_SUCCESS; 
} 

मेरी राय में, यह abcdexghij प्रिंट करना चाहिए। हालांकि, यह कुछ भी प्रिंट किए बिना समाप्त हो जाता है।

 
int main(void) { 
    char * test = "abcdefghijklmnopqrstuvwxyz"; 
    printf("%s\n", test); 
    return EXIT_SUCCESS; 
} 

हालांकि यह ठीक है, इसलिए मैं सी तार या कुछ और जोड़ तोड़ की अवधारणा गलत था काम करता है? यदि यह महत्वपूर्ण है, तो मै मैक ओएस एक्स 10.6 चला रहा हूं और यह एक 32-बिट बाइनरी है जिसे मैं संकलित कर रहा हूं।

+1

मुझे यह कहने से नफरत है, लेकिन यह वास्तव में सी अकसर पूछे जाने वाले प्रश्नों में होना चाहिए ... इसे पहले से ही स्टैक ओवरफ़्लो पर दसियों या सैकड़ों अन्य बार पूछा गया है। – ephemient

+0

मुझे खेद है अगर इससे पहले पूछा गया था, हालांकि मुझे कोई जवाब नहीं मिला। मैंने वास्तव में फ़ंक्शन संदर्भ और सब कुछ पहले पढ़ा था, लेकिन मुझे वास्तव में नहीं देखा कि मैं क्या गलत कर रहा था। क्या आप मुझे ऐसे सी एफएक्यू के लिए इंगित कर सकते हैं? – fresskoma

+3

@ x3ro: किसी ने आपको 4 वर्षों में सी एफएक्यू के बारे में उत्तर नहीं दिया है ?? [Comp.lang.c अकसर किये गए सवाल] (http://www.c-faq.com/) उत्कृष्ट है। धारा 8 में वर्ण और तार शामिल हैं, और 8.52 प्रश्न पूछने के लिए 8.5 अंक पूछें, जो आपके विशिष्ट प्रश्न को संबोधित करते हैं। –

उत्तर

4

accepted answer अच्छा है, लेकिन पूरा नहीं है।

char * test = "abcdefghijklmnopqrstuvwxyz"; 

एक स्ट्रिंग शाब्दिक (अर्थात यह कार्यक्रम की पूरी निष्पादन के लिए मौजूद है), जहां N स्ट्रिंग की लंबाई के अलावा एक के लिए है स्थिर भंडारण अवधि के साथ प्रकार char[N] की एक अनाम सरणी वस्तु को संदर्भित करता है '\0' को समाप्त करना। यह ऑब्जेक्ट const नहीं है, लेकिन इसे संशोधित करने के किसी भी प्रयास में अपरिभाषित व्यवहार है। (एक कार्यान्वयन अगर यह चुनता है, लेकिन सबसे आधुनिक compilers नहीं स्ट्रिंग शाब्दिक लिखने योग्य बना सकते हैं।)

घोषणा से ऊपर प्रकार char[27] के इस तरह के एक गुमनाम वस्तु बनाता है, और test प्रारंभ करने में उस वस्तु का पहला तत्व के पते का उपयोग करता । इस प्रकार test[5] = 'x' जैसे असाइनमेंट सरणी को संशोधित करने का प्रयास करता है, और व्यवहार को अपरिभाषित करता है; आमतौर पर यह आपके कार्यक्रम को दुर्घटनाग्रस्त कर देगा। (प्रारंभिकरण पते का उपयोग करता है क्योंकि शाब्दिक सरणी प्रकार की अभिव्यक्ति है, जो सरणी के पहले तत्व में सूचक के लिए अधिकांश संदर्भों में निहित रूप से परिवर्तित होता है।)

ध्यान दें कि सी ++ में, स्ट्रिंग अक्षर वास्तव में const हैं, और उपर्युक्त घोषणा अवैध होगी।

const char *test = "abcdefghijklmnopqrstuvwxyz"; 

तो संकलक आपको चेतावनी देगा अगर आप test के माध्यम से सरणी को संशोधित करने का प्रयास: या तो सी या सी ++ में, यह स्थिरांकchar के सूचक के रूप test घोषित करने के लिए सबसे अच्छा है।

(सी स्ट्रिंग अक्षर const ऐतिहासिक कारणों से नहीं हैं। 1 9 8 9 एएनएसआई सी मानक से पहले, const कीवर्ड मौजूद नहीं था। इसे आपके जैसे घोषणाओं में इस्तेमाल करने की आवश्यकता सुरक्षित कोड के लिए बनाई गई होगी, लेकिन इसकी आवश्यकता होगी मौजूदा कोड को संशोधित करने की कोशिश की गई, एएनएसआई कमेटी ने कुछ टालने की कोशिश की। आपको दिखाएं कि स्ट्रिंग अक्षर const हैं, भले ही वे नहीं हैं। यदि आप जीसीसी का उपयोग करते हैं, तो -Wwrite-strings विकल्प कंपाइलर स्ट्रिंग का इलाज करेगा const के रूप में शाब्दिक - जो जीसीसी गैर-अनुरूप बनाता है।)

यदि आपस्ट्रिंग को संशोधित करने में सक्षम होना चाहते हैंकरने के लिए, आप इसे इस प्रकार परिभाषित कर सकते हैं संदर्भित करता है:

char test[] = "abcdefghijklmnopqrstuvwxyz"; 

संकलक प्रारंभकर्ता पर लग रहा है कितना बड़ा test होने की जरूरत है निर्धारित करने के लिए। इस मामले में, testchar[27] प्रकार का होगा। स्ट्रिंग शाब्दिक अभी भी एक अज्ञात ज्यादातर-पढ़ने-योग्य सरणी वस्तु को संदर्भित करता है, लेकिन इसका मान test में कॉपी किया गया है। (एक सरणी ऑब्जेक्ट को प्रारंभ करने के लिए उपयोग किए जाने वाले प्रारंभकर्ता में एक स्ट्रिंग अक्षर एक संदर्भ में से एक है जिसमें एक सरणी एक सूचक को "क्षय" नहीं करती है; अन्य तब होते हैं जब यहया sizeof का संचालन होता है।) क्योंकि आगे नहीं हैं अज्ञात सरणी के संदर्भ, संकलक इसे अनुकूलित कर सकते हैं।

इस मामले में, test स्वयं एक सरणी है जिसमें आपके द्वारा निर्दिष्ट 26 वर्ण हैं, साथ ही '\0' टर्मिनेटर। उस सरणी का जीवनकाल इस बात पर निर्भर करता है कि test घोषित किया गया है, जो इससे कोई फर्क नहीं पड़ता या नहीं। उदाहरण के लिए, यदि आप ऐसा करते हैं:

char *func(void) { 
    char test[] = "abcdefghijklmnopqrstuvwxyz"; 
    return test; /* BAD IDEA */ 
} 

कॉलर को उस चीज़ के लिए सूचक मिलेगा जो अब मौजूद नहीं है। आप दायरे से बाहर सरणी जिसमें test परिभाषित किया गया है का उल्लेख करने की जरूरत है, तो आप इसे static के रूप में परिभाषित कर सकते हैं, या आप malloc का उपयोग कर इसे आवंटित कर सकते हैं:

char *test = malloc(27); 
if (test == NULL) { 
    /* error handling */ 
} 
strcpy(test, "abcdefghijklmnopqrstuvwxyz"; 

तो सरणी अस्तित्व के लिए जब तक आप free() फोन के लिए जारी रहेगा । गैर-मानक strdup() फ़ंक्शन यह करता है (इसे POSIX द्वारा परिभाषित किया गया है लेकिन आईएसओ सी द्वारा नहीं)।

ध्यान से ध्यान दें कि test या तो आप इसे घोषित करने के तरीके के आधार पर एक सूचक या सरणी हो सकते हैं। यदि आप स्ट्रिंग फ़ंक्शन में test पास करते हैं, या किसी भी फ़ंक्शन को char* पर लेते हैं, इससे कोई फर्क नहीं पड़ता है, लेकिन sizeof test जैसे कुछ test एक पॉइंटर या सरणी के आधार पर बहुत अलग व्यवहार करेंगे।

comp.lang.c FAQ उत्कृष्ट है। धारा 8 में वर्ण और तार शामिल हैं, और 8.52 प्रश्न पूछने के लिए 8.5 अंक पूछें, जो आपके विशिष्ट प्रश्न को संबोधित करते हैं। धारा 6 में सरणी और पॉइंटर्स के बीच अक्सर भ्रमित संबंध शामिल होते हैं।

27

प्रारंभिक मान के साथ परिभाषित चार पॉइंटर्स केवल पढ़ने-योग्य खंड में जाते हैं। उन्हें संशोधित करने के लिए, आपको या तो उन्हें ढेर पर बनाना होगा (उदा। नए/मॉलोक के साथ) या उन्हें सरणी के रूप में परिभाषित करें।

परिवर्तनीय नहीं:

char * foo = "abc"; 

परिवर्तनीय:

char foo[] = "abc"; 
+0

हूप्स - संपादन के लिए धन्यवाद। – Joe

+1

foo [0] = 'x' अभी भी मेरे बॉक्स – pm100

4

आप initialiser के प्रकार के साथ चर के प्रकार के मिलान की आदत में मिलना चाहिए। इस मामले में:

const char* test = "abcdefghijklmnopqrstuvwxyz"; 

इस तरह आपको रन-टाइम त्रुटि के बजाय एक कंपाइलर त्रुटि मिल जाएगी। अधिकतम तक आपके कंपाइलर चेतावनी स्तर को क्रैंक करने से इस तरह के नुकसान से बचने में भी मदद मिल सकती है। सी में यह कोई त्रुटि क्यों नहीं है शायद ऐतिहासिक है; शुरुआती कंपाइलर्स ने इसे अनुमति दी और भाषा को मानकीकृत होने पर इसे बहुत अधिक मौजूदा कोड तोड़ दिया हो सकता है। अब हालांकि ऑपरेटिंग सिस्टम इसकी अनुमति नहीं देते हैं इसलिए यह अकादमिक है।

3

स्ट्रिंग शब्दकोष संशोधित नहीं हो सकते हैं; यह मानना ​​सबसे अच्छा है कि वे नहीं हैं। अधिक जानकारी के लिए here देखें।

1

कार्य करें:

char * bar = strdup(foo); 
bar[5] = 'x'; 

strdup एक परिवर्तनीय प्रतिलिपि बनाता है।

और हाँ, आपको वास्तव में परीक्षण करना चाहिए कि strdup पूर्ण वापस नहीं आया।

+0

पर segfaults ... और यदि आप strdup() का उपयोग करते हैं तो अंत में मुफ्त (बार)! –

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