Search code examples
cscanffgetsgets

Why doesn't this program work?


When I was working on the C Programming Language, I wanted to do a little program to revise these previous knowledge points. And this is the program which it seems there are some problems with it.

This program is supposed to collect information from input and print it in the file "reg.txt" in a format.

However, after typing the first line and press the enter, the program quits, but I can't figure it out what's wrong with it.

#include <stdio.h>

int main()
{
    FILE *fp;
    struct profile
    {
        char *name;
        char *surname;
        int year;
        int month;
        int day;
    } people[10];
    int temp;
    int i = 0;
    char *line;


    fp = fopen("reg.txt", "a");
    while (fgets(line, 256, stdin)
    {
        sscanf(line, "%s %s %d/%d/%d", people[i].name, people[i].surname, &(people[i].year), &(people[i].month), &(people[i].day));
        ++i;
    }
    temp = i-1;

    for (i = 0; i <= temp; ++i)
        fprintf(fp, "NAME: %s %s\nBIRTHDAY: %d/%d/%d\n", people[i].name, people[i].surname, people[i].year, people[i].month, people[i].day);

    fclose(fp);
    return 0;
}

I've taken Ed Heal's advice and I was aim to check the return value of 'sscanf'. What's strange is that the program doesn't really reach the 'printf' part. I thought may there are some problems with the loop?

#include <stdio.h>

int main()
{
    FILE *fp;
    void filecopy(FILE *, FILE *);
    struct profile
    {
        char *name;
        char *surname;
        int year;
        int month;
        int day;
    } people[10];
    int temp;
    int i = 0;
    char *line;
    int j;


    fp = fopen("reg.txt", "a");
    while (fgets(line, 256, stdin) != NULL)
    {
        j = sscanf(line, "%s %s %d/%d/%d", people[i].name, people[i].surname, &(people[i].year), &(people[i].month), &(people[i].day));
        ++i;
    }
    temp = i-1;

    //for (i = 0; i <= temp; ++i)
    //  fprintf(fp, "NAME: %s %s\nBIRTHDAY: %d/%d/%d\n", people[i].name, people[i].surname, people[i].year, people[i].month, people[i].day);

    printf("%d",j);
    fclose(fp);
    return 0;
}

Solution

  • Even after making sure line has allocated memory, you should be getting a segfault on your sscanf when it tries to write to people[0].name and people[0].surname because those pointers will be undefined.

    You need to allocate memory for these strings, either statically or dynamically (with malloc).

    Printing log statements can also help quite a bit to gather some insight.

    #include <stdio.h>
    
    int main()
    {
        FILE *fp;
        typedef struct
        {
            char name[64];
            char surname[64];
            int year;
            int month;
            int day;
        } profile;
        profile people[10];
    
        int temp;
        int i = 0;
        char line[512];
    
        printf("Starting profile line parser...\n");
        printf("Please enter up to 10 people in the format: (name surname year/month/day)\n");
        printf("Enter EOF to exit. (Linux: CTRL+D     Windows CTRL+Z)\n");
        fp = fopen("reg.txt", "a");
        while (gets(line) != NULL)
        {
            sscanf(line, "%63s %63s %d/%d/%d", people[i].name, people[i].surname, &(people[i].year), &(people[i].month), &(people[i].day));
            ++i;
        }
        printf("Processed %d lines.\n", i);
        temp = i-1;
        for (i = 0; i <= temp; ++i)
        {
            fprintf(fp, "NAME: %s %s\nBIRTHDAY: %d/%d/%d\n", people[i].name, people[i].surname, people[i].year, people[i].month, people[i].day);
        }
    
        fclose(fp);
        printf("Done with profile line parser...\n");
        return 0;
    }
    

    EDIT: Because gets is deprecated, here is a fgets alternative. Further reading on gets: Why is the gets function so dangerous that it should not be used?

    EDIT: Also adding chux's buffer overflow protection. Further reading on preventing buffer overruns with scanf: Read no more than size of string with scanf()

    #include <stdio.h>
    
    int main()
    {
        FILE *fp;
        typedef struct
        {
            char name[64];
            char surname[64];
            int year;
            int month;
            int day;
        } profile;
        profile people[10];
    
        int temp;
        int i = 0;
        char line[512];
    
        printf("Starting profile line parser...\n");
        printf("Please enter up to 10 people in the format: (name surname year/month/day)\n");
        printf("Enter EOF to exit. (Linux: CTRL+D     Windows CTRL+Z)\n");
        fp = fopen("reg.txt", "a");
        while (fgets(line, 512, stdin) != NULL)
        {
            sscanf(line, "%63s %63s %d/%d/%d", people[i].name, people[i].surname, &(people[i].year), &(people[i].month), &(people[i].day));
            ++i;
        }
        printf("Processed %d lines.\n", i);
        temp = i-1;
        for (i = 0; i <= temp; ++i)
        {
            fprintf(fp, "NAME: %s %s\nBIRTHDAY: %d/%d/%d\n", people[i].name, people[i].surname, people[i].year, people[i].month, people[i].day);
        }
        printf("Done with profile line parser...\n");
        fclose(fp);
        return 0;
    }