Dr Spec
Dr Spec

Reputation: 23

Get input with fscanf

I am building a program that enables the user to enter a movie and prints out the information that the user entered.

I'm using a struct to define the variables of a movie. The problem is that when the user enter the first to fscanf() with a space. Example: "Miami Vice" all of the other puts() prints after each other. The stdin do not work after. And I dont know why this is happening.

I've been reading about gets() and it has security issues so I should instead using fgets() or fscanf() for this. But I can't figure out what the problem is here.

main.c

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

int main()
{
    struct movie m;

    puts("What was the title of the movie you saw?");
    fscanf(stdin, "%s", m.title);
    puts("What was the relase year?");
    fscanf(stdin, "%d", &m.year);
    puts("How would you rate the movie? (1-10)");
    fscanf(stdin, "%d", &m.rate);

    printf("You saw the movie %s which was released %d and you rated it a %d", m.title, m.year, m.rate);

    return 0;
}

main.h

struct movie {
    char title[40];
    int rate;
    int year;
};

Upvotes: 1

Views: 2560

Answers (2)

user4925
user4925

Reputation: 209

Try to use fgets() whenever reading strings as inputs. Anyways here is the code to which I modified a bit. Feel free to modify the code to your own needs.

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

struct movie {
    char title[40];
    int rate;
    int year;
};

int main(){

   struct movie m;
   char *newline_char=NULL;

   puts("What was the title of the movie you saw?");
   fgets(m.title,40,stdin);

   //The below two lines of code are used to remove the '\n'
   //character from the input since fgets() also stores the '\n'
   //character. Replace the '\n' char with '\0' character.
   if((newline_char=strchr(m.title,'\n')) != NULL){
    *newline_char = '\0';
   }

   puts("What was the relase year?");
   fscanf(stdin, "%d", &m.year);
   puts("How would you rate the movie? (1-10)");
   fscanf(stdin, "%d", &m.rate);

   printf("You saw the movie %s which was released %d and you rated it a %d", m.title, m.year, m.rate);
   return 0;
}

As chux recommends, You can also use only fgets() and avoid fscanf() as shown below in the code,

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

struct movie {
    char title[40];
    int rate;
    int year;
};

int main(){

    struct movie m;
    char *newline_char=NULL;
    char input[256];

    puts("What was the title of the movie you saw?");
    fgets(m.title,40,stdin);

    if((newline_char=strchr(m.title,'\n')) != NULL){
       *newline_char = '\0';
    }

    puts("What was the relase year?");
    fgets(input,256,stdin);
    sscanf(input,"%d",&m.year);
    puts("How would you rate the movie? (1-10)");
    fgets(input,256,stdin);
    sscanf(input,"%d",&m.rate);

    printf("You saw the movie %s which was released %d and you rated it a %d", m.title, m.year, m.rate);
    return 0;
}

Upvotes: 1

chqrlie
chqrlie

Reputation: 144951

The %s format instructs scanf to read a single word. White space acts as a word separator, hence only Miami gets parsed into m.title and Vice stays in the input stream. Subsequent calls to scanf with a %d format fail to parse an integer from the stream and return 0, leaving m.yearand m.date uninitialized. You therefore invoke undefined behavior when printing their values with the last call to printf.

You can correct the problem with a different format: %[^\n]. Furthermore, you should prevent scanf from writing beyond the end of m.title with a width specifier: %39[^\n]. An additional before the format will skip white space if any is present before the movie title. An additional %*c would read the \n but is not required since the subsequent scanf("%d",...) will skip leading white space including the \n left pending in the input stream.

Here is a modified version of your program:

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

struct movie {
    char title[40];
    int rate;
    int year;
};

int main(void) {
    struct movie m;

    puts("What was the title of the movie you saw?");
    if (scanf(" %39[^\n]", m.title) != 1)
        return 1;
    puts("What was the release year?");
    if (scanf("%d", &m.year) != 1)
        return 1;
    puts("How would you rate the movie? (1-10)");
    if (scanf("%d", &m.rate) != 1)
        return 1;

    printf("You saw the movie %s which was released in %d and you rated it a %d\n",
           m.title, m.year, m.rate);

    return 0;
}

Upvotes: 0

Related Questions