Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy two structs in C that contain char pointers

Tags:

c

pointers

struct

What is the standard way to copy two structs that contain char arrays?

Here is some code:

#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;
}

The line printf("%s\n", p2.name); does not print something, because I freed the buffer.

The problem with my structs is that they are bigger than struct person. They contain hundreds of char pointers, and I have to copy every member one by one.

Is there another way to copy two structs that contain char arrays without using malloc and strcpy for every member?

like image 581
cateof Avatar asked Jul 22 '10 09:07

cateof


People also ask

Can you copy one struct to another in C?

In C/C++, we can assign a struct (or class in C++ only) variable to another variable of same type. When we assign a struct variable to another, all members of the variable are copied to the other struct variable.

Can structures contain pointers?

Structures can also contain pointers, either to basic types or to structs of the same or different types.

Why Strcpy is used in structure?

The strcpy() function is used to copy the source string to destination string. If the buffer size of dest string is more than src string, then copy the src string to dest string with terminating NULL character. But if dest buffer is less than src then it will copy the content without terminating NULL character.

Are C structs pointers?

Structs are structs, arrays are arrays, and pointers are pointers.


2 Answers

You have to allocate memory to any pointer if you want to do a copy. However you can always make a pointer point to already allocated memory. For example, you can do the following:

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

This is dangerous as there are more than one reference to the same memory location. If you free either p1.name or p2.name, it results in a dangerous situation.

In order to copy the entire content you have to allocate memory to the pointers of the struct p2.

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

This is because memory is not allocated in a contiguous manner. Also sizeof(struct) will give you size of the members of the struct and not the memory allocated to it.

For example sizeof(p2) = 8 = sizeof(p1)= sizeof(person) even after allocating memory to members of p1.

It would be a different case had the members been char arrays.

like image 59
Praveen S Avatar answered Oct 29 '22 15:10

Praveen S


To elaborate on the answer of Alexandre C. you might want to do the malloc() as a single operation so that a free() is also simple.

This approach provides a degree of protection in that the single malloc() will either succeed or fail so that you would not have a problem of malloc() failing midway through constructing a copy. With this approach you would mix person with pointers to person that have been malloced so you might want to have two different data types something along the lines of the following in order to better mark which is which.

I have provided two alternatives for the copying with one using C Standard library functions strcpy() and strlen() and the other using a simple function that does a straight copy and returns a pointer to where it left off in the destination buffer.

I have not tried to compile this example so there may be problems with it.

There is one possible concern with this approach. Since the individual strings are not malloced you may run into a problem if you are moving the individual strings around using their pointers with the idea that each of the individual strings is its own malloced area of memory. This approach assumes the entire object is wanted or none of it is wanted.

    #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;
    }
like image 32
Richard Chambers Avatar answered Oct 29 '22 17:10

Richard Chambers