स्कैनफ के साथ एक स्ट्रिंग पढ़ना


147

मैं किसी बात को लेकर थोड़ा भ्रमित हूं। मैं इस धारणा के अधीन था कि C स्ट्रिंग को पढ़ने का सही तरीका क्या हैscanf() तर्ज पर है

(कभी भी संभव बफर अतिप्रवाह मन नहीं है, यह सिर्फ एक सरल उदाहरण है)

char string[256];
scanf( "%s" , string );

हालाँकि, निम्नलिखित भी काम करने लगता है,

scanf( "%s" , &string );

क्या यह सिर्फ मेरा संकलक (जीसीसी), शुद्ध भाग्य, या कुछ और है?


दूसरे मामले में, वास्तव में कोई भी संभावित बफर अतिप्रवाह नहीं है, क्योंकि आप उस बफर का उपयोग बिल्कुल नहीं कर रहे हैं। या तो वह, या आप कह सकते हैं कि 3 वर्णों से बड़ा कोई भी तार आपके "बफर" को ओवरफ्लो करेगा।
TED

मैं पहले उदाहरण की बात कर रहा था। इसके अलावा, अन्य लोगों ने पहले ही बताया है कि यहाँ क्या हो रहा है।
abeln

हाँ। यह कोशिश की, और गैरेथ सही है। अजीब।
TED

चूँकि यह प्रश्न "स्कैनफ़ के साथ एक स्ट्रिंग को कैसे पढ़ा जाए" के लिए खोजों द्वारा लौटाया गया है, इसलिए यह इंगित करना उचित हो सकता है कि यह प्रश्न सूचक को बफर को पास करने के तरीकों के बारे में है scanf, और प्रश्न और स्वीकृत उत्तर दोनों पर ध्यान केंद्रित करता है कि, और अधिकतम इनपुट लंबाई के लिए महत्वपूर्ण रूप से महत्वपूर्ण प्रतिबंधों को छोड़ दें जिन्हें वास्तविक कोड में उपयोग किया जाना चाहिए (लेकिन इस प्रश्न के लिए बिंदु के अलावा)।
अरक्कू

जवाबों:


141

एक सरणी अपने पहले तत्व के लिए एक पॉइंटर में "डिकेज" करता है, इसलिए scanf("%s", string)इसके बराबर है scanf("%s", &string[0])। दूसरी ओर, scanf("%s", &string)एक पॉइंटर-टू-char[256] टू , लेकिन यह उसी स्थान पर इंगित करता है।

फिर scanf, अपनी तर्क सूची की पूंछ को संसाधित करते समय, एक खींचने की कोशिश करेंगे char *। यही कारण है कि सही काम है जब आप में पारित कर दिया गया है stringया &string[0]है, लेकिन जब आप में पारित कर दिया गया है &stringआप कुछ के आधार पर की जा रही भाषा मानक है कि नहीं गारंटी, अर्थात् है कि संकेत &stringऔर&string[0] - संकेत दिए गए विभिन्न प्रकार और आकार की वस्तुओं के लिए कि एक ही स्थान पर शुरू - उसी तरह से दर्शाया जाता है।

मुझे विश्वास नहीं होता कि मैंने कभी ऐसी प्रणाली का सामना किया है जिस पर काम नहीं होता है, और व्यवहार में आप शायद सुरक्षित हैं। कोई भी कम नहीं, यह गलत है, और यह कुछ प्लेटफार्मों पर विफल हो सकता है। (हाइपोथेटिकल उदाहरण: एक "डिबगिंग" कार्यान्वयन जिसमें प्रत्येक सूचक के साथ प्रकार की जानकारी शामिल है। मुझे लगता है कि प्रतीक "लिस्प मशीन" पर सी कार्यान्वयन ने कुछ ऐसा किया।)


5
+1। यह सत्यापित करने के लिए भी तुच्छ है कि सरणी क्षय परिणाम के &stringरूप में ही काम करता है string(यादृच्छिक स्मृति भ्रष्टाचार में जिसके परिणामस्वरूप, अन्य उत्तरों के रूप में गलत तरीके से मुखर):printf("%x\n%x\n", string, &string);
जोश केली

@ जोश केली दिलचस्प है, मैं इसे तब ले जाऊंगा कि यह पॉइंटर के साथ मॉलोक () के माध्यम से आवंटित स्ट्रिंग के मामले में नहीं होगा?
abeln

4
@ वेबन: सही। Malloc () के माध्यम से आवंटित स्ट्रिंग के लिए, stringएक पॉइंटर है, और &stringउस पॉइंटर का पता है, इसलिए दोनों परस्पर विनिमय करने योग्य नहीं हैं। जैसा कि गेरेथ बताते हैं, यहां तक ​​कि सरणी क्षय के मामले के लिए, stringऔर &stringतकनीकी रूप से समान प्रकार नहीं हैं (भले ही वे अधिकांश आर्किटेक्चर के लिए विनिमेय होने के लिए होते हैं), और यदि आप चालू करते हैं तो gcc आपके दूसरे उदाहरण के लिए एक चेतावनी देगा -Wall
जोश केली

@ जोश केली: धन्यवाद, मुझे खुशी है कि मैं इस पर अपना मन साफ ​​कर सका।
abeln

1
@JCooper str, और str [0] दोनों एक ही चीज़ (सरणी की शुरुआत) का प्रतिनिधित्व करते हैं, और हालांकि जरूरी नहीं कि & str भी एक ही मेमोरी एड्रेस हो। अब strPtr, str को इंगित करता है, इसलिए strPtr के अंदर संग्रहीत मेमोरी एड्रेस, str और thats 12fe60 के समान है। अंत में और strPtr चर strPtr का पता है, यह strptr में मूल्य भंडार नहीं है, लेकिन strPtr का वास्तविक मेमोरी पता है। चूंकि स्ट्रैप्टर अन्य सभी की तुलना में एक भिन्न चर है, इसलिए इसका एक अलग मेमोरी एड्रेस भी है, इस मामले में 12fe54
जुआन बेसा

-9

मुझे लगता है कि यह नीचे सटीक है और इससे मदद मिल सकती है। यदि आपको कोई त्रुटि मिलती है तो इसे ठीक करने के लिए स्वतंत्र महसूस करें। मैं C पर नया हूं।

char str[]  
  1. स्मृति में अपने स्वयं के पते के साथ प्रकार चार के मूल्यों की सरणी
  2. स्मृति में अपने स्वयं के पते के साथ प्रकार चार के मूल्यों की सरणी, सरणी में तत्वों के रूप में लगातार कई पते
  3. समाप्ति शून्य वर्ण सहित '\0' &str, &str[0]और str, तीनों स्मृति में एक ही स्थान का प्रतिनिधित्व करते हैं जो कि सरणी के पहले तत्व का पता हैstr

    char * strPtr = & str [0]; // घोषणा और आरंभीकरण

वैकल्पिक रूप से, आप इसे दो में विभाजित कर सकते हैं:

char *strPtr; strPtr = &str[0];
  1. strPtr एक के लिए एक सूचक है char
  2. strPtr सरणी में अंक str
  3. strPtr स्मृति में अपने स्वयं के पते के साथ एक चर है
  4. strPtr एक चर है जो पते के मूल्य को संग्रहीत करता है &str[0]
  5. strPtr स्मृति में स्वयं का पता उस मेमोरी एड्रेस से अलग होता है जिसे वह स्टोर करता है (मेमोरी एरा और अरै में सरणी का पता [0])
  6. &strPtr खुद स्ट्रैप के पते का प्रतिनिधित्व करता है

मुझे लगता है कि आप एक पॉइंटर को पॉइंटर घोषित कर सकते हैं:

char **vPtr = &strPtr;  

घोषित करता है और strPtr सूचक के पते के साथ आरंभ करता है

वैकल्पिक रूप से आप दो में विभाजित कर सकते हैं:

char **vPtr;
*vPtr = &strPtr
  1. *vPtr strPtr पॉइंटर पर अंक
  2. *vPtr स्मृति में अपने स्वयं के पते के साथ एक चर है
  3. *vPtr एक वैरिएबल है जो एड्रेस और स्ट्रैप के मूल्य को स्टोर करता है
  4. अंतिम टिप्पणी: आप नहीं कर सकते str++, strपता एक है const, लेकिन आप कर सकते हैंstrPtr++
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.