2010-07-22 14 views
12

char arrays वाले दो structs की प्रतिलिपि बनाने का मानक तरीका क्या है?सी में दो structs कॉपी करें जिसमें चार पॉइंटर्स

#include stdio.h> 
#include string.h> 
#include stdlib.h> 

typedef struct { 
    char* name; 
    char* surname; 
} person; 

int main(void){ 
    person p1; 
    person p2; 

    p1.name  = (char*)malloc(5); 
    p1.surname = (char*)malloc(5); 

    strcpy(p1.name, "AAAA"); 
    strcpy(p1.surname, "BBBB"); 

    memcpy(&p2, &p1, sizeof(person)); 
    free(p1.name); 
    printf("%s\n", p2.name); 
    return 0; 
} 

लाइन printf("%s\n", p2.name);, कुछ प्रिंट नहीं करता क्योंकि मैं बफर मुक्त कर दिया:

यहाँ कुछ कोड है।

मेरे structs के साथ समस्या यह है कि वे संरचना person से बड़ी हैं। उनमें सैकड़ों चार पॉइंटर्स होते हैं, और मुझे प्रत्येक सदस्य को एक-एक करके कॉपी करना होता है।

क्या दो सूत्रों की प्रतिलिपि बनाने का कोई और तरीका है जिसमें प्रत्येक सदस्य के लिए malloc और strcpy का उपयोग किए बिना चार सरणी शामिल हैं?

+0

memcpy कैसे काम करता है, अगर स्मृति को पी 2 के लिए आवंटित नहीं किया गया है, तो क्या कोई समझा सकता है? क्या इसे रन टाइम पर कुछ अपवाद नहीं फेंकना चाहिए? – JagsVG

+1

आपकी संरचनाओं में * पॉइंटर्स *, नहीं * सरणी * शामिल हैं। आपके पॉइंटर्स में char की सरणी का पता हो सकता है, लेकिन क्या आप उस सरणी की प्रतिलिपि बनाना चाहते हैं, आपको इसे स्पष्ट रूप से प्रबंधित करना होगा। –

उत्तर

13

आप कोई विकल्प नहीं है लेकिन एक प्रति समारोह अपने आप को प्रदान करते हैं:

void copy_person(person *dst, const person *src) 
{ 
    dst->name = malloc(strlen(src->name) + 1); 
    dst->surname = malloc(strlen(src->surname) + 1); 
    strcpy(dst->name, src->name); 
    strcpy(dst->surname, src->surname); 
} 

जो अधिक है कि तुलना में सविस्तार किया जा सकता है: त्रुटियों के लिए जाँच, एक सहायक समारोह में strlen + strcpy बाँटे, आदि

कि क्या सी ++ में कॉपी कन्स्ट्रक्टर के लिए हैं।

+4

यदि आप एक पॉज़िक्स सिस्टम (जैसे लिनक्स) पर हैं, तो आप 'malloc + strcpy' के बजाय' strdup' का उपयोग कर सकते हैं। –

+1

@ जेन्स: जब मैंने "सहायक उपकरण में" फैक्टरिंग .... लिखा था, तो मेरे सिर में यही था। –

7

हाँ, नकल struct कि चार सरणियों किसी भी समस्या के बिना काम करेंगे होते हैं, लेकिन चार संकेत (या उस बात के लिए सूचक किसी भी प्रकार की) के साथ struct आप मैन्युअल रूप से करना होगा।

यह भी ध्यान रखें कि मॉलोक के रिटर्न प्रकार की कास्ट सी में आवश्यक नहीं है (यह सी ++ में है) और मॉलोक के लिए एक लापता प्रोटोटाइप छुपा सकता है।

0

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

p2.name = p1.name (p1.name is already allocated memory) 

यह खतरनाक है के रूप में वहाँ एक ही स्मृति स्थान के लिए एक से अधिक संदर्भ हैं। यदि आप या तो p1.name या p2.name मुक्त करते हैं, तो यह एक खतरनाक स्थिति में परिणाम देता है।

संपूर्ण सामग्री की प्रतिलिपि बनाने के लिए आपको संरचना पी 2 के पॉइंटर्स को स्मृति आवंटित करना होगा।

p2.name = <allocate memory> 
Copy individual struct members instead of a memcpy of the entire struct 

ऐसा इसलिए है क्योंकि स्मृति को एक समान तरीके से आवंटित नहीं किया जाता है। sizeof(struct) आपको संरचना के सदस्यों का आकार देगा, न कि स्मृति को आवंटित किया जाएगा।

उदाहरण के लिए sizeof(p2) = 8 = sizeof(p1)= sizeof(person)p1 के सदस्यों को स्मृति आवंटित करने के बाद भी।

यह एक अलग मामला होगा जब सदस्य चार सरणी थे।

1

थोड़ा बाहर के बॉक्स सोच:

के बाद से अपने struct की संरचना स्थिर है, तो आप एक छोटे उपयोगिता कार्यक्रम या स्क्रिप्ट आप के लिए प्रतिलिपि कोड उत्पन्न करने के लिए लिख सकते हैं।

इनपुट के रूप में अपनी संरचना परिभाषा का स्रोत-कोड लें, और उसके बाद प्रतिलिपि कोड उत्पन्न करने के लिए नियमों का एक सेट तैयार करें।

यह त्वरित है, और मुझे नहीं पता कि यह कॉपी-कोड मैन्युअल रूप से लिखने के लिए तेज़ था - लेकिन कम से कम यह एक और दिलचस्प समस्या है।

1

अलेक्जेंड्रे सी के जवाब पर विस्तृत करने के लिए आप एक ही ऑपरेशन के रूप में malloc() करना चाहते हैं ताकि free() भी आसान हो।

यह दृष्टिकोण एक डिग्री प्रदान करता है जिसमें एकल malloc() या तो सफल या विफल हो जाएगा ताकि आपको malloc() की कोई प्रतिलिपि बनाने के माध्यम से मिडवे में विफल होने की कोई समस्या न हो। इस दृष्टिकोण के साथ आप person को person पर पॉइंटर्स के साथ मिश्रित कर देंगे जिन्हें मॉलोक किया गया है ताकि आप बेहतर तरीके से चिह्नित करने के लिए निम्न के साथ दो अलग-अलग डेटा प्रकारों को कुछ करना चाहें।

मैं एक का उपयोग कर सी स्टैंडर्ड पुस्तकालय कार्यों strcpy() और strlen() और अन्य एक साधारण समारोह है कि एक सीधे नकल करता है और जहां यह गंतव्य बफर में दूर छोड़ दिया करने के लिए एक सूचक रिटर्न उपयोग करने के साथ नकल के लिए दो विकल्प प्रदान की है।

मैंने इस उदाहरण को संकलित करने की कोशिश नहीं की है, इसलिए इसमें समस्याएं हो सकती हैं।

इस दृष्टिकोण के साथ एक संभावित चिंता है। चूंकि अलग-अलग तारों को मॉलोकॉइड नहीं किया जाता है, इसलिए आप किसी समस्या में भाग ले सकते हैं यदि आप अपने पॉइंटर्स का उपयोग करके अलग-अलग तारों को इस विचार के साथ ले जा रहे हैं कि प्रत्येक व्यक्तिगत तार स्मृति का अपना मॉलोकॉइड क्षेत्र है। यह दृष्टिकोण मानता है कि पूरी वस्तु चाहता है या इसमें से कोई भी नहीं चाहता था।

#include <stdio.h> 
    #include <string.h> 
    #include <stdlib.h> 

    typedef struct { 
     char* name; 
     char* surname; 
     char* address1; 
    } person, *personptr; 

    // copy a string to destination string return pointer after end of destination string 
    char * StrCpyRetEnd (char *pDest, char *pSrc) 
    { 
     while (*pDest++ = *pSrc++); 
     return pDest; 
    } 
    personptr DeepCopyPerson (person *pSrc) 
    { 
     personptr  pDest = 0; 
     unsigned int iTotalSize = sizeof(person); 

     iTotalSize += (strlen(pSrc->name) + 1) * sizeof(char); 
     iTotalSize += (strlen(pSrc->surname) + 1) * sizeof(char); 
     iTotalSize += (strlen(pSrc->address1) + 1) * sizeof(char); 
     pDest = malloc(iTotalSize); 
     if (pDest) { 
#if 1 
      // alternative one without a helper function 
      pDest->name = (char *)(pDest + 1); strcpy (pDest->name, pSrc->name); 
      pDest->surname = pDest->name + strlen(pDest->name) + 1; strcpy (pDest->surname, pSrc->surname); 
      pDest->address1 = pDest->surname + strlen(pDest->surname) + 1; strcpy (pDest->address1, pSrc->address1); 
#else 
      // alternative two using StrCpyRetEnd() function 
      pDest->name = (char *)(pDest + 1); 
      pDest->surname = StrCpyRetEnd (pDest->name, pSrc->name); 
      pDest->address1 = StrCpyRetEnd (pDest->surname, pSrc->surname); 
      strcpy (pDest->address1, pSrc->address1); 
#endif 
     } 
     return pDest; 
    } 

    int main(void){ 
     person p1; // programmer managed person with separate mallocs 
     personptr p2; // created using ClonePerson() 

     p1.name  = malloc(5); 
     p1.surname = malloc(5); 
     p1.address1 = malloc(10); 

     strcpy(p1.name,"AAAA"); 
     strcpy(p1.surname,"BBBB"); 
     strcpy(p1.address1,"address1"); 

     p2 = DeepCopyPerson (&p1); 

     free(p1.name); 
     printf("%s\n", p2->name); 

     free (p2); // frees p2 and all of the memory used by p2 
     return 0; 
    } 
संबंधित मुद्दे