Christian Christmann <pl*****@yahoo.de> writes:
I was wondering how the =operator works for
struct.
By copying the values of all the members. It can either copy them one
at a time or, more likely, by doing the equivalent of a memcpy() on
the entire structure.
When I for example define a struct as follows:
struct point {
int a;
char *c;
};
and create the first struct
struct point p1 = { 10, "Hallo" };
and then create another struct and assign it struct p1
struct point p2;
p2 = p1;
it seams that all elements are copied properly, i.e.
a new variable is created for 'a' but also, what is more interesting,
an independent string char* 'c' is generated since a
modification to p1.c does not affect p2.c.
Does this mean that structs can be assigned by '=' without any
problems even if they contain (pointer to) nested structs as
elements?
No, it doesn't. If a structure contains pointers, copying it by
assignment to another structure object just copies the pointers; both
pointers will point to the same external object. To use the jargon,
struct assignment does a "shallow copy", not a "deep copy".
p1.c, a pointer, is part of the structure, and is copied by the
assignment. The string that p1.c points to is not part of the
structure, and is not copied by the assignment.
Given the code above, you can modify p2.c without affecting p1 (just
as you can modify p2.a without affecting p1), but you can't modify
what p2.c points to without affecting p1 (or rather, affecting what
p1.c points to).
And in this case, since p1.c and p2.c both point to a string literal,
you can't legally modify it at all (attempting to do so invokes
undefined behavior).
Here's a program that illustrates what happens. Note that I've
initialized p1.c to point to a (non-const) array object rather than to
a string literal, so modifying the string is allowed.
================================
#include <stdio.h>
int main(void)
{
char hello[] = "hello";
struct point {
int a;
char *c;
};
struct point p1 = { 10, hello };
struct point p2;
p2 = p1;
printf("p1 = { %d, %p --> \"%s\" }\n", p1.a, (void*)p1.c, p1.c);
printf("p2 = { %d, %p --> \"%s\" }\n", p2.a, (void*)p2.c, p2.c);
printf("Modifying p2.c[0]\n");
p2.c[0] = 'J';
printf("p1 = { %d, %p --> \"%s\" }\n", p1.a, (void*)p1.c, p1.c);
printf("p2 = { %d, %p --> \"%s\" }\n", p2.a, (void*)p2.c, p2.c);
printf("Modifying p2.c\n");
p2.c = "Good-bye";
printf("p1 = { %d, %p --> \"%s\" }\n", p1.a, (void*)p1.c, p1.c);
printf("p2 = { %d, %p --> \"%s\" }\n", p2.a, (void*)p2.c, p2.c);
return 0;
}
================================
The output is:
p1 = { 10, 0x22eeb0 --> "hello" }
p2 = { 10, 0x22eeb0 --> "hello" }
Modifying p2.c[0]
p1 = { 10, 0x22eeb0 --> "Jello" }
p2 = { 10, 0x22eeb0 --> "Jello" }
Modifying p2.c
p1 = { 10, 0x22eeb0 --> "Jello" }
p2 = { 10, 0x40205d --> "Good-bye" }
Keep in mind that the printf with a "%p" format prints its argument (a
pointer), while printf with a "%s" format prints what its argument
points to (a string).
--
Keith Thompson (The_Other_Keith)
ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.