2009-06-18 16 views
52

मैं कुछ घंटों के लिए ट्यूटोरियल से संबंधित सी ट्यूटोरियल और किताबों के साथ संघर्ष कर रहा हूं लेकिन मैं वास्तव में जानना चाहता हूं कि यह बनने के बाद एक बार पॉइंटर बदलना संभव है।सी में चार की स्ट्रिंग को संशोधित करना संभव है?

यह है कि मैं क्या करने की कोशिश की है:

char *a = "This is a string"; 
char *b = "new string"; 

a[2] = b[1]; // Causes a segment fault 

*b[2] = b[1]; // This almost seems like it would work but the compiler throws an error. 

तो वहाँ तार के बजाय सूचक पतों के अंदर मूल्यों को बदलने के लिए किसी भी तरह से है?

धन्यवाद

संपादित करें:

धन्यवाद अपने जवाब के लिए हर किसी को। यह अब और अधिक समझ में आता है। यह विशेष रूप से समझ में आता है कि कभी-कभी यह ठीक काम क्यों कर रहा था और दूसरी बार काम नहीं कर रहा था। क्योंकि कभी-कभी मैं एक चार पॉइंटर पास करता हूं और दूसरी बार एक चार सरणी (चार सरणी ठीक काम करती है)।

उत्तर

110

जब आप अपने स्रोत कोड में "स्ट्रिंग" लिखते हैं, तो यह सीधे निष्पादन योग्य में लिखा जाता है क्योंकि उस मान को संकलित समय पर जाना आवश्यक है (सॉफ़्टवेयर को अलग करने और सभी को खोजने के लिए टूल उपलब्ध हैं उनमें सादे पाठ तार)। जब आप char *a = "This is a string" लिखते हैं, तो "यह एक स्ट्रिंग" का स्थान निष्पादन योग्य है, और स्थान को इंगित करने योग्य स्थान पर है। निष्पादन योग्य छवि में डेटा केवल पढ़ने के लिए है।

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

char a[] = "This is a string"; 

तुम भी कॉपी कर सकते हैं कि डेटा मैन्युअल रूप से ढेर पर कुछ स्मृति आवंटन, और फिर एक स्ट्रिंग है कि अंतरिक्ष में शाब्दिक कॉपी करने के लिए strcpy() का उपयोग करके।

char *a = malloc(256); 
strcpy(a, "This is a string"); 

जब भी आप का उपयोग कर malloc()free() कॉल करने के लिए याद है जब आप इसे (: स्मृति रिसाव पढ़ें) के साथ समाप्त कर अंतरिक्ष का आवंटन।

असल में, आपको यह ट्रैक रखना होगा कि आपका डेटा कहां है। जब भी आप अपने स्रोत में एक स्ट्रिंग लिखते हैं, तो वह स्ट्रिंग केवल पढ़ने के लिए होती है (अन्यथा आप निष्पादन योग्य के व्यवहार को संभावित रूप से बदल देंगे - कल्पना करें कि आपने char *a = "hello"; लिखा है और फिर a[0] से 'c' बदल दिया है। फिर कहीं और printf("hello"); लिखा गया था। "hello" का पहला वर्ण बदलने के लिए, और अपने संकलक केवल एक बार संग्रहीत (यह होना चाहिए), तो printf("hello"); उत्पादन cello!)

+10

अंतिम खंड ने मुझे बहुत कुछ समझाया कि इसे क्यों पढ़ा जाना चाहिए। धन्यवाद। – CDR

+1

-1: कॉन्स्ट char * का उपयोग करने के लिए नहीं कहता है, और कुछ भी गारंटी नहीं देता है कि शाब्दिक तार निष्पादन योग्य स्मृति में संग्रहीत हैं। –

+0

मुझे आपको दिए गए दो समाधानों के लिए कॉन्स की आवश्यकता नहीं है - अगर स्ट्रिंग को संकलित समय पर जाना जाता है, और निष्पादन योग्य में संकलित किया जाता है - यह कहां संग्रहीत होगा? जीसीसी में, अगर मैं या तो चार * ए = "हेलो" लिखता हूं; या char b [] = "हैलो।" ;, फिर असेंबली आउटपुट "एलसी 0: \t .ascii" हेलो। \ 0 " एलसी 1: \t .ascii" हैलो। \ 0 "" दोनों निष्पादन योग्य स्मृति में हैं .. यह कब नहीं है? –

0

आपको स्ट्रिंग को दूसरे में कॉपी करने की आवश्यकता है, न केवल पढ़ने के लिए मेमोरी बफर और इसे संशोधित करें। नई स्ट्रिंग के लिए गतिशील रूप से आवंटित करने के लिए स्ट्रिंग लम्बाई, malloc() और free() का पता लगाने के लिए स्ट्रिंग, strlen() को कॉपी करने के लिए strncpy() का उपयोग करें।

उदाहरण के लिए (सी ++ स्यूडोकोड की तरह):

int stringLength = strlen(sourceString); 
char* newBuffer = malloc(stringLength + 1); 

// you should check if newBuffer is 0 here to test for memory allocaton failure - omitted 

strncpy(newBuffer, sourceString, stringLength); 
newBuffer[stringLength] = 0; 

// you can now modify the contents of newBuffer freely 

free(newBuffer); 
newBuffer = 0; 
19

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

char a[] = "This is a string"; 

या वैकल्पिक रूप से, आप malloc का उपयोग कर स्मृति आवंटित कर सकते हैं उदा।

char *a = malloc(100); 
strcpy(a, "This is a string"); 
free(a); // deallocate memory once you've done 
+3

कोड के पूरा होने के लिए, यह आप भी मुक्त() कॉल में जोड़ सकते हैं, तो अच्छा होगा। – Naveen

5

& बी के लिए स्मृति आपके द्वारा आवंटित नहीं की गई है। संकलक पात्रों को संग्रहीत करने के लिए केवल पढ़ने के लिए स्मृति स्थान चुनने के लिए स्वतंत्र है। तो यदि आप इसे बदलने की कोशिश करते हैं तो परिणामस्वरूप सीजी गलती हो सकती है। तो मैं आपको एक चरित्र सरणी बनाने के लिए सुझाव देता हूं। कुछ ऐसा: char a[10]; strcpy(a, "Hello");

+1

चरित्र सरणी के साथ समस्या यह है कि मैं एक फ़ंक्शन में एक चार सरणी का पॉइंटर पास कर रहा हूं ताकि मैं वहां एक स्ट्रिंग में हेरफेर कर सकूं और फिर इसे फिर से भेज सकूं। ऐसा लगता है कि मुझे दुर्भाग्यवश मॉलोक का उपयोग करना है। –

+0

आप किसी फंक्शन को स्वीकार करने वाले फ़ंक्शन को सरणी पास कर सकते हैं। –

+0

नहीं, आप अभी भी स्टैक पर आवंटित ऑब्जेक्ट का उपयोग कर सकते हैं। उदाहरण के लिए यदि आपके पास फ़ंक्शन शून्य एफ (char * p) है; फिर मुख्य() से आप एफ (ए) पास कर सकते हैं। यह फ़ंक्शन में पहले वर्ण का पता पारित करेगा। इसके अलावा, अगर आप malloc() द्वारा जाने का निर्णय लेते हैं तो मुक्त() का उपयोग करके स्मृति को छोड़ना न भूलें। – Naveen

0
char *a = "stack overflow"; 
char *b = "new string, it's real"; 
int d = strlen(a); 

b = malloc(d * sizeof(char)); 
b = strcpy(b,a); 
printf("%s %s\n", a, b); 
+2

मॉलोक को 1 और बाइट की आवश्यकता है। नल टर्मिनेशन कैरेक्टर को न भूलें, जो स्ट्रैपी उम्मीद करता है, और कॉपी भी करेगा। यह एक बहुत ही लगातार गलती है। – xcramps

7

लोगों का एक बहुत चार * और चार [] के बीच अंतर के बारे में भ्रमित हो जाएगा सी में स्ट्रिंग अक्षर के संयोजन के साथ। जब आप लिखते हैं:

char *foo = "hello world"; 

... आप वास्तव में स्मृति की एक निरंतर ब्लॉक करने के लिए foo ओर इशारा करते हैं (वास्तव में, क्या संकलक इस उदाहरण में "हैलो दुनिया" के साथ करता है कार्यान्वयन पर निर्भर है।)

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

3

ऐसा लगता है कि आपके प्रश्न का उत्तर दिया गया है, लेकिन अब आप सोच सकते हैं कि char * a = "स्ट्रिंग" केवल पढ़ने योग्य स्मृति में क्यों संग्रहीत किया जाता है। खैर, यह वास्तव में c99 मानक से अपरिभाषित छोड़ दी जाती है लेकिन सबसे compilers यह करने के लिए की तरह उदाहरण के लिए इस तरह से चुनें:

printf("Hello, World\n"); 

c99 standard(pdf) [पेज 130, खंड 6.7.8]:

घोषणा:

char s[] = "abc", t[3] = "abc"; 

"सादा" चार सरणी ऑब्जेक्ट्स एस और टी को परिभाषित करता है जिनके तत्व चरित्र स्ट्रिंग अक्षर के साथ प्रारंभ किए जाते हैं। इस घोषणा चार को

s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' }; 

सरणियों की सामग्री को परिवर्तनीय हैं समान है। दूसरी ओर, घोषणा

char *p = "abc"; 

प्रकार के साथ पी को परिभाषित करता है "सूचक चार करने के लिए" और लंबाई 4 जिसका तत्वों एक चरित्र स्ट्रिंग शाब्दिक साथ प्रारंभ कर रहे हैं के साथ प्रकार के साथ "चार की सरणी" एक वस्तु को इंगित करने के लिए इसे initializes पर । यदि सरणी की सामग्री को संशोधित करने के लिए पी का उपयोग करने के लिए प्रयास किया जाता है, तो व्यवहार अपरिभाषित होता है।

1

सभी अच्छे जवाब बता रहे हैं कि आप स्ट्रिंग अक्षर को क्यों संशोधित नहीं कर सकते हैं क्योंकि उन्हें केवल-पढ़ने वाली स्मृति में रखा गया है। हालांकि, जब धक्का ढकने लगता है, तो ऐसा करने का एक तरीका है।

#include <sys/mman.h> 
#include <unistd.h> 
#include <stddef.h> 
#include <string.h> 
#include <stdlib.h> 
#include <stdio.h> 

int take_me_back_to_DOS_times(const void *ptr, size_t len); 

int main() 
{ 
    const *data = "Bender is always sober."; 
    printf("Before: %s\n", data); 
    if (take_me_back_to_DOS_times(data, sizeof(data)) != 0) 
     perror("Time machine appears to be broken!"); 
    memcpy((char *)data + 17, "drunk!", 6); 
    printf("After: %s\n", data); 

    return 0; 
} 

int take_me_back_to_DOS_times(const void *ptr, size_t len) 
{ 
    int pagesize; 
    unsigned long long pg_off; 
    void *page; 

    pagesize = sysconf(_SC_PAGE_SIZE); 
    if (pagesize < 0) 
     return -1; 
    pg_off = (unsigned long long)ptr % (unsigned long long)pagesize; 
    page = ((char *)ptr - pg_off); 
    if (mprotect(page, len + pg_off, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) 
     return -1; 
    return 0; 
} 

मैं my somewhat deeper thoughts on const-correctness का हिस्सा है, जो आपको दिलचस्प लग सकते (मुझे आशा है :)) के रूप में इस में लिखा है: इस उदाहरण देखें।

उम्मीद है कि यह मदद करता है। शुभ लाभ!आप उदाहरण के लिए

The strdup() function returns a pointer to a new string which is a duplicate of the string s. 
    Memory for the new string is obtained with malloc(3), and can be freed with free(3). 

:

2

तुम भी strdup इस्तेमाल कर सकते हैं

char *a = strdup("stack overflow"); 
+0

प्रश्न का उत्तर नहीं है, लेकिन अभी भी एक बहुत ही आसान काम है, धन्यवाद! मुझे 'strdup' के बारे में सिखाने के लिए – mknaf

+0

+1। मुझे यकीन नहीं है कि मैं इसका उपयोग कब करना चाहता हूं। –

+0

जब आप 'var = malloc (strlen (str) + 1) जैसे कुछ करते हैं; strcpy (var, str); ', तो आपको शायद इसके बजाय' strdup' का उपयोग करना चाहिए। –

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