I am extremely new to working in C so forgive me if I have just made a simple error but I am extremely confused. My code is as follow:
#include <stdio.h>
#include <string.h>
int
main ()
{
char first[10],last[10],address[20],city[10],state[3],zipcode[5];
printf("\n\nPart 3:\n");
printf("Please enter your name and address:\n");
printf("First Name: ");
scanf("%s", first);
printf("Last Name: ");
scanf("%s", last);
printf("Address: ");
fgetc(stdin);
fgets(address, 20, stdin);
address[strcspn(address,"[/r/n]")] = 0;
printf("City: ");
scanf("%s", city);
printf("State: ");
scanf("%s", state);
printf("Zipcode: ");
scanf("%s", zipcode);
printf("%s %s\n%s%s, %s, %s",first,last,address,city,state,zipcode);
return 0;
}
Everything works except when the final print statement is read first is not output, it just begins with last name. Example:
For the input
Please enter your name and address:
First Name: Ben
Last Name: Johnson
Address: 1234 Smith St
City: Townsville
State: CA
Zipcode: 12345
I get the following output:
Johnson
1234 Smith St
Townsville, CA, 12345
Just not sure where it is going wrong as my first is being inputted the exact same way as my other variables that are working.
CodePudding user response:
You are writing to the arrays city
and zipcode
out of bounds, which causes undefined behavior.
The input string Townsville
is 10
characters long, so it requires 11
characters including the terminating null character. However, the array city
only has space for 10
characters, so it is not large enough to store that string. Therefore, when scanf
attempts to store Townsville
into city
, it will overflow the buffer.
The array zipcode
has the same problem. For the stated input 12345
it requires 6 characters (including the terminating null character), but you only gave the array space for 5
characters.
In order to prevent this kind of problem in the future, I recommend that that you use fgets
for all data, as fgets
will never overflow the buffer, provided that you pass the correct size of the buffer (which you are doing in your posted code). However, this would mean a lot of extra code, because you would also have to write code to remove the newline character every time you call fgets
. For this reason, it would probably be best to write your own function. This function could also verify that the entire line was read in, and print an error message if the buffer was not large enough.
I have rewritten your code to use such a function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void get_line_from_user( char *buffer, int buffer_size );
int main( void )
{
char first[10],last[10],address[20],city[10],state[3],zipcode[5];
printf("Part 3:\n");
printf("Please enter your name and address:\n");
printf("First Name: ");
get_line_from_user( first, sizeof first );
printf("Last Name: ");
get_line_from_user( last, sizeof last );
printf("Address: ");
get_line_from_user( address, sizeof address );
printf("City: ");
get_line_from_user( city, sizeof city );
printf("State: ");
get_line_from_user( state, sizeof state );
printf("Zipcode: ");
get_line_from_user( zipcode, sizeof zipcode );
printf("%s %s\n%s%s, %s, %s",first,last,address,city,state,zipcode);
return 0;
}
//This function will read exactly one line of input from the
//user. On failure, the function will never return, but will
//print an error message and call "exit" instead.
void get_line_from_user( char *buffer, int buffer_size )
{
char *p;
//attempt to read one line of input
if ( fgets( buffer, buffer_size, stdin ) == NULL )
{
printf( "Error reading from input\n" );
exit( EXIT_FAILURE );
}
//attempt to find newline character
p = strchr( buffer, '\n' );
//make sure that entire line was read in (i.e. that
//the buffer was not too small to store the entire line)
if ( p == NULL )
{
//a missing newline character is ok if the next
//character is a newline character or if we have
//reached end-of-file (for example if the input is
//being piped from a file or if the user enters
//end-of-file in the terminal itself)
if ( getchar() != '\n' && !feof(stdin) )
{
printf( "Line input was too long!\n" );
exit( EXIT_FAILURE );
}
}
else
{
//remove newline character by overwriting it with
//null character
*p = '\0';
}
}
Now the program will give you a proper error message if the input is too long, instead of overflowing the buffer:
Part 3:
Please enter your name and address:
First Name: Ben
Last Name: Johnson
Address: 1234 Smith St
City: Townsville
Line input was too long!