2009-09-01 23 views
11

मैं निम्नलिखित कोड मैं सी में उलटे क्रम में एक स्ट्रिंग मुद्रण प्रत्यावर्तन प्रयोग करने के लिए में आए देख रहा था:यह सी कोड कैसे काम करता है?

void ReversePrint(char *str) { //line 1 
    if(*str) {     //line 2 
     ReversePrint(str+1);  //line 3 
     putchar(*str);   //line 4 
    } 
} 

मैं अपेक्षाकृत सेल्सियस के लिए नया हूँ और मेरी समझ से लाइन 2. *str से उलझन में हूँ अपसंदर्भन है सूचक और वर्तमान स्थिति में स्ट्रिंग के मान वापस करना चाहिए। लेकिन यह एक सशर्त बयान के लिए तर्क के रूप में कैसे प्रयोग किया जा रहा है (जो एक बूलियन दाएं को छोड़कर चाहिए?)? लाइन 3 में, सूचक हमेशा अगले ब्लॉक (4 बाइट्स को इसके int के बाद से) में बढ़ाया जाएगा ... तो क्या स्ट्रिंग के अंत के बाद अगली मेमोरी ब्लॉक में डेटा होने पर यह कोड विफल हो सकता है?

अद्यतन: तो सी में कोई बूलियन प्रकार सही नहीं है? एक सशर्त बयान 'झूठा' का मूल्यांकन करता है यदि मूल्य 0 है, और अन्यथा 'सत्य' है?

+8

लड़का, मुझे उम्मीद है कि उत्पादन कोड नहीं था! :) –

+2

आश्चर्य है कि यह शोषण से पहले कितनी देर तक होनी चाहिए। – Skurmedel

+0

शायद बहुत लंबा ... लेकिन फिर भी। – Skurmedel

उत्तर

38

लाइन 2 यह देखने के लिए जांच कर रहा है कि वर्तमान वर्ण स्ट्रिंग का शून्य टर्मिनेटर है - चूंकि सी स्ट्रिंग्स को निरस्त कर दिया गया है, और शून्य चरित्र को गलत मान माना जाता है, यह रिकर्सन को अनियंत्रित करना शुरू कर देगा जब यह हिट करेगा स्ट्रिंग का अंत (नल टर्मिनेटर के बाद चरित्र पर StrReverse4 को कॉल करने का प्रयास करने के बजाय, जो मान्य डेटा की सीमा से परे होगा)।

यह भी ध्यान रखें कि सूचक char पर है, इस प्रकार पॉइंटर को केवल 1 बाइट द्वारा बढ़ाया जाता है (char एक एकल बाइट प्रकार है)।

उदाहरण:

0 1 2 3 
+--+--+--+--+ 
|f |o |o |\0| 
+--+--+--+--+ 
  1. जब str = 0, तो *str'f' तो पुनरावर्ती कॉल str के लिए किया जाता है + 1 = 1.
  2. जब str = 1, तो *str'o' तो है रिकर्सिव कॉल स्ट्र + 1 = 2.
  3. जब str = 2, तोके लिए बनाया गया है'o' तो पुनरावर्ती कॉल str + 1 = 3.
  4. जब str = 3, तो *str'\0' है और \0 एक झूठी मूल्य इस प्रकार if(*str) गलत का आकलन है, इसलिए कोई पुनरावर्ती कॉल किया जाता है, इस प्रकार वापस जाने के लिए किया जाता है हम रिकर्सन प्राप्त करते हैं ...
  5. सबसे हालिया रिकर्सन 'Putchar (' o ') के बाद, उसके बाद
  6. अगला सबसे हालिया रिकर्सन' Putchar ('o') के बाद किया गया था, उसके बाद ,
  7. कम हालिया रिकर्सन 'Putchar (' f ') के बाद किया गया, और हम कर रहे हैं।
+0

प्रतिक्रिया के लिए धन्यवाद .. लेकिन जैसा कि मेरे अपडेट में उल्लिखित है .. क्या आप 'शून्य को झूठा मान माना जाता है' के बारे में विस्तार से बता सकते हैं क्योंकि सी में बुलियन प्रकार नहीं है? –

+5

सी में, कोई बुलियन प्रकार नहीं है, सही - इसके बजाए, तर्क बयान केवल कुछ भी मानते हैं जो 0 को 'झूठी' के रूप में मूल्यांकन करता है, और कुछ भी जो गैर-शून्य को 'सत्य' के रूप में मूल्यांकन करता है। चूंकि "शून्य चरित्र" वास्तव में केवल एक बाइट है जिसका मूल्य 0 है, इसे 'झूठा' माना जाता है। – Amber

+0

उत्कृष्ट स्पष्टीकरण .. धन्यवाद –

2

स्ट्रिंग के अंत में आमतौर पर 0 बाइट होता है - रेखा if (*str) उस बाइट के अस्तित्व की जांच कर रही है और इसे प्राप्त होने पर रोक रही है।

3

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

*str, इस प्रकार, स्ट्रिंग का पहला अक्षर str द्वारा इंगित किया गया है।

(खाली) स्ट्रिंग में समाप्त अशक्त बाइट के लिए falsestr अगर अंक के लिए एक सशर्त मूल्यांकन में *str का उपयोग करना।

1

स्ट्रिंग के अंत में एक 0 है - तो आप "test" => [0]'t' [1]'e' [2]'s' [3]'t' [4]0

और if(0) -> false

इस तरह से यह काम होगा।

1

लाइन 3 में, सूचक हमेशा अगले ब्लॉक करने के लिए वृद्धि की जाती दिया जायेगा (किसी पूर्णांक के बाद से 4 बाइट्स) ...

गलत Thats, इस चार * है, यह केवल वृद्धि की जाएगी 1 तक। क्योंकि चार केवल 1 बाइट लंबा है।

लेकिन यह एक सशर्त कथन के लिए तर्क के रूप में कैसे उपयोग किया जा रहा है (जो एक बूलियन दाएं को छोड़कर चाहिए?)?

आप में अगर ($$) $$ पर, और यह केवल जांच करेगा कि अपने गैर शून्य या नहीं, मूल रूप से bool भी रूप में सरल 1 = सच और 0 = false केवल कार्यान्वित किया जाता है किसी भी मूल्य का उपयोग कर सकते हैं।

अन्य उच्च स्तर पर दृढ़ता से टाइप की गई भाषा में आप ऐसी चीजों का उपयोग नहीं कर सकते हैं, लेकिन सी में सबकुछ संख्याओं तक उबाल जाता है। और आप कुछ भी उपयोग कर सकते हैं।

if(1) // evaluates to true 
if("string") // evaluates to true 
if(0) // evaulates to false 

आप सी में स्थिति

0

सशर्त बयान (if, for, while, आदि) एक बूलियन अभिव्यक्ति की उम्मीद है, जबकि, अगर किसी भी बात कर सकते हैं। यदि आप एक पूर्णांक मान प्रदान करते हैं तो मूल्यांकन 0 == false या non-0 == true तक उबाल जाता है। जैसा कि पहले से उल्लेख किया गया है, सी-स्ट्रिंग का समापनिक चरित्र एक शून्य बाइट (पूर्णांक मान 0) है। तो if स्ट्रिंग के अंत में विफल हो जाएगा (या स्ट्रिंग के भीतर पहले शून्य बाइट)।

एक तरफ के रूप में, यदि आप एक पूर्ण सूचक पर *str करते हैं तो आप अपरिभाषित व्यवहार का आह्वान कर रहे हैं; आपको हमेशा यह सत्यापित करना चाहिए कि एक संकेतक डीरफ्रेंसिंग से पहले मान्य है।

0

1.

str एक चार के लिए सूचक है। str बढ़ाना स्ट्रिंग के दूसरे अक्षर पर सूचक बिंदु बना देगा (क्योंकि यह एक चार सरणी है)। नोट: बढ़ते पॉइंटर्स डेटा प्रकार पॉइंटर पॉइंट्स द्वारा बढ़ेगा।

पूर्व के लिए:

int *p_int; 
p_int++;  /* Increments by 4 */ 

double *p_dbl; 
p_dbl++;  /* Increments by 8 */ 

2.

if(expression) 
{ 
    statements; 
} 

अभिव्यक्ति मूल्यांकन किया जाता है और अगर परिणामस्वरूप मूल्य शून्य (NULL, \0, 0) है, बयान निष्पादित नहीं कर रहे हैं। चूंकि प्रत्येक स्ट्रिंग \0 के साथ समाप्त होती है तो रिकर्सन को कुछ समय समाप्त करना होगा।जहां 0 मतलब है false और गैर शून्य true सी में, हर अदिश प्रकार (यानी गणित और सूचक प्रकार) बूलियन संदर्भों में इस्तेमाल किया जा सकता है:

+0

प्रत्येक स्ट्रिंग को शून्य बाइट में समाप्त होने की गारंटी नहीं है। वास्तव में, यह ज्यादातर बार है; लेकिन ऐसा कुछ भी नहीं है जिसके लिए यह मामला होना आवश्यक है। – ezpz

+0

सहमत हैं। मैंने अभी इस मामले में यह माना है। – Shrinidhi

+1

@ezpz: एक सी-स्ट्रिंग * परिभाषा के अनुसार * एक शून्य-चरित्र द्वारा समाप्त वर्णों का एक अनुक्रम है; यदि कोई समाप्ति शून्य नहीं है, तो यह केवल सी-स्ट्रिंग नहीं है;) – Christoph

0

सी बूलियन मूल्यों की धारणा नहीं है।

तारों को निरस्त कर दिया गया है, टर्मिनेटर को false के रूप में व्याख्या किया जाएगा, जबकि हर दूसरे चरित्र (गैर-शून्य मान के साथ!) true होगा। इस का अर्थ है कि एक आसान तरीका एक स्ट्रिंग के पात्रों से अधिक पुनरावृति करने के लिए इसका मतलब है:

for(;*str; ++str) { /* so something with *str */ } 

StrReverse4() एक ही बात करता है, लेकिन बजाय प्रत्यावर्तन यात्रा से।

0

जो एक है जो आप उपयोग कर रहे हैं के रूप में सरल है इस कोड का प्रयास करें,:

int rev(int lower,int upper,char*string) 
{ 
    if(lower>upper) 
      return 0; 
    else 
      return rev(lower-1,upper-1,string); 
} 
0

इस विषय को बंद तरह का है, लेकिन जब मैं सवाल देखा मैं तुरंत है कि यदि वास्तव में तेजी से बस की तुलना में था सोचा पीछे से एक strlen और पुनरावृत्ति कर रही है।

तो, मैंने थोड़ा परीक्षण किया।

#include <string.h> 

void reverse1(const char* str) 
{ 
    int total = 0; 
    if (*str) { 
      reverse1(str+1); 
      total += *str; 
    } 
} 

void reverse2(const char* str) 
{ 
    int total = 0; 
    size_t t = strlen(str); 
    while (t > 0) { 
      total += str[--t]; 
    } 
} 

int main() 
{ 
    const char* str = "here I put a very long string ..."; 

    int i=99999; 

    while (--i > 0) reverseX(str); 
} 

मैं पहली बार एक्स = 1 के साथ संकलित (समारोह reverse1 का प्रयोग करके) और फिर एक्स = 2 के साथ। दोनों बार -O0 के साथ।

यह लगातार रिकर्स संस्करण के लिए लगभग 6 सेकंड और स्ट्रेल संस्करण के लिए 1.8 सेकंड लौटा।

मुझे लगता है कि ऐसा इसलिए है क्योंकि स्ट्रेलन को असेंबलर में लागू किया गया है और रिकर्सन काफी ओवरहेड जोड़ता है।

मुझे पूरा यकीन है कि बेंचमार्क प्रतिनिधि है, अगर मुझे गलत लगता है तो कृपया मुझे सही करें।

वैसे भी, मैंने सोचा कि मुझे इसे आपके साथ साझा करना चाहिए।

+0

ऐसा शायद इसलिए है क्योंकि * आपके सिस्टम में * रिकर्सिव फ़ंक्शन कॉल के लिए ओवरहेड पुनरावर्तक समाधान के समय की तुलना में बड़ा है, जो एक फ़ंक्शन कॉल को स्ट्रेल करने के लिए बनाता है। मेरा मुख्य बिंदु एक परीक्षण से सामान्यीकरण कर रहा है, यदि दिलचस्प हो तो खतरनाक हो सकता है। पहले स्पष्ट, रखरखाव योग्य कोड लिखना और इसे बाद में अनुकूलित करना बेहतर है, केवल तभी जब वास्तविक प्रदर्शन परीक्षण बाधाओं को प्रकट करता है। – Berry

+0

मैं सहमत हूं। हालांकि, जैसा कि स्ट्रेल स्कैन रैखिक रूप से स्कैन करता है (मुझे लगता है) सभी स्ट्रिंग, तुलना एक फ़ंक्शन कॉल (रिकर्सन) और स्ट्रेलन कार्यान्वयन के एक पुनरावृत्ति के साथ होना चाहिए और स्ट्रेल फ़ंक्शन कॉल के 1/n के बीच होना चाहिए। लेकिन, फिर से, मैं सहमत हूं कि स्पष्ट लिखना बेहतर है और फिर आवश्यक होने पर अनुकूलित करें। एक सवाल, आपके सिस्टम में यह पुनरावृत्ति समाधान के बजाय पुनरावृत्ति समाधान तेजी से है? – Gaston

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