# Why do we get a wrong result?

#### evinda

##### Well-known member
MHB Site Helper
Hello!!!

I have a code in C where the user has to give information (id, name, surname, grade) of a student.

The id must be 5 characters, the name and the surname at most 50 characters.

The code is:
Code:
#include <stdio.h>
#include <stdlib.h>

struct student
{
char id[5];
char name[50];
char surname[50];
};

void GetInformation(struct student *ptr){
printf("Enter ID of the student: ");
scanf("%s", ptr->id);
printf("Enter the name of the student: ");
scanf("%s", ptr->name);
printf("Enter the surname of the student: ");
scanf("%s", ptr->surname);
printf("Enter the grad of the student: ");
}

int main() {
int i=0, num;
printf("Enter the number of students: ");
scanf("%d", &num);
struct student *students = malloc( num*sizeof(struct student) );
struct student *ptr=students;
for (i=0; i<num; i++){
GetInformation(ptr);
printf("\nThe ID of the student is: %s.\n", students[i].id);
printf("The name of this student is %s and the surname is %s.\n", students[i].name, students[i].surname);
ptr++;
}
return 0;
}
At the output I gave the following information and I get the following results:
Code:
Enter the number of students: 1
Enter ID of the student: 12345
Enter the name of the student: Lea
Enter the surname of the student: Smith
Enter the grad of the student: 5

The ID of the student is: 12345Lea.
The name of this student is Lea and the surname is Smith.
The grade is 5.000000.
Why at the printed ID we get ID and name together? I noticed after doing several examples that if I give ID's with less characters then it is printed normally. This occurs when I give 5 characters. Why does this occur? Where is a mistake at the program?

#### Klaas van Aarsen

##### MHB Seeker
Staff member
Why at the printed ID we get ID and name together? I noticed after doing several examples that if I give ID's with less characters then it is printed normally. This occurs when I give 5 characters. Why does this occur? Where is a mistake at the program?
A string in C must always be terminated by a '\0' character.
It identifies where the string ends.
When we put "12345" into the char id[5] with scanf, we automatically also get a '\0' character as the 6th character, which is out of bounds and causes havoc.
When we enter the 'name' that 6th character gets overwritten, so that when we print the student id, C keeps printing beyond the end of the actual student id.

We can fix it if we make each character array one bigger than the maximum number of characters that we need to store in it.
That is, we should have:
Code:
struct student
{
char id[5+1];
char name[50+1];
char surname[50+1];
};

Additionally we should probably make the code robust against a user entering more characters than the character array can hold.

#### evinda

##### Well-known member
MHB Site Helper
A string in C must always be terminated by a '\0' character.
It identifies where the string ends.
When we put "12345" into the char id[5] with scanf, we automatically also get a '\0' character as the 6th character, which is out of bounds and causes havoc.
When we enter the 'name' that 6th character gets overwritten, so that when we print the student id, C keeps printing beyond the end of the actual student id.

We can fix it if we make each character array one bigger than the maximum number of characters that we need to store in it.
That is, we should have:
Code:
struct student
{
char id[5+1];
char name[50+1];
char surname[50+1];
};

Additionally we should probably make the code robust against a user entering more characters than the character array can hold.
To check if the given surname doesn't contain the empty space do we check that with the command "strchr(ptr->surname,' ') != NULL" ? I tried this but although I gave as input a word with space it didn't recognized it.

For this I changed the function like this:
Code:
void GetInformation(struct student *ptr){
printf("Enter ID of the student: ");
scanf("%s", ptr->id);
printf("Enter the name of the student: ");
scanf("%s", ptr->name);
printf("Enter the surname of the student: ");
scanf("%s", ptr->surname);
if (strchr(ptr->surname,' ') != NULL){
printf("The surname has empty space");
printf("Enter the surname of the student: ");
scanf("%s", ptr->surname);
}
printf("Enter the grad of the student: ");
}
And at the ouput I got
Code:
Enter the number of students: 1
Enter ID of the student: 12345
Enter the name of the student: Lea
Enter the surname of the student: Smith A
Enter the grad of the student:
The ID of the student is: 12345Lea.
The name of this student is Lea and the surname is Smith.
The grade is 0.000000.
What is wrong?

#### Klaas van Aarsen

##### MHB Seeker
Staff member
When we use scanf with %s we get a string from the input up to a white space.
So we didn't get the full surname, but only the part up the space.
That's why we can't find a space in it.

#### evinda

##### Well-known member
MHB Site Helper
When we use scanf with %s we get a string from the input up to a white space.
So we didn't get the full surname, but only the part up the space.
That's why we can't find a space in it.
Do we have to use fgets instead of scanf? I tried: "fgets(ptr->surname, sizeof(ptr->surname), stdin);" but it doesn't work....
Or isn't it possible to check for empty spaces at an input?

#### Klaas van Aarsen

##### MHB Seeker
Staff member
Yes, fgets is a way to get the full surname.
Your problem will be that there is still unread data in the input that interfers.

We can call getchar() repeatedly until it returns '\n' (new line) to get rid of the unread input before surname.
Or alternatively we can make a call to fgets() beforehand with a dummy buffer.

Last edited:

#### evinda

##### Well-known member
MHB Site Helper
I found online that we could use:
Code:
scanf("%c",&temp);
scanf("%[^\n]", ptr->surname);
instead of the scanf I used above and this works!!! Could you explain to me why we need this temporary variable 'temp' and what '%[^\n]' means?

#### Klaas van Aarsen

##### MHB Seeker
Staff member
I found online that we could use:
Code:
scanf("%c",&temp);
scanf("%[^\n]", ptr->surname);
instead of the scanf I used above and this works!!! Could you explain to me why we need this temporary variable 'temp' and what '%[^\n]' means?
We scan a "%c" to get rid of the new line ('\n') that is still in the input after the previous scanf command of the 'name'.
It corresponds to the Enter key, which puts a new line character in the input.
When we scanf for "%c", we need to provide a variable to put the result into. That is what the 'temp' variable is for.
Alternatively we can use scanf("%*c"). The * means that we are not interested in the value, so that we don't need a 'temp' variable.

The "%[^\n]" is a special syntax that means that we want to read a string that consists of any character other than a '\n' (new line).
In particular that includes spaces.
More specifically, the caret (^) means NOT. And the part between square brackets ([]) is a so called search set.
We can specify patterns of characters we want to allow - or, as in this case, which characters we want to disallow.

For the record, this method with scanf("%c", &temp) is not fullproof, because if the previous string that we scanned ('name') ended with a space, the scanf of "%c" will not do what we want, because then the '\n' character won't be the next unread character in the input.
Instead we can replace the code you have by:
Code:
scanf(" %[^\n]", ptr->surname);
Note the space at the beginning, which will ensure any 'white space' is skipped before reading the surname.
That 'white space' includes any spaces or new line characters, which should be skipped.

Last edited: