2

I'm sorry if this questions has already been asked, I searched a bit before posting, but couldn't find an answer to it.

I have this code:

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

#define ESC 27

typedef struct{
    int data[10];
    int n;
} tlist;

void menu(){
    printf("Options:\n");
    printf("1) Show list\n");
    printf("ESC) Quit\n");
}

void showList(tlist *list){
    int *p;
    p = &list->data[0];
    if(list->n == 0){
        printf("Empty list!\n\n");
    }else{
        for(int i=0; i<list->n; i++){
            printf("%d \n", *p);
            p++;
        }
    }
}

int main(){
    char choice;
    tlist list;
    list.n = 10;

    list.data[0] = 16;  
    list.data[1] = 17;
    list.data[2] = 18;
    list.data[3] = 19;
    list.data[4] = 20;
    list.data[5] = 21;
    list.data[6] = 22;
    list.data[7] = 23;
    list.data[8] = 24;
    list.data[9] = 25;
    do{
        menu();
        scanf("%s",&choice);
            switch(choice){
                case '1': showList(&list);
                    break;
                case ESC:
                    printf("quiting...\n");
                    break;
                default:
                    printf("Invalid Choice!\n");
                    break;      
            }
    }while(choice != ESC);
    return 0;
}

When I run this program I have this output:

0 17 18 19 20 21 22 23 24 25

I can't understand why the first print is the position of the first element in the array and not the first element itself. Can someone please explain me?

gr0gu3
  • 555
  • 1
  • 6
  • 11
  • 7
    `scanf("%s",&choice);` - that's wrong. `choice` is a single char. – Mat Sep 23 '18 at 18:37
  • Well, this part of the code is working anyway. – gr0gu3 Sep 23 '18 at 18:40
  • 3
    No, it's not. It sort of looks like it is but in fact you have undefined behavior. – Mat Sep 23 '18 at 18:42
  • Mat, you were right. Changed it for %c and it worked. But the code is giving me 2 outputs now: 16 17 18 19 20 21 22 23 24 25 Choose option: 1) Show list ESC) Quit Invalid option! – gr0gu3 Sep 23 '18 at 18:44
  • 2
    `char choice;` does not go with `scanf("%s",&choice);` or even with `scanf("%s",choice);` which expects an array. I suggest `scanf(" %c", &choice);` note the space before `%c` because [scanf() leaves the newline char in the buffer](https://stackoverflow.com/questions/5240789/scanf-leaves-the-new-line-char-in-the-buffer). – Weather Vane Sep 23 '18 at 18:47
  • (" %c", &choice) worked perfectly! Thank you Mat and Vane for the explanation! – gr0gu3 Sep 23 '18 at 18:49
  • probable UB explanation: when you enter a 1 for the wrong `"%s"` in scanf, it may write the string (`"%s"`) null terminator to `list.data[0]` overwriting the initial 16. – pmg Sep 23 '18 at 19:08
  • gr0gu3, What compiler are you using that does not warn about `char choice;... scanf("%s",&choice);`? – chux - Reinstate Monica Sep 23 '18 at 19:48
  • 1
    @chux gcc -Wall does not give a warning. I doubt that it should: Since variable ``choice'' is a char, &choice matches the format string "%s", methinks. – Tano Fotang Sep 23 '18 at 22:32
  • 1
    @chux I use GCC – gr0gu3 Sep 25 '18 at 02:44

1 Answers1

1

choice is a char and the correct conversion specifier to be used in scanf is c and not s.

One must also be careful when using scanf interspersed with printf statements which print new lines (\n).

When scanf has the conversion specifier c, then it will interpret any whitespace as a character and will not wait for the actual input. So the scanf here should make allowance for the whitespace character by including a leading blank space.

So the scanf statement should be:

scanf(" %c", &choice);

It is also a good practice to check the return value of scanf before proceeding further in the program. As per the standard, scanf returns the number of input items assigned, which can be fewer than provided for, or even zero, in the event of an early matching failure.

P.W
  • 26,289
  • 6
  • 39
  • 76