Search code examples
cgccstructfgets

C input issue


================================================================

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 changing...


Solution

  • 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);
    }