Why does the ID and name get printed together when the ID is 5 characters?

  • Context: MHB 
  • Thread starter Thread starter evinda
  • Start date Start date
Click For Summary

Discussion Overview

The discussion revolves around a C programming issue related to handling string inputs for student information, specifically focusing on the behavior of character arrays and the use of input functions like scanf. Participants explore the implications of string termination and the handling of whitespace in user input.

Discussion Character

  • Technical explanation
  • Debate/contested
  • Exploratory

Main Points Raised

  • One participant describes a problem where the ID and name are printed together when the ID is exactly 5 characters long, suggesting a potential buffer overflow issue due to the lack of a null terminator.
  • Another participant explains that the string in C must be terminated by a '\0' character, and that the ID array defined as char id[5] does not account for this, leading to undefined behavior when printing.
  • Some participants propose increasing the size of the character arrays to accommodate the null terminator, suggesting changes to the struct definition.
  • There is a discussion about checking for spaces in the surname input, with one participant noting that using scanf with %s only captures input up to the first whitespace, which complicates the validation of surnames with spaces.
  • Several participants suggest using fgets instead of scanf to capture full input, but express concerns about handling leftover input in the buffer that may interfere with subsequent reads.
  • One participant shares a solution involving the use of a temporary variable and a specific scanf format specifier to read the surname correctly, prompting questions about the mechanics of this approach.

Areas of Agreement / Disagreement

Participants generally agree that the original code has issues related to string termination and input handling, but there is no consensus on the best approach to resolve these issues, with multiple proposed solutions and methods discussed.

Contextual Notes

Limitations include the potential for buffer overflow due to insufficiently sized character arrays and the challenge of handling user input that includes spaces. The discussion does not resolve the best practices for input handling in C.

evinda
Gold Member
MHB
Messages
3,741
Reaction score
0
Hello! (Wave)

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];
    float grade;
};

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: ");
    scanf("%f", &ptr->grade);
}

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);
        printf("The grade is %f.", students[i].grade);
        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? (Thinking)
 
Technology news on Phys.org
evinda said:
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. :eek:
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];
    float grade;
};
(Nerd)

Additionally we should probably make the code robust against a user entering more characters than the character array can hold. (Thinking)
 
Klaas van Aarsen said:
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. :eek:
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];
    float grade;
};
(Nerd)

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

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: ");
    scanf("%f", &ptr->grade); 
}

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? (Thinking)
 
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. (Nerd)
 
Klaas van Aarsen said:
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. (Nerd)
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? 🧐
 
Yes, fgets is a way to get the full surname. (Nod)
Your problem will be that there is still unread data in the input that interfers. :eek:

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:
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? 🧐 🧐
 
evinda said:
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. (Nerd)

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. (Nerd)

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. (Sun)
 
Last edited:

Similar threads

  • · Replies 2 ·
Replies
2
Views
2K
Replies
2
Views
2K
  • · Replies 5 ·
Replies
5
Views
4K
  • · Replies 2 ·
Replies
2
Views
3K
  • · Replies 4 ·
Replies
4
Views
2K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 6 ·
Replies
6
Views
4K
  • · Replies 4 ·
Replies
4
Views
2K
  • · Replies 5 ·
Replies
5
Views
2K