80

I know that I can copy the structure member by member, instead of that can I do a memcpy on structures?

Is it advisable to do so?

In my structure, I have a string also as member which I have to copy to another structure having the same member. How do I do that?

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
asir
  • 12,843
  • 8
  • 24
  • 18
  • 4
    Why are you talking about "member functions" in a question tagged as C? – unwind Feb 08 '11 at 08:59
  • 2
    Could you show us the struct or at least an extract of it? I assume that the string is not a member _function_, only a member as we're talking plain C here. Is the "string" a char array, a dynamically allocated char* or what? – rjnilsson Feb 08 '11 at 09:00

8 Answers8

88

Copying by plain assignment is best, since it's shorter, easier to read, and has a higher level of abstraction. Instead of saying (to the human reader of the code) "copy these bits from here to there", and requiring the reader to think about the size argument to the copy, you're just doing a plain assignment ("copy this value from here to here"). There can be no hesitation about whether or not the size is correct.

Also, if the structure is heavily padded, assignment might make the compiler emit something more efficient, since it doesn't have to copy the padding (and it knows where it is), but mempcy() doesn't so it will always copy the exact number of bytes you tell it to copy.

If your string is an actual array, i.e.:

struct {
  char string[32];
  size_t len;
} a, b;

strcpy(a.string, "hello");
a.len = strlen(a.string);

Then you can still use plain assignment:

b = a;

To get a complete copy. For variable-length data modelled like this though, this is not the most efficient way to do the copy since the entire array will always be copied.

Beware though, that copying structs that contain pointers to heap-allocated memory can be a bit dangerous, since by doing so you're aliasing the pointer, and typically making it ambiguous who owns the pointer after the copying operation.

For these situations a "deep copy" is really the only choice, and that needs to go in a function.

unwind
  • 391,730
  • 64
  • 469
  • 606
43

Since C90, you can simply use:

dest_struct = source_struct;

as long as the string is memorized inside an array:

struct xxx {
    char theString[100];
};

Otherwise, if it's a pointer, you'll need to copy it by hand.

struct xxx {
    char* theString;
};

dest_struct = source_struct;
dest_struct.theString = malloc(strlen(source_struct.theString) + 1);
strcpy(dest_struct.theString, source_struct.theString);
Simone
  • 11,655
  • 1
  • 30
  • 43
  • 1
    What happens before C90? What would be the difference in struct assignment between pre-C90 and post-C90 compilers if the struct contains an array like in your example? – cesss Mar 27 '17 at 10:10
  • 1
    @cesss: Before C90/C89 there was no formal standard for C, so it depended on the compiler you used. Not all supported assignment of `struct`s. Since C90 requires compilers to support it, you can be sure any compiler that conforms to C90 (or later) will let you do it. – sleske Sep 28 '17 at 09:02
23

If the structures are of compatible types, yes, you can, with something like:

memcpy (dest_struct, source_struct, sizeof (*dest_struct));

The only thing you need to be aware of is that this is a shallow copy. In other words, if you have a char * pointing to a specific string, both structures will point to the same string.

And changing the contents of one of those string fields (the data that the char * points to, not the char * itself) will change the other as well.

If you want a easy copy without having to manually do each field but with the added bonus of non-shallow string copies, use strdup:

memcpy (dest_struct, source_struct, sizeof (*dest_struct));
dest_struct->strptr = strdup (source_struct->strptr);

This will copy the entire contents of the structure, then deep-copy the string, effectively giving a separate string to each structure.

And, if your C implementation doesn't have a strdup (it's not part of the ISO standard), get one from here.

jrtc27
  • 8,496
  • 3
  • 36
  • 68
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
6

You can memcpy structs, or you can just assign them like any other value.

struct {int a, b;} c, d;
c.a = c.b = 10;
d = c;
Conrad Meyer
  • 2,851
  • 21
  • 24
6

In C, memcpy is only foolishly risky. As long as you get all three parameters exactly right, none of the struct members are pointers (or, you explicitly intend to do a shallow copy) and there aren't large alignment gaps in the struct that memcpy is going to waste time looping through (or performance never matters), then by all means, memcpy. You gain nothing except code that is harder to read, fragile to future changes and has to be hand-verified in code reviews (because the compiler can't), but hey yeah sure why not.

In C++, we advance to the ludicrously risky. You may have members of types which are not safely memcpyable, like std::string, which will cause your receiving struct to become a dangerous weapon, randomly corrupting memory whenever used. You may get surprises involving virtual functions when emulating slice-copies. The optimizer, which can do wondrous things for you because it has a guarantee of full type knowledge when it compiles =, can do nothing for your memcpy call.

In C++ there's a rule of thumb - if you see memcpy or memset, something's wrong. There are rare cases when this is not true, but they do not involve structs. You use memcpy when, and only when, you have reason to blindly copy bytes.

Assignment on the other hand is simple to read, checks correctness at compile time and then intelligently moves values at runtime. There is no downside.

Scott M
  • 684
  • 7
  • 14
  • "In C++ there's a rule of thumb - if you see memcpy or memset, something's wrong." Seems like a strong statement given that std::memcpy is literally the only legal way to do certain operations in C++, cf. https://youtu.be/_qzMpk-22cc?t=1814 – heiner Nov 29 '21 at 16:48
2

You can use the following solution to accomplish your goal:

struct student 
{
    char name[20];
    char country[20];
};
void main()
{
    struct student S={"Wolverine","America"};
    struct student X;
    X=S;
    printf("%s%s",X.name,X.country);
}
Grant Miller
  • 27,532
  • 16
  • 147
  • 165
Anvesh
  • 97
  • 2
  • 11
2

Just in addition to other answers, as a clarification.
If you want to copy structs but you have struct pointers, you can also do it easy:

*ptr = *ptr2;

Long example:

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

struct some {
        int a;
        char b;
};

int main(void)
{
        struct some some1;
        struct some *ptr = malloc(sizeof(struct some));
        struct some *ptr2 = malloc(sizeof(struct some));
        struct some *ptr3 = malloc(sizeof(struct some));
        memset(ptr, 0, sizeof(struct some));
        memset(ptr2, 0, sizeof(struct some));

        ptr->a = 123;
        ptr->b = 'b';

        *ptr2 = *ptr;
        printf("%d %c\n", ptr2->a, ptr2->b);

        some1 = *ptr;
        printf("%d %c\n", some1.a, some1.b);

        *ptr3 = some1;
        printf("%d %c\n", ptr3->a, ptr3->b);

        return 0;
}

The output is:

123 b
123 b
123 b
red0ct
  • 4,840
  • 3
  • 17
  • 44
0
  1. You can use a struct to read write into a file. You do not need to cast it as a `char*. Struct size will also be preserved. (This point is not closest to the topic but guess it: behaving on hard memory is often similar to RAM one.)

  2. To move (to & from) a single string field you must use strncpy and a transient string buffer '\0' terminating. Somewhere you must remember the length of the record string field.

  3. To move other fields you can use the dot notation, ex.: NodeB->one=intvar; floatvar2=(NodeA->insidebisnode_subvar).myfl;

    struct mynode {
        int one;
        int two;
        char txt3[3];
        struct{char txt2[6];}txt2fi;
        struct insidenode{
            char txt[8];
            long int myl;
            void * mypointer;
            size_t myst;
            long long myll;
             } insidenode_subvar;
        struct insidebisnode{
            float myfl;
             } insidebisnode_subvar;
    } mynode_subvar;
    
    typedef struct mynode* Node;
    
    ...(main)
    Node NodeA=malloc...
    Node NodeB=malloc...
    
  4. You can embed each string into a structs that fit it, to evade point-2 and behave like Cobol: NodeB->txt2fi=NodeA->txt2fi ...but you will still need of a transient string plus one strncpy as mentioned at point-2 for scanf, printf otherwise an operator longer input (shorter), would have not be truncated (by spaces padded).

  5. (NodeB->insidenode_subvar).mypointer=(NodeA->insidenode_subvar).mypointer will create a pointer alias.
  6. NodeB.txt3=NodeA.txt3 causes the compiler to reject: error: incompatible types when assigning to type ‘char[3]’ from type ‘char *’
  7. point-4 works only because NodeB->txt2fi & NodeA->txt2fi belong to the same typedef !!

    A correct and simple answer to this topic I found at In C, why can't I assign a string to a char array after it's declared? "Arrays (also of chars) are second-class citizens in C"!!!

Community
  • 1
  • 1
splugenbrau
  • 11
  • 1
  • 3