================================================================
typedef struct {
union {
struct {
char fn[5];
char ln[5];
} fullname;
char name[5+5+1];
}
unsigned int age;
unsigned int area_code;
} my_struct;
The above is a struct that I have no control over. I personally am not a fan, but the struct is "legal".
================================================================
My code:
void caller {
my_struct str;
str = (my_struct){}; //initialise
fill(&str);
printf("%s [%s/%s]\n", str.name, str.fullname.fn, str.fullname.ln); // PROBLEM!
}
void fill(my_struct * str) {
//first name
printf("Enter first name: ");
fgets(str.fullname.fn, sizeof(str.fullname.fn), stdin);
if (str.fullname.fn[strlen(str.fullname.fn) - 1] == '\n')
str.fullname.fn[strlen(str.fullname.fn) - 1] = '\0';
//last name
printf("Enter last name: ");
fgets(str.fullname.ln, sizeof(str.fullname.fn), stdin);
if (str.fullname.ln[strlen(str.fullname.ln) - 1] == '\n')
str.fullname.ln[strlen(str.fullname.ln) - 1] = '\0';
sprintf(str.name, "%s %s", str.fullname.fn, str.fullname.ln);
printf("Age: ");
scanf("%ud", &str.age);
getchar();
printf("Area Code: ");
scanf("%ud", &str.area_code);
getchar();
}
================================================================
If the input was:
- joe
- moe
- 18
- 214
The printout at // PROBLEM
is:
joe moe [joe moe/oe]
instead of
joe moe [joe/moe]
Any ideas? I cannot, for the life of me, figure out why the values of fn and ln are 开发者_StackOverflow社区changing...
The problem is that name
and fullname
share the memory (because of the union
). So
sprintf(str.name, "%s %s", str.fullname.fn, str.fullname.ln);
also writes over fn
and ln
.
Not a bad question, but I don't really see how to cleanly solve this. The way I'd do it: get rid of the sprintf
above, and do it on your own.
void caller
{
fill(&str);
printf("%s %s [%s/%s]\n", str.fullname.fn, str.fullname.ln, str.fullname.fn, str.fullname.ln);
}
the problem is here:
sprintf(str.name, "%s %s", str.fullname.fn, str.fullname.ln);
sprintf can't operate on overlapping memory regions.
What you can do is to NOT put a \0
after the first name, but a space instead of the \n
and just print str.name
.
Also, initialize the array with ' '
(spaces) it would make inputs for the 1st name that are less than 5 chars.
memset(&str, ' ', sizeof(str));
The name part of the struct is a union, so it's either name
or fullname
, but not both at the same time. So after setting name the field fullname is invalid. The problem with unions is that you have to provide a mechanism for detecting which part of the union is actually used. I don't see anything here to decide whether name or fullname is used.
精彩评论