यह फ़ंक्शन एक स्ट्रिंग की सही लंबाई क्यों लौटाता है? (एक चार्ट पॉइंटर में वृद्धि)


12

यह एक फ़ंक्शन है जो एक स्ट्रिंग में वर्णों की संख्या को गिनता है:

int str_len(const char* s) {
    int i = 0;
    while(*(s++)) {
        i++;
    }
    return i;
}

यह सही लंबाई क्यों लौटाता है?

मान लीजिए कि मैं इस फ़ंक्शन को एक साधारण स्ट्रिंग के साथ कहता हूं "a"। तब s, जबकि पाश में वृद्धि की जाती इसलिए का मूल्य है sऔर iदोनों 0 कर रहे हैं।

जवाबों:


10

मूल्य का s++मूल मूल्य है s, वेतन वृद्धि से पहले, वृद्धि अगले अनुक्रम बिंदु से पहले अनिर्दिष्ट समय पर होती है।

इसलिए *s++और *(s++)समतुल्य हैं: वे दोनों मूल मूल्य को कम करते हैं s। एक और समकक्ष अभिव्यक्ति है *(0, s++), दिल के बेहोश होने के लिए नहीं, यह एक है:0[s++]

ध्यान दें कि आपके फ़ंक्शन को इसके और इसके प्रकार size_tके प्रकार का उपयोग करना चाहिए i:

size_t str_len(const char *s) {
    size_t i = 0;
    while (*s++) {
        i++;
    }
    /* s points after the null terminator */
    return i;
}

यहां प्रति लूप एकल वेतन वृद्धि के साथ संभावित रूप से अधिक कुशल संस्करण है:

size_t str_len(const char *s) {
    const char *s0 = s;
    while (*s++) {
        /* nothing */
    }
    return s - 1 - s0;
}

दूसरे पैराग्राफ में अजीब भावों के बारे में सोचने वालों के लिए:

  • 0, s++अल्पविराम ऑपरेटर का एक उदाहरण है जो ,इसके बाएं हिस्से का मूल्यांकन करता है, फिर इसका दाहिना हिस्सा जो इसके मूल्य का गठन करता है। इसलिए (0, s++)के बराबर है (s++)

  • 0[s++]के बराबर है (s++)[0]और *(0 + s++)या *(s++ + 0)जो सरल है *(s++)। सूचक और इंडेक्स एक्सप्रेशन को भावों में []बदलना बहुत सामान्य नहीं है और न ही विशेष रूप से उपयोगी है, लेकिन सी मानक के अनुरूप है।


यकीन है कि अल्पविराम ऑपरेटर स्पष्ट था। दूर करो , s++और बुरी चीजें होंगी:)
डेविड सी। रैनकिन

6

मान लें कि मैं इस फ़ंक्शन को एक साधारण स्ट्रिंग "ए" के साथ कहता हूं। तब s लूप में वृद्धि होती है इसलिए s का मान 0 होता है I i भी 0 होता है।

उस उदाहरण में, को sइंगित करता 'a'है "a"। फिर यह बढ़ा हुआ iभी है और बढ़ा हुआ भी है। अब sशून्य टर्मिनेटर को इंगित करें, और iहै 1। तो पाश के माध्यम से अगले समय में, *(s++)है '\0'(जो 0), तो पाश समाप्त होता है, और के वर्तमान मूल्य i(के कि 1) दिया जाता है।

आमतौर पर, लूप स्ट्रिंग में प्रत्येक वर्ण के लिए एक बार चलता है, और फिर नल टर्मिनेटर पर रुक जाता है, इसलिए यह वर्णों को गिनता है।


क्योंकि s कोष्ठक में है, मैंने सोचा था कि इसे पहले बढ़ाया जाएगा (इसलिए अब यह '/ 0' की ओर इशारा करता है)। इसलिए जबकि लूप झूठा है और मैं कभी भी बढ़ा नहीं हूं।
लॉर

2
@lor, याद क्या postincrement ऑपरेटरों: यह जो कुछ भी करने के लिए मूल्यांकन करता sआयोजित पहले incrementing। आप जो वर्णन कर रहे हैं, वह है व्यवहार ++s(जो वास्तव में एक-एक करके रेखांकित होगा, और खाली स्ट्रिंग पारित होने पर यूबी आह्वान करेगा)।
टोबी स्पाइट

2

यह सही समझ में आता है:

int str_len(const char* s) {
    int i = 0;
    while(*(s++)) { //<-- increments the pointer to char till the end of the string
                    //till it finds '\0', that is, if s = "a" then s is 'a'
                    // followed by '\0' so it increments one time
        i++; //counts the number of times the pointer moves forward
    }
    return i;
}

"लेकिन sकोष्ठक में है। इसीलिए मैंने सोचा कि इसे पहले बढ़ाया जाएगा"

ठीक यही कारण है कि पॉइंटर को इंक्रीमेंट किया जाता है और कैरेक्टर को नहीं, आइए आपको बताते हैं कि (*s)++इस मामले में कैरेक्टर को इंप्रूव किया जाएगा न कि पॉइंटर को। डेरेफेरिंग का अर्थ है कि अब आप पॉइंटर द्वारा संदर्भित मूल्य के साथ काम कर रहे हैं, न कि पॉइंटर ही।

चूंकि दोनों संचालकों में एक ही तरह का पूर्वाग्रह है, लेकिन दाएं-से-बाएं समरूपता है तो आप *s++पॉइंटर को बढ़ाने के लिए बिना किसी कोष्ठक के भी उपयोग कर सकते हैं ।


लेकिन एस कोष्ठक में है। इसलिए मैंने सोचा कि पहले इसे बढ़ा दिया जाएगा। (यदि हमारे पास एक सरल स्ट्रिंग है जैसे "ए" अब इंगित करेगा "/ 0")। क्योंकि हालत अब (0) है, जबकि लूप में कभी प्रवेश नहीं किया जाता है।
lor

2

पोस्ट इंक्रीमेंट ऑपरेटर ऑपरेंड के मूल्य को 1 से बढ़ाता है लेकिन एक्सप्रेशन का मूल्य इंक्रीमेंट ऑपरेशन से पहले ऑपरेंड का मूल मूल्य है।

मान लिया गया है कि तर्क दिया गया str_len()है "a"। में str_len(), सूचक sस्ट्रिंग के पहले वर्ण की ओर इशारा करता है "a"। में whileपाश:

while(*(s++)) {
.....
.....

हालाँकि sवसीयत की जाएगी, लेकिन अभिव्यक्तिs में मूल्य उस चरित्र के लिए सूचक होगा जो वह वेतन वृद्धि से पहले इंगित कर रहा है, जो कि पहले चरित्र का सूचक है । जब पॉइंटर को डिफाइन किया जाता है, तो यह कैरेक्टर देगा । अगले पुनरावृत्ति में, सूचक अगले वर्ण की ओर इशारा करेगा जो कि अशक्त वर्ण है । जब डिफरेंस किया जाता है, तो यह दिया जाएगा और लूप बाहर निकल जाएगा। ध्यान दें कि, अब स्ट्रिंग के अशक्त वर्ण को एक तत्व की ओर इंगित करेगा ।'a's'a's\0s0s"a"

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.