2015-11-22 8 views
5

द्वारा स्ट्रिंग बदलें मैं सी ++ में शुरुआत कर रहा हूं और मैं वर्तमान में तारों के साथ काम कर रहा हूं। मेरा प्रश्न यह है कि जब मैं नीचे दिए गए स्क्रिप्ट को संकलित करता हूं, तो मैं स्ट्रिंग के वर्ण प्राप्त कर सकता हूं जब मैं इंडेक्स नोटेशन का उपयोग करता हूं, लेकिन स्ट्रिंग को cout का उपयोग करके स्वयं नहीं प्राप्त कर सकता।सी ++: इंडेक्स

#include <iostream> 
#include <string> 

using namespace std; 

int main() 
{ 
    string original; // original message 
    string altered; // message with letter-shift 

    original = "abc"; 
    cout << "Original : " << original << endl; // display the original message 

    for(int i = 0; i<original.size(); i++) 
     altered[i] = original[i] + 5; 

    // display altered message 
    cout << altered[0] << " " << altered[1] << " " << altered[2] << endl; 
    cout << "altered : " << altered << endl; 

    return 0; 
} 

जब मैं इस स्क्रिप्ट को चलाने, स्ट्रिंग "बदल" में पात्रों इस लाइन के साथ सही ढंग से प्रदर्शित कर रहे हैं:

cout << altered[0] << " " << altered[1] << " " << altered[2] << endl; 

लेकिन स्वयं स्ट्रिंग इस के साथ प्रदर्शित नहीं किया जाता इस कोड है लाइन:

cout << "altered : " << altered << endl; 

मैं जानना चाहता हूं कि ऐसा क्यों होता है।

+1

जबकि आपके पास पहले से ही एक उत्तर है, तो अपने प्रोग्राम में डायग्नोस्टिक्स को सक्षम करने का तरीका जानने का प्रयास करें। आपके पास जो कोड है वह वास्तव में छोटी है, लेकिन सी ++ कंपाइलर्स प्रदान करने वाले डायग्नोस्टिक मोड का उपयोग करके, यह त्रुटि आसानी से पाई जा सकती थी। –

+0

कृपया सभी उत्तरों के माध्यम से अभी जाएं और उस प्रश्न को चिह्नित करें जो आपके प्रश्न का सबसे अच्छा जवाब दे। प्रश्न खोलने के लिए अच्छा नहीं है :-) –

+0

कृपया ध्यान दें कि सी ++ कोड [* स्क्रिप्ट *] नहीं है (https://en.wikipedia.org/wiki/Scripting_language) लेकिन * स्रोत कोड *। लिपियों का अर्थ है और सी ++ स्रोत कोड [संकलित] है (https://en.wikipedia.org/wiki/Compiled_language)। –

उत्तर

5

आप अपने altered स्ट्रिंग आकार दिया पाश से पहले original स्ट्रिंग की लंबाई फिट करने के लिए नहीं किया है, इस प्रकार आपके कोड दर्शाती अपरिभाषित व्यवहार:

altered[i] = original[i] + 5; // UB - altered is empty 

इसे ठीक करने के पाश से पहले altered आकार परिवर्तन:

altered.resize(original.size()); 

या std::string::operator+= या इसी तरह का उपयोग altered में जोड़ने के लिए:

altered += original[i] + 5; 

इस तरह, यह लूप से पहले खाली हो सकता है, यह स्वचालित रूप से संलग्न वर्ण रखने के लिए स्वयं का आकार बदल जाएगा।


स्पष्टीकरण

रास्ता यूबी यहाँ क्या हो रहा है, कि तुम स्थिर सरणी, जो std::string कम स्ट्रिंग अनुकूलन के लिए उपयोग करता है में डेटा लिखने में सफल हो रहे हैं (अगर आप std::string::operator[] कोई भी चेक करता है std::string::size() से पहले इस सरणी को एक्सेस करना), लेकिन std::string::size()0, साथ ही साथ std::string::begin() == std::string::end() बनी हुई है।

कारण है कि आप डेटा को व्यक्तिगत रूप से (फिर यूबी के साथ,) का उपयोग कर सकते है यही कारण है कि:

cout << altered[0] << " " << altered[1] << " " << altered[2] << endl; 

लेकिन cout << aligned कुछ भी प्रिंट नहीं है, पर विचार सरलीकृतstd::string के लिए operator<< परिभाषा लग रहा है कार्यात्मक इस तरह:

std::ostream &operator<<(std::ostream &os, std::string const& str) 
{ 
    for(auto it = str.begin(); it != str.end(); ++it) // this loop does not run 
     os << *it; 

    return os; 
} 

एक वाक्य में, std::string इस बात से अवगत नहीं है कि आपने इसके अंतर्निहित सरणी के साथ क्या किया था और इसका मतलब है कि स्ट्रिंग लंबाई में बढ़ने के लिए है।


इस बदलाव करने का निष्कर्ष करने के लिए, <algoritm> रास्ता:

std::transform(original.begin(), original.end(), 
    std::back_inserter(altered), // or altered.begin() if altered was resized to original's length 
    [](char c) 
    { 
     return c + 5; 
    } 

(आवश्यक शीर्षकों: <algorithm>, <iterator>)

+1

आपको बहुत बहुत धन्यवाद। तो जो आपने सुझाव दिया है वह करके मैं प्रत्येक चरित्र को स्ट्रिंग के अंत में जोड़ता हूं, है ना? – theodor

+0

या आप altered.resize (original.size()) जोड़ सकते हैं; के लिए पहले –

+0

लूप के पहले altered.size() को बदलने के लिए, है ना? आपके उत्तर के लिए धन्यवाद। – theodor

2

अपने कार्यक्रम स्ट्रिंग में altered खाली है। इसमें कोई तत्व नहीं है। इस प्रकार आप के रूप में आप

altered[i] = original[i] + 5; 

कर रहे हैं तो आप नए पात्रों के साथ स्ट्रिंग जोड़ सकते हैं तार का न के बराबर तत्वों का उपयोग करने के सबस्क्रिप्ट ऑपरेटर का उपयोग नहीं कर सकते। इसे करने बहुत सारे तरीके हैं। उदाहरण के लिए

altered.push_back(original[i] + 5); 

या

altered.append(1, original[i] + 5); 

या

altered += original[i] + 5; 

आप तो एक मूल्य निर्दिष्ट करने के लिए इसे range- उपयोग करने के लिए बेहतर है एक खाली स्ट्रिंग के लिए सबस्क्रिप्ट ऑपरेटर के रूप में लागू नहीं हो सकता लूप के लिए आधारित है क्योंकि वास्तव में इंडेक्स का उपयोग नहीं किया जाता है। उदाहरण

for (char c : original) altered += c + 5; 
+0

@ बेंजामिनआर टाइप चार के लिए संदर्भ का उपयोग करने की कोई आवश्यकता नहीं है। संदर्भ के बिना कोड और भी कुशल हो सकता है। –

+0

@ बेंजामिनर आप समझ में नहीं आता कि कंपाइलर्स ऑब्जेक्ट कोड कैसे उत्पन्न करते हैं। –

+0

@ बेंजामिनआर खुद को देखें कि ऑब्जेक्ट कोड किस प्रकार उत्पन्न होगा। –

1

लिए altered का आकार हमेशा शून्य है - अनुक्रमित आप अनुक्रमणिका पर altered को original से मूल्यों को कॉपी करने के लिए कोशिश कर रहे हैं altered नहीं है का उपयोग करके। चूंकि लॉजिकस्टफ ने कहा है, यह अपरिभाषित व्यवहार है - यह त्रुटि उत्पन्न नहीं करता है क्योंकि जब हम std::string के साथ इंडेक्स का उपयोग करते हैं तो हम वास्तव में एक स्ट्रिंग के data फ़ील्ड तक पहुंचने के लिए std::string पर ऑपरेटर को कॉल कर रहे हैं। [] ऑपरेटर का उपयोग C++ मानक में के रूप में परिभाषित किया गया है - इसीलिए कोई त्रुटि नहीं डाली गई थी। सुरक्षित अनुक्रमित उपयोग करने के लिए जिस तरह से at(i) विधि का उपयोग करने के लिए है: altered.at(i) बजाय एक रेंज त्रुटि अगर altered.size() <= i

हालांकि, मैं, क्योंकि यह एक "आधुनिक सी ++" मेरी समाधान के रूप में यह देने के लिए जा रहा हूँ फेंक होगा दृष्टिकोण (प्लस छोटे और पूर्ण)। ,

string original = "abc"; 
string altered = original; 
for (auto& c : altered) c += 5; // ranged for-loop - for each element in original, increase its value by 5 
cout << altered << endl; 

नोट :-)

कोड में काफी कमी यहां तक ​​कि अगर मैं इसे LogicStuff के रास्ते कर रहे थे मैं अभी भी होगा:

यह विकल्प है कि मैं क्या ऊपर दिया गया है करने के लिए क्या करना होगा है

string original = "abc" 
string altered = ""; // this is actually what an empty string should be initialised to. 
for (auto& c : original) altered += (c+5); 

हालांकि, मैं वास्तव में क्योंकि रास्ते से इस दृष्टिकोण की सलाह नहीं देते, push_back() और स्ट्रिंग appending/स्ट्रिंग concatenatio: इस तरह यह है एन काम यह इस छोटे से उदाहरण में ठीक है, लेकिन क्या होगा अगर original एक स्ट्रिंग था जिसे पुस्तक के पहले 10 पृष्ठों को पार्स किया जा सकता था? या क्या होगा यदि यह दस लाख वर्णों का कच्चा इनपुट है?फिर हर बार dataaltered के लिए फ़ील्ड इसकी सीमा तक पहुंच जाती है, इसे सिस्टम कॉल के माध्यम से फिर से आवंटित करने की आवश्यकता होती है और altered की सामग्री कॉपी की जाती है और data फ़ील्ड के लिए पूर्व आवंटन मुक्त हो जाता है। यह एक महत्वपूर्ण प्रदर्शन बाधा है जो original के आकार के सापेक्ष बढ़ता है - यह सिर्फ खराब अभ्यास है। प्रतिलिपि स्ट्रिंग पर आवश्यक समायोजन करने के साथ, यह हमेशा एक पूर्ण प्रतिलिपि करने के लिए और फिर पुन: सक्रिय होगा। यह std::vector पर लागू होता है।

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