क्या C में तार के तार को संशोधित करना संभव है?


81

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

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

तो क्या सूचक पतों के बजाय स्ट्रिंग्स के अंदर मूल्यों को बदलने का कोई तरीका है?

जवाबों:


158

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

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

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

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

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


12
अंतिम खंड ने मुझे बहुत कुछ समझाया कि क्यों इसे आसानी से पढ़ने की आवश्यकता है। धन्यवाद।
सीडीआर

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

मुझे नहीं लगता कि आपको मेरे द्वारा दिए गए दो समाधानों के लिए कास्ट की आवश्यकता नहीं है - यदि स्ट्रिंग को संकलित समय पर जाना जाता है, और निष्पादन योग्य में संकलित किया जाता है - तो इसे कहां संग्रहीत किया जाएगा? Gcc में, यदि मैं या तो char * a = "hallo" लिखता हूँ; या चार बी [] = "हैलो।"; तब विधानसभा आउटपुट "LC0: .ascii" हैलो। ?
कार्सन मायर्स

1
बस जीसीसी 4.4 के साथ प्रयास किया गया, यह (। केवल डेटा) में शाब्दिक तार डालता है। मैंने objdump और विधानसभा सूची के साथ जाँच की। मुझे नहीं लगता कि मानक को केवल पढ़ने के लिए शाब्दिक तार की आवश्यकता होती है , इसलिए मुझे लगता है कि वे भी डाटाटा में डाल सकते हैं।
बैस्टियन लेओनर्ड

इसके अलावा, मुझे पॉइंटर को कांस्टेबल के रूप में अर्हता प्राप्त नहीं करने में कोई फायदा नहीं दिखता है। यदि आप बाद में स्ट्रिंग को बदलने का निर्णय लेते हैं तो यह बग को छिपा सकता है।
बास्टियन लेओनार्ड

29

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

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


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

15

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

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

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


7

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


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

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

5

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

c99 मानक (पीडीएफ) [पेज 130, खंड 6.7.8]:

घोषणा:

"सादा" वर्ण सरणी वस्तुओं को परिभाषित करता है और जिनके तत्व वर्ण स्ट्रिंग शाब्दिक के साथ आरंभीकृत होते हैं। यह घोषणा चार के समान है

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

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


4

आप यह भी उपयोग कर सकते हैं strdup:

आपके लिए उदाहरण:


सवाल का जवाब नहीं है, लेकिन अभी भी एक बहुत ही आसान कार्य, धन्यवाद!
mknaf

1
मुझे सिखाने के लिए +1 strdup। मुझे यकीन नहीं है कि मैं इसका उपयोग कब करना चाहूंगा।
Z बोसॉन

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

3

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

मैंने इसे कब्ज़-शुद्धता पर अपने कुछ गहरे विचारों के हिस्से के रूप में लिखा है , जो आपको दिलचस्प लग सकता है (मुझे आशा है कि :))।

आशा है कि इससे सहायता मिलेगी। शुभ लाभ!


ध्यान दें कि एक स्ट्रिंग शाब्दिक बदलना अपरिभाषित व्यवहार है।
स्टोहन

0

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

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


0

6
मॉलॉक को 1 और बाइट की जरूरत है। NULL टर्मिनेशन कैरेक्टर को न भूलें, जो कि बहुत ज्यादा उम्मीद करता है, और कॉपी भी करेगा। यह एक बहुत अधिक बार-बार की जाने वाली गलती है।
xcramps
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.