0

I would like to know why Jack and George's names fail to print. I tried adding another member in the struct the names get printed normally, why is that ? I would really appreciate it if someone can help. Here's the code:

    #include <stdio.h>
    typedef unsigned short int u16;
    typedef unsigned char u8;
    typedef struct 
    {
     u8 name[10];
     u16 salary;
     u16 bonus;
     u16 deduction;
     //u8 x;//why does the printed name get ruined 
     //without this?
     }employee;
     void main (void)
     {
       employee arr[3]={{.name = "John"},{.name = 
        "Jack"},{.name = "George"}};
       u16 i = 0;
       u16 sum = 0; 
       for (i = 0; i < 3; i++)
{
    printf("\nPlease enter %s's Salary:",arr[i].name);
    scanf(" %d",&arr[i].salary);
    printf("\nPlease enter %s's Bonus:",arr[i].name);
    scanf(" %d",&arr[i].bonus);
    printf("\nPlease enter %s's Deduction:",arr[i].name);
    scanf(" %d",&arr[i].deduction);
    sum = sum + arr[i].salary + arr[i].bonus - arr[i].deduction;
}
    printf("\nTotal value needed is: %d",sum);
}
Nemo
  • 85
  • 2
  • 11
  • but you're showing the code that _works_ right? can you show what changes you made exactly / or the code which _doesn't_ work? – Jean-François Fabre Dec 04 '18 at 21:21
  • 5
    You are using the wrong format specifier in `scanf` which leads to memory corruption. An easy fix is to change to reading an `int` instead of "u16" (which you shouldn't be definiing yourself anyway since the language already provides fixed width types) – M.M Dec 04 '18 at 21:21
  • 2
    turn all warnings on (see MM comment) – Jean-François Fabre Dec 04 '18 at 21:22
  • @M.M which format specifier should I use instead of %d then? – Nemo Dec 04 '18 at 21:23
  • @Jean-FrançoisFabre the code doesn't work with " u8 x" commented – Nemo Dec 04 '18 at 21:24
  • 2
    `%hu` would be correct in this case. But I would recommend reading into an `int` and then assigning that back to your struct field. – M.M Dec 04 '18 at 21:25
  • 1
    [What is the format specifier for unsigned short int?](//stackoverflow.com/q/8699812) – 001 Dec 04 '18 at 21:25
  • @Nemo, `%d` will read into `int`. `%hu` is closest you get to `u16`, but its not guaranteed. – mvp Dec 04 '18 at 21:26
  • 1
    If it is a memory corruption, then changing the 'shape' of the memory (like by adding more fields or variables on the stack, for example) sometimes causes the corruption to happen on a part of the memory that is not used, or that is used for something else (causing either no symptoms, or a different symptom) – Basya Dec 04 '18 at 21:26
  • @M.M I thought that the memory widths sometimes differ from a compiler to another e.g sometimes int is 2 bytes and other times it's 4 bytes isn't this true ? – Nemo Dec 04 '18 at 21:27
  • 1
    @Nemo `%hu` is defined as the specifier for reading `unsigned short` regardless of sizes, which is what the code has (it defines u16 as typedef for unsigned short) – M.M Dec 04 '18 at 21:28
  • @M.M I tried '%hu' and it works fine thanks a lot. – Nemo Dec 04 '18 at 21:32
  • @Jean-FrançoisFabre how do I turn the warnings on ? I am using a gcc compiler. – Nemo Dec 04 '18 at 21:38

1 Answers1

3

It's because your scanf()'s are wrong, and are overwriting members of your struct.

A decent compiler will issue a lot of warnings that are very severe:

$ gcc -Wall t.c
t.c:13:11: warning: return type of ‘main’ is not ‘int’ [-Wmain]
      void main (void)
           ^~~~
t.c: In function ‘main’:
t.c:22:14: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘u16 *’ {aka ‘short unsigned int *’} [-Wformat=]
     scanf(" %d",&arr[i].salary);
             ~^  ~~~~~~~~~~~~~~
             %hd
t.c:24:14: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘u16 *’ {aka ‘short unsigned int *’} [-Wformat=]
     scanf(" %d",&arr[i].bonus);
             ~^  ~~~~~~~~~~~~~
             %hd
t.c:26:14: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘u16 *’ {aka ‘short unsigned int *’} [-Wformat=]
     scanf(" %d",&arr[i].deduction);
             ~^  ~~~~~~~~~~~~~~~~~
             %hd

When you are calling scanf(" %d",&arr[i].salary); , the %d says to store the number you read as an int type.

However you have declared salary as a u16 type, which on your system is probably a lot smaller than an int. scanf jsut assumes you were telling the truth when you provided %d ,and stores an int in whatever the &arr[i].salary pointer points to, overwriting memory after that variable which might overwrite and trash the name array.

So either

  • declare your salary, bonus and deduction as int instead of u16, so it matches the %d argument you give to scanf or
  • Provide a proper type specifier to scanf for your u16 variables, which is %hu.

e.g.

   scanf(" %hu",&arr[i].salary);
   scanf(" %hu",&arr[i].bonus);
   scanf(" %hu",&arr[i].deduction);
nos
  • 223,662
  • 58
  • 417
  • 506