0

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;
}
Ogu Himean
  • 19
  • 3
  • how you feed input ? – ntshetty May 10 '18 at 03:23
  • I open the cmd and run the program. Then enter these info. – Ogu Himean May 10 '18 at 03:25
  • 3
    turn up the warning level when you compile. `warning: ‘line’ may be used uninitialized in this function [-Wmaybe-uninitialized]`. iI'd also advise against using `gets`, use [`fgets`](https://stackoverflow.com/a/4309845/1540468) instead. – Paul Rooney May 10 '18 at 03:28

2 Answers2

1

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;
}
Brennen Sprimont
  • 1,564
  • 15
  • 28
0

You need to allocate memory before you use line with gets

#include <stdio.h>

int main()
{
    FILE *fp;
    struct profile
    {
        char *name;
        char *surname;
        int year;
        int month;
        int day;
    };
    struct profile people[10];
    int temp;
    int i = 0;
    char line[256]; //you can also do dynamic allocation by using malloc

    fp = fopen("reg.txt", "a");
   // while (gets(line) != NULL) //use fgets instead gets
    while( fgets(line, 256, stdin) ) //specify required buffer len
    {
        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;
}
ntshetty
  • 1,293
  • 9
  • 20
  • 2
    As `gets()` is depreciated in C99 and no longer standard in C11, I suggest posting a solution without using the poor function `gets()`. Perhaps `fgets()`? – chux - Reinstate Monica May 10 '18 at 03:31
  • Note the program will enter UB if the user enters a line of text longer than 256 characters. OP should use `fgets` or `gets_s` to prevent a buffer overflow. You also may want to zero-out the buffer too. – Dai May 10 '18 at 03:32
  • @chux & @Dai suggested in comment to use `fgets`, anyway updated the solution to use it. – ntshetty May 10 '18 at 03:37
  • 1
    ogu I think basically you've just progressed to the next issue. I would advise reading more about the pointers and functions you are using. You will make more progress with a solid understanding of the basics of the language. – Paul Rooney May 10 '18 at 03:37
  • ... and check the return value from `fopen` and `sscanf`. Ditto with `fprintf` – Ed Heal May 10 '18 at 03:43
  • Problem Updated – Ogu Himean May 10 '18 at 03:43
  • 4
    this answer didn't correct sscanf to non allocated pointers. Error remain the same – Jacek Cz May 10 '18 at 03:59