2009-05-01 14 views
49

मेरा प्रश्न है, क्या इस कोड (http://www.joelonsoftware.com/articles/CollegeAdvice.html से) क्या करता है:"जबकि (* s ++ = * t ++)" एक स्ट्रिंग की प्रतिलिपि कैसे करता है?

while (*s++ = *t++); 

वेबसाइट का कहना है कि प्रतियां ऊपर कोड एक स्ट्रिंग लेकिन मैं क्यों समझ में नहीं आता ...

यह है पॉइंटर्स के साथ क्या करना है?

उत्तर

41

यह इस के बराबर है:

while (*t) { 
    *s = *t; 
    s++; 
    t++; 
} 
*s = *t; 

जब चार कि t अंक '\0' है, जबकि पाश समाप्त कर देगा। तब तक, यह उन चारों की प्रतिलिपि बनायेगा जो t उन चारों ओर इंगित कर रहे हैं जो s इंगित कर रहे हैं, फिर s और t को अपने सरणी में अगले चार को इंगित करने के लिए इंगित करें।

+3

दे रहा है मेरा उत्तर नीचे देखें। यह जवाब गलत है। –

-1

हां, इसे पॉइंटर्स के साथ करना होगा।

कोड पढ़ने का तरीका यह है: "सूचक जो" पॉइंटर "द्वारा इंगित किया गया है (जो इस ऑपरेशन के बाद बढ़ता है) वह मान प्राप्त करता है जो पॉइंटर" टी "(जो हो जाता है) इस ऑपरेशन के बाद बढ़ी हुई; इस ऑपरेशन का पूरा मूल्य कॉपी किए गए चरित्र के मान का मूल्यांकन करता है; इस ऑपरेशन में तब तक पुनरावृत्ति करें जब तक कि मान शून्य के बराबर न हो। "स्ट्रिंग नल टर्मिनेटर का मान शून्य का वर्ण मान है ('/ 0'), लूप तब तक फिर से चालू हो जाएगा जब तक टी द्वारा इंगित स्थान से एक स्ट्रिंग की प्रतिलिपि बनाई जाती है।

0

यह एक स्ट्रिंग की प्रतिलिपि बनाता है क्योंकि सरणी हमेशा संदर्भ द्वारा पारित होती हैं, और स्ट्रिंग केवल एक चार सरणी होती है। असल में क्या हो रहा है (अगर मुझे सही शब्द याद है) सूचक अंकगणित। एच ईर का a bit more information from wikipedia on c arrays

आप उस मूल्य को संग्रहीत कर रहे हैं जिसे टी में से संदर्भित किया गया था और फिर ++ के माध्यम से अगली अनुक्रमणिका में जा रहा था।

1

यह '' द्वारा इंगित स्ट्रिंग में 't' द्वारा इंगित स्ट्रिंग से वर्णों की प्रतिलिपि बनाकर काम करता है। प्रत्येक चरित्र प्रतियों के लिए, दोनों पॉइंटर्स वृद्धि हुई हैं। लूप समाप्त होता है जब इसे NUL वर्ण (शून्य के बराबर, इसलिए बाहर निकलें) मिलता है।

-1

हां यह पॉइंटर्स का उपयोग करता है, और समय की स्थिति का मूल्यांकन करते समय भी सभी काम करता है। सी सशर्त अभिव्यक्तियों के दुष्प्रभावों की अनुमति देता है।

"*" ऑपरेटर पॉइंटर्स और टी को अपमानित करता है।

वृद्धि ऑपरेटर ("++") असाइनमेंट के बाद पॉइंटर्स एस और टी बढ़ाता है।

पाश एक अशक्त चरित्र है, जो सी

एक अतिरिक्त टिप्पणी के रूप में झूठी का मूल्यांकन करता है की शर्त पर समाप्त हो जाता है .... यह सुरक्षित कोड के रूप में यह सुनिश्चित करने के लिए रों पर्याप्त स्मृति आवंटित किया है कुछ नहीं करता नहीं है,।

1

संकेत:

  • क्या ऑपरेटर '=' क्या करता है?
  • "ए = बी" अभिव्यक्ति का मूल्य क्या है? उदाहरण: यदि आप "सी = ए = बी" करते हैं तो सी क्या मूल्य प्राप्त करता है?
  • सी स्ट्रिंग को क्या समाप्त करता है? क्या यह सच या गलत मूल्यांकन करता है?
  • "* s ++" में, कौन सा ऑपरेटर उच्च प्राथमिकता है?

सलाह:

  • उपयोग strncpy() के बजाय। - इस मामले "एच" में

    char *someString = "Hello, World!"; 
    

    someString स्ट्रिंग में पहले वर्ण के लिए अंक:

0

आप कुछ इस तरह है कहो।

अब, अगर आप एक के बाद सूचक को बढ़ा:

someString++ 

someString अब 'ई' इंगित करेंगे।

while (*someString++); 

इच्छा पाश जो कुछ someString बिंदुओं पर जब तक शून्य हो जाता है, वह राशि है जो एक स्ट्रिंग के अंत ("शून्य समाप्त") संकेत देती है।

और कोड:

while (*s++ = *t++); 

के बराबर है:

while (*t != NULL) { // While whatever t points to isn't NULL 
    *s = *t;   // copy whatever t points to into s 
    s++; 
    t++; 
} 
26

यह इतना कवर के तहत चल रहा है:

while (*s++ = *t++); 

s और t चर संकेत दिए गए हैं (लगभग निश्चित रूप से वर्ण), s गंतव्य होने के नाते। निम्न चरणों के उदाहरण देकर स्पष्ट करना क्या हो रहा है:

  • टी (*t) की सामग्री रों (*s), एक चरित्र को कॉपी कर रहे हैं।
  • s और t दोनों वृद्धि हुई हैं (++)।
  • असाइनमेंट (प्रतिलिपि) उस प्रतिलिपि को वापस लौटाता है जिसे कॉपी किया गया था (while पर)।
  • while तब तक जारी रहता है जब तक कि वर्ण शून्य न हो (C में स्ट्रिंग का अंत)।

प्रभावी रूप से, यह है:

while (*t != 0) { 
    *s = *t; 
    s++; 
    t++; 
} 
*s = *t; 
s++; 
t++; 

लेकिन एक और अधिक कॉम्पैक्ट तरीके से लिखा है।

3

इस पहलू के बारे में रहस्यमय है ऑपरेशन का क्रम है।यदि आप सी भाषा कल्पना को देखने के लिए, यह कहा गया है कि इस संदर्भ में, आपरेशन के क्रम निम्नानुसार है:

1. * operator 
2. = (assignment) operator 
3. ++ operator 

इसलिए जब पाश तो, हो जाता है अंग्रेजी:

 
while (some condition): 
    Take what is at address "t" and copy it over to location at address "s". 
    Increment "s" by one address location. 
    Increment "t" by one address location. 

अब, "कुछ हालत" क्या है? सी लैंग विनिर्देश यह भी कहता है कि असाइनमेंट अभिव्यक्ति का मान निर्दिष्ट मूल्य है, जो इस मामले में *t है।

तो "कुछ हालत" t कुछ शून्य जो शून्य है, या एक सरल तरीके से "है," स्थान t पर डेटा NULL नहीं है "।

+0

पोस्ट वृद्धि वृद्धि ऑपरेटर से पहले असाइनमेंट क्यों किया जाता है जब पोस्ट वृद्धि ऑपरेटर की उच्च प्राथमिकता होती है। – light

-1

थोड़ी देर के पाश शुरू होता है ....

* एस = * टी पहले से चला जाता है, यह क्या टी क्या पर अंक एस के लिए कम से अंक के लिए प्रदान करती है। यानी, यह टी स्ट्रिंग से एस स्ट्रिंग के लिए एक चरित्र की प्रतिलिपि बनाता है।

आवंटित किया जा रहा है, जबकि शर्त दी जा रही है ... कोई भी शून्य शून्य "सत्य" है, इसलिए यह जारी रहेगा, और 0 झूठा है, यह रुक जाएगा .... और यह केवल एक स्ट्रिंग का अंत होता है शून्य भी है।

रों ++ और टी ++ वे संकेत

को बढ़ा देते और यह सब फिर से

तो यह पाशन बताए रहता है, संकेत जाने लगता है, जब तक यह एक 0 है, जो स्ट्रिंग के अंत है हिट

17

मान लें कि s और tchar * एस हैं जो तारों को इंगित करते हैं (और मान लें s कम से कम t जितना बड़ा है)। सी में, 0 (ASCII "एनयूएल") में सभी अंत तार, सही? तो क्या यह क्या करता है:

*s++ = *t++; 

सबसे पहले, यह *s = *t करता है, *s करने के लिए *t पर मूल्य को कॉपी। फिर, यह s++ करता है, इसलिए s अब अगले चरित्र को इंगित करता है। और फिर यह t++ करता है, इसलिए t अगले चरित्र को इंगित करता है। इसे ऑपरेटर प्राथमिकता और उपसर्ग बनाम पोस्टफिक्स वृद्धि/कमी के साथ करना है।

ऑपरेटर प्राथमिकता वह क्रम है जिसमें ऑपरेटरों का समाधान किया जाता है। एक साधारण उदाहरण के लिए, देखने के लिए:

4 + 2 * 3 

इस 4 + (2 * 3) या (4 + 2) * 3 है? खैर, हम जानते हैं कि यह प्राथमिकता की वजह से पहला है - बाइनरी * (गुणा ऑपरेटर) बाइनरी + (अतिरिक्त ऑपरेटर) की तुलना में अधिक प्राथमिकता है, और पहले हल किया गया है।

*s++ में, हमारे पास * (पॉइंटर डेरेंसेंस ऑपरेटर) और यूनरी ++ (पोस्टफिक्स वृद्धि ऑपरेटर) है। इस मामले में, ++ में * की तुलना में अधिक प्राथमिकता है ("बाध्य बाध्य" भी कहा जाता है)।अगर हम ++*s ने कहा था, हम*s पर मूल्य को बढ़ा देते हैं बल्कि पता द्वाराs क्योंकि उपसर्ग वेतन वृद्धि भिन्नता के रूप में कम पूर्वता * है की ओर इशारा किया की तुलना में, लेकिन हम पोस्टफ़िक्स वेतन वृद्धि, जो उच्च पूर्वता है इस्तेमाल किया। अगर हम उपसर्ग वृद्धि का उपयोग करना चाहते थे, तो हम *(++s) कर सकते थे, क्योंकि ब्रांड्स ने सभी कम प्राथमिकताओं को ओवरराइड कर दिया होगा और ++s को पहले आने के लिए मजबूर किया होगा, लेकिन स्ट्रिंग की शुरुआत में खाली चरित्र छोड़ने के अवांछित दुष्प्रभाव ।

ध्यान दें कि सिर्फ इसलिए कि इसकी प्राथमिकता है इसका मतलब यह नहीं है कि यह पहले होता है। के बाद पोस्टफिक्स वृद्धि विशेष रूप से होती है मान का उपयोग किया गया है, जिसका कारण *s = *ts++ से पहले होता है।

तो अब आप *s++ = *t++ समझते हैं। लेकिन वे एक पाश में रख:

while(*s++ = *t++); 

इस पाश कुछ नहीं करता है - कार्रवाई सभी हालत में है। लेकिन उस स्थिति की जांच करें - *s 0 0 है, जिसका अर्थ है *t 0 था, जिसका अर्थ है कि वे स्ट्रिंग के अंत में थे (ASCII "NUL" के लिए yay)। तो यह लूप तब तक लूप करता है जब तक t में वर्ण होते हैं, और उन्हें s में s और t में बढ़ते हुए प्रतिलिपि बनाते हैं। जब यह लूप निकलता है, s एनयूएल समाप्त हो गया है, और एक उचित स्ट्रिंग है। एकमात्र समस्या है, s अंत तक अंक। एक और सूचक आस-पास रखें कि (while() पाश से पहले यानी s) की s शुरुआत करने के लिए अंक - कि कॉपी किए गए स्ट्रिंग हो जाएगा:

char *s, *string = s; 
while(*s++ = *t++); 
printf("%s", string); // prints the string that was in *t 

वैकल्पिक रूप से, यह बाहर की जाँच:

size_t i = strlen(t); 
while(*s++ = *t++); 
s -= i + 1; 
printf("%s\n", s); // prints the string that was in *t 

हम लंबाई प्राप्त करके शुरू किया, इसलिए जब हम समाप्त हो गए, तो हमने शुरुआत में s को शुरू करने के लिए और अधिक पॉइंटर अंकगणित किया, जहां यह शुरू हुआ।

बेशक, यह कोड खंड (और मेरे सभी कोड टुकड़े) सादगी के लिए बफर मुद्दों को अनदेखा करते हैं। बेहतर संस्करण यह है:

size_t i = strlen(t); 
char *c = malloc(i + 1); 
while(*s++ = *t++); 
s -= i + 1; 
printf("%s\n", s); // prints the string that was in *t 
free(c); 

लेकिन आप पहले से ही जानते थे, या आप जल्द ही इसके बारे में हर किसी की पसंदीदा वेबसाइट पर एक प्रश्न पूछेंगे। ;)

* असल में, उनके पास समान प्राथमिकता है, लेकिन यह विभिन्न नियमों द्वारा हल किया गया है। इस स्थिति में वे प्रभावी रूप से कम प्राथमिकता रखते हैं।

+0

क्या कोई मुझे समझाने में मदद कर सकता है कि क्यों 'char * c = malloc (i + 1);' और 'free (c);' सादगी के लिए बफर मुद्दों को अनदेखा करना बेहतर है '? मुझे यह नहीं मिला। –

1

सी प्रोग्रामिंग भाषा (K & आर) ब्रायन डब्ल्यू Kernighan और डेनिस एम रिची द्वारा इस बात का एक विस्तृत विवरण देता है।

द्वितीय संस्करण, पृष्ठ 104:

5।5 चरित्र प्वाइंटर और कार्य

एक स्ट्रिंग निरंतर,

"I am a string" 

के रूप में लिखा पात्रों में से एक सरणी है। आंतरिक प्रतिनिधित्व में, सरणी को शून्य वर्ण '\0' से समाप्त कर दिया जाता है ताकि प्रोग्राम अंत प्राप्त कर सकें। भंडारण की लंबाई डबल कोट्स के बीच वर्णों की संख्या से अधिक है।

शायद स्ट्रिंग स्थिरांक का सबसे आम घटना में

printf("hello, world\n"); 

जहां इस तरह एक चरित्र स्ट्रिंग एक कार्यक्रम में प्रकट होता है, उस तक पहुँच एक चरित्र सूचक के माध्यम से है के रूप में कार्य करने के लिए तर्क के रूप में है; printf चरित्र सरणी की शुरुआत में एक सूचक प्राप्त करता है। यही है, एक सूचक द्वारा अपने पहले तत्व में एक स्ट्रिंग निरंतर उपयोग किया जाता है।

स्ट्रिंग स्थिरांक को कार्य तर्कों की आवश्यकता नहीं है। pmessage

char *pmessage; 

तो बयान

pmessage = "now is the time"; 

pmessage के चरित्र सरणी के लिए सूचक प्रदान करती है के रूप में घोषित किया जाता है। यह एक स्ट्रिंग प्रति नहीं है; केवल पॉइंटर्स शामिल हैं। सी एक इकाई के रूप में वर्णों की एक पूरी स्ट्रिंग को संसाधित करने के लिए किसी भी ऑपरेटरों को प्रदान नहीं करता है।

वहाँ इन परिभाषाओं के बीच एक महत्वपूर्ण अलग है:

char amessage[] = "now is the time"; /* an array */ 
char *pmessage = "now is the time"; /* a pointer */ 

amessage एक सरणी, बस काफी बड़ा पात्रों के अनुक्रम और '\0' कि यह initializes धारण करने के लिए है। सरणी के भीतर व्यक्तिगत वर्ण amessage द्वारा बदला जा सकता है हमेशा एक ही भंडारण का संदर्भ लेंगे। दूसरी ओर, pmessage एक सूचक है, जो स्ट्रिंग स्थिर को इंगित करने के लिए प्रारंभ किया गया है; पॉइंटर को बाद में कहीं और इंगित करने के लिए संशोधित किया जा सकता है, लेकिन यदि आप स्ट्रिंग सामग्री को संशोधित करने का प्रयास करते हैं तो परिणाम अपरिभाषित होता है।

  +---+  +--------------------+ 
pmessage: | o-------->| now is the time \0 | 
      +---+  +--------------------+ 

      +--------------------+ 
amessage: | now is the time \0 | 
      +--------------------+ 

हम मानक पुस्तकालय से अनुकूलित दो उपयोगी कार्यों के संस्करणों का अध्ययन करके संकेत दिए गए और सरणियों के अधिक पहलुओं उदाहरण देकर स्पष्ट करना होगा। पहला फ़ंक्शन strcpy(s,t) है, जो स्ट्रिंग s स्ट्रिंग t की प्रतिलिपि बनाता है। s = t कहने के लिए यह अच्छा होगा लेकिन यह सूचकों की प्रतिलिपि नहीं करता है, वर्णों की प्रतिलिपि बनाने के लिए, हमें एक लूप की आवश्यकता है। सरणी संस्करण पहला है:

/* strcpy: copy t to s; pointer version 1 */ 
void strcpy(char *s, char *t) 
{ 
    while((*s = *t) != '\0') 
    { 
     s ++; 
     t ++; 
    } 
} 

क्योंकि तर्क मान द्वारा पारित कर रहे हैं, strcpy मापदंडों s और t किसी भी तरह से उपयोग कर सकते हैं:

/* strcpy: copy t to s; array subscript version */ 
void strcpy(char *s, char *t) 
{ 
    int i; 

    i = 0; 
    while((s[i] = t[i]) != '\0') 
     i ++; 
} 

इसके विपरीत के लिए, यहाँ संकेत के साथ strcpy का एक संस्करण है यह प्रसन्न करता है। यहां वे आसानी से पॉइंटर्स प्रारंभ कर रहे हैं, जो एक समय में एक वर्ण के सरणी के साथ घुड़सवार होते हैं, '\0' जो t को s पर कॉपी कर दिया गया है।

अभ्यास में, strcpy लिखा नहीं जाएगा जैसा कि हमने इसे ऊपर दिखाया है। अनुभवी C प्रोग्रामर पसंद करेंगे

/* strcpy: copy t to s; pointer version 2 */ 
void strcpy(char *s, char *t) 
{ 
    while((*s++ = *t++) != '\0') 
     ; 
} 

इस पाश की कसौटी पर भाग में s और t की वेतन वृद्धि ले जाता है। *t++ का मान वह वर्ण है जो tt से पहले इंगित किया गया था; इस वर्ण के बाद पोस्टफिक्स ++t नहीं बदलता है। इसी तरह, s से पहले वर्ण को पुराने s स्थिति में संग्रहीत किया जाता है। यह वर्ण लूप को नियंत्रित करने के लिए '\0' के विरुद्ध तुलना की गई मान भी है। शुद्ध प्रभाव यह है कि t से s तक वर्णों की प्रतिलिपि बनाई गई है, '\0' को समाप्त करने सहित।

अंतिम संक्षेप के रूप में, देखें कि '\0' के विरुद्ध तुलना अनावश्यक है, क्योंकि प्रश्न केवल यह है कि अभिव्यक्ति शून्य है या नहीं। तो समारोह की संभावना के रूप में

/* strcpy: cope t to s; pointer version 3 */ 
void strcpy(char *s, char *t) 
{ 
    while(*s++ = *t++); 
} 

लिखा जाएगा हालांकि यह पहली नजर के रूप में गुप्त लग सकता है, सांकेतिक सुविधा काफी है, और मुहावरा, में महारत हासिल किया जाना चाहिए क्योंकि आप सी कार्यक्रमों में यदि बार-बार देखेंगे।

मानक पुस्तकालय में strcpy (<string.h>) लक्ष्य कार्य को इसके कार्य मान के रूप में लौटाता है।

यह इस खंड के प्रासंगिक भागों का अंत है।

पीएस: यदि आप इसे पढ़ने में आनंद लेते हैं, तो & आर की एक प्रति खरीदने पर विचार करें - यह महंगा नहीं है।

12
while(*s++ = *t++); 

लोग क्यों लगता है कि यह के बराबर है है:

while (*t) { 
    *s = *t; 
    s++; 
    t++; 
} 
*s = *t; /* if *t was 0 at the beginning s and t are not incremented */ 

जब यह स्पष्ट रूप से नहीं है।

char tmp = 0; 
do { 
    tmp = *t; 
    *s = tmp; 
    s++; 
    t++; 
} while(tmp); 

अधिक है जैसे कि यह

संपादित है: एक संकलन त्रुटि सही किया। tmp चर लूप के बाहर घोषित किया जाना चाहिए।

+2

अच्छा पकड़ .. यह कम से कम एक बार प्रतिलिपि बनाता है .. – baash05

-1

जिस प्रश्न पर मैंने निम्नलिखित उत्तर दिया है, इस प्रश्न के डुप्लिकेट के रूप में बंद किया गया था, इसलिए मैं यहां उत्तर के प्रासंगिक भाग की प्रतिलिपि बना रहा हूं।

for (;;) { 
    char *olds = s;    // original s in olds 
    char *oldt = t;    // original t in oldt 
    char c = *oldt;    // original *t in c 
    s += 1;      // complete post increment of s 
    t += 1;      // complete post increment of t 
    *olds = c;     // copy character c into *olds 
    if (c) continue;   // continue if c is not 0 
    break;      // otherwise loop ends 
} 

आदेश है कि s और t सहेजा जाता है और आदेश है कि s और t बढ़ती है, आपस में बदल किया जा सकता है:

जबकि पाश की वास्तविक अर्थ स्पष्टीकरण की तरह कुछ होगा। *oldt से c की बचत oldt सहेजी गई है और c से पहले किसी भी समय हो सकती है।c से *olds का असाइनमेंट c और olds सहेजे जाने के बाद किसी भी समय हो सकता है। मेरे लिफाफे के पीछे, यह कम से कम 40 विभिन्न व्याख्याओं के लिए काम करता है।

+0

यह उत्तर डाउनवॉट किया गया क्योंकि यह जवाब दे रहा है [जिस प्रश्न को डुप्लिकेट चिह्नित किया गया है] (http://stackoverflow.com/q/16581048/315052)। साथ ही, यह इस सवाल का जवाब देता है कि कॉपी कैसे होती है। – jxh

-2

वैसे यह सच है कि अगर कोई नहीं है तो char के मामले में यह सही है और यह एक पूर्णांक सरणी है, तो प्रोग्राम क्रैश हो जाएगा क्योंकि वहां एक पता होगा जिसका तत्व सरणी या सूचक का हिस्सा नहीं है , अगर सिस्टम में स्मृति है जो मॉलोक का उपयोग करके आवंटित किया गया था तो सिस्टम मेमोरी

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