Reputation: 23
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
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
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.year
and 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