1

I want to write a little program to learn C; here it is:

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

int total;
char suffix[3];
struct person {
    char id[11];
    char name[21];
    char sex[7];
    int age;
    char phone[12];
};

char* number_suffix (int number) {
    int mod;
    mod = number % 10;

    switch (mod) {
        case 1:
            strcpy(suffix, "st");
            break;
        case 2:
            strcpy(suffix, "nd");
            break;
        case 3:
            strcpy(suffix, "rd");
            break;
        default:
            strcpy(suffix, "th");
            break;
    }
    return suffix;
}

void input_info (struct person info[], int total_people) {
    int counter;
    for (counter=0; counter<total_people; counter++){
        printf("%s%d%s%s\n","Please input the ID(10 digits) of ", (counter+1),
                number_suffix(counter), " person: ");
        scanf("%s", info[counter].id);
        fflush(stdin);

        printf("%s%d%s%s\n", "Please input the Name(20 chars) of ", (counter+1),
                number_suffix(counter), " person: ");
        scanf("%[^\n]", info[counter].name);
        fflush(stdin);

        printf("%s%d%s%s\n", "Please input the Sex(Male/Female) of ", (counter+1),
                number_suffix(counter), " person: ");
        scanf("%s", info[counter].sex);
        fflush(stdin);

        printf("%s%d%s%s\n", "Please input the Age(1~100) of ", (counter+1),
                number_suffix(counter), " person: ");
        scanf("%d", &info[counter].age);
        fflush(stdin);

        printf("%s%d%s%s\n", "Please input the Phone of ", (counter+1),
                number_suffix(counter), " person: ");
        scanf("%s", info[counter].phone);
        fflush(stdin);
    }
    printf("%s\n%s\n%s\n%d\n%s\n", info[counter].id, info[counter].name, info[counter].sex, &info[counter].age, info[counter].phone);
}

int main (void) {
    printf("%s\n", "Please input a number that how many people you want to record:");
    scanf("%d", &total);
    fflush(stdin);
    struct person *person_info = malloc(sizeof(struct person)*total);
    input_info(person_info, total);

    free(person_info);
    return 0;
}

I found something weird, when I run it.

Please input a number that how many people you want to record:
1
Please input the ID(10 digits) of 1th person:
A01
Please input the Name(20 chars) of 1th person:
Please input the Sex(Male/Female) of 1th person:
Male
Please input the Age(1~100) of 1th person:
32
Please input the Phone of 1th person:
1224464
[empty line]
[empty line]
[empty line]
1926234464
[empty line]

Is that program skip scanf("%[^\n]", info[counter].name); this line when it run?

Why, and what causes it?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Joshua Lee
  • 121
  • 1
  • 9
  • 1
    `fflush(stdin)` is not recommended. In many implementations flushing an input stream is undefined behaviour. And in your particular case it is likely not getting rid of the newline character left there by the first `scanf`. See [scanf Getting Skipped](http://stackoverflow.com/questions/14484431/scanf-getting-skipped) – kaylum Jan 24 '16 at 06:13
  • "_How to understand the relation between pointers, struct, malloc, functions parameters?_" -- What? And that is too broad to be answered. So, I've removed it. – Spikatrix Jan 24 '16 at 06:38
  • `11st` , `12nd`, `13rd`? – Jasen Jan 24 '16 at 06:40
  • 1
    Please consult [Using `fflush(stdin)`](http://stackoverflow.com/questions/2979209/using-fflushstdin) for details — unless you're on a Windows system, it won't be doing what you want/expect. – Jonathan Leffler Jan 24 '16 at 06:44
  • 1
    You need to call `number_suffix(counter+1)` when you print `counter+1`. And don't forget that it is `11th`, `12th`, and `13th` (but `1st` and `21st`, `2nd` and `22nd`, `3rd` and `23rd`). – Jonathan Leffler Jan 24 '16 at 06:46
  • 1
    On the whole, you should check the result from `scanf()` each time to ensure you got what you expected. One basic technique when debugging a problem is to echo the input you just got to ensure that the computer got what you expected. – Jonathan Leffler Jan 24 '16 at 06:52

2 Answers2

1

fflush(stdin) is undefined as per the C standard, but it works on some implementations. But it is best to avoid it as it isn't portable and may invoke Undefined Behavior.

To fix the issue, replace all fflush(stdin)s with

int c; /* Declare it once */
while((c = getchar()) != '\n' && c != EOF); /* Discards everything until a newline character or EOF */

Another problem is with

printf("%s\n%s\n%s\n%d\n%s\n", info[counter].id, info[counter].name, info[counter].sex, &info[counter].age, info[counter].phone);

It should be

printf("%s\n%s\n%s\n%d\n%s\n", info[counter].id, info[counter].name, info[counter].sex, info[counter].age, info[counter].phone);

and should be placed inside the for loop. Otherwise, you invoke Undefined Behavior because

  1. You passed an int* for %d which expects an int.
  2. You access invalid memory location beyond the allocated memory segment.

Also, as others have said, pass counter + 1 to number_suffix.

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
  • There is no difference between the `printf` lines you say have a problem. Even the one you have posted as changed is the same. – Box Box Box Box Jan 24 '16 at 09:03
  • @AshishAhuja Look carefully. I removed the ampersand. – Spikatrix Jan 24 '16 at 09:36
  • Oops, my mistake :-( – Box Box Box Box Jan 24 '16 at 11:30
  • @CoolGuy Although the `printf` needs to placed inside the `for` loop so that it can print the info I needed, but the info that I inputted indeed in the memory that I get by using `malloc`, right? – Joshua Lee Jan 25 '16 at 03:19
  • @JoshuaLee Yes. But without putting it in the loop, you invoke undefined behavior as said in my answer (_You access invalid memory location beyond the allocated memory segment_) – Spikatrix Jan 25 '16 at 13:55
1
  1. Problem is with your scanf pattern. Use " %[^\n]" instead of "%[^\n]" to not catch \n (After previous data entry)
  2. Pass counter + 1 to number_suffix

How to understand the relation between pointers, struct, malloc, functions parameters?

Read Understanding and Using C Pointers from O'Reilly Media

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
pouyan
  • 307
  • 1
  • 5
  • 3
    The reason for using `%[^\n]` instead of `%s` is to allow people to have two (or more) names separated by a space (or spaces): `John Doe` etc. – Jonathan Leffler Jan 24 '16 at 07:01
  • Why the book advertisement? :-) – Box Box Box Box Jan 24 '16 at 08:24
  • @JonathanLeffler thanx for your comment. I fixed it. – pouyan Jan 24 '16 at 08:29
  • @CoolGuy you were right. Address of string(array) field will be retrieved when not accessing any item of an string(array). &(info[counter].id) ~= info[counter].id when passing byref – pouyan Jan 24 '16 at 08:33
  • @AshishAhuja It was based on the OP's question. [I removed it](http://stackoverflow.com/questions/34972783/scanf-n-gets-skipped/34973004?noredirect=1#comment57675611_34972783) as it was too broad. See the [original question before all edits](http://stackoverflow.com/revisions/34972783/1) – Spikatrix Jan 24 '16 at 09:38