Unexpected results when trying to prevent stack overflow - c

I'm trying to secure the fields below by specifying the width of the variables so that buffer overflow will not occur. I would prefer not to use fgets() as I am trying to write something within the specifications I have been given (using scanf).
The code is below:
char firstName[11], surName[21], job[16];
printf("Enter first name: ");
scanf("%10s", firstName);
printf("Enter surname: ");
scanf("%20s", surName);
printf("Enter job: ");
scanf("%15s", job);
So for input like so:
Enter first Name: UmbertoOverflow
/*surName gets skipped over*/
Enter job: janitor
I get:
First name: UmbertoOve
Surname: rflow
Job: janitor
It doesn't give me a chance to enter surname, it just fills with the remainder of the first name. This seems to be buffer overflow to me, so is there a way of using scanf without getting this result?

%10s for first name reads only first 10 characters - UmbertoOve - from input string and puts into firstname. The remaining - rflow - are still in the input buffer of program and scanf() for surname takes those characters. '\n' - or Return - key pressed while entering first name works as terminator and adds rflow in surname.
Its not buffer overflow, but expected behavior.

It's not bufferoverflow. It's just that scanf takes space or newline as the delimiter. Hence, the first scanf scans for 10 chars and the next continues to scan till it finds a space or '\n'.
Use
scanf("%10s%*s", firstName);
scanf("%20s%*s", surName);
scanf("%15s%*s", job);

Related

SCANF probably not reading the correct value

If you enter more than five characters in the "name" field the function giving the wrong output, otherwise if the input is less than or equal to five characters the function works just fine, or if I use just %s instead of reading five characters using %5s then also the function works.
Is there any fix available (I want to use %5s)?
#include<stdio.h>
int main(void)
{
char name[6];
int age;
printf("Enter your name: ");
scanf("%5s",name);
printf("Enter your age: ");
scanf("%d",&age);
printf("Your name: %.4s\n",name);
printf("Your age: %d\n",age);
return 0;
}
It's good that you limit the input to five characters, as that will make it fit perfectly in the array you have (including the terminator). However, if the user inputs a longer string, the remaining will be left in the buffer and the input of the age will not work.
As a (relatively) simple way to improve input, use fgets instead to read a line but increase array size as it can include the newline itself. And that's kind of the point here: If the buffer contains the newline, then you know you have read the full string, can replace it with the string terminator, and then move on. However, if the buffer doesn't contain a newline, you need to "flush" the input buffer by reading all the remaining characters of the line and ignore them.

Fgets skipping input and printing next line?

I'm trying to read a string including spaces so scanf wouldn't work so I'm trying to use fgets. When I run it and it hits the if statement what prints on screen is:
Please enter the course name.
You entered the course:
Please enter the course ID.
=======================
if(coursetotal==0)/*start of 1 course*/
{
printf("Please enter the course name.\n");
fgets(course[0].name,sizeof(course[0].name),stdin);
printf("You entered the course name: %s\n",course[0].name);
printf("\nPlease enter the four digit course ID.\n");
int temp=0,temp1=0,count=0; /*Variables used to check if 4 digits*/
scanf("%d",&temp);
temp1=temp;
while(temp1!=0)
{
temp1/=10;
count++;
}
if(count==4)/*start of is 4 digits*/
{
course[0].id=temp;
coursetotal+=1;
printf("You entered the course ID: %d\n",course[0].id);
}/*end of is 4 digits*/
else
{
printf("The course ID you input was not 4 digits.\n");
return;
}
printf("You have successfully added the course: %s. The ID is : %d, and you now have a total of %d course.\n",course[0].name,course[0].id,coursetotal);
} /*end 1 course*/
First I have to address the pet peeve I see here:
I'm trying to read a string including spaces so scanf wouldn't work
That's not true at all. There's something called a negated scanset you can use it to read past the white space characters (such as space) that normally terminate scanf()s input for a string.
That said. You should really pick just one input mechanism scanf() or fgets() and use that exclusively. When you intermix, things get weird and missed. The fact that you've done it here tells me you've done it other places and you probably used scanf() prior to this leaving yourself an "unclean" stdin buffer. This will fix your issue.
Now just a quick example for you, given a int (num) and a char * (`string):
scanf("%d", &num);
fgets(string, sizeof(string), stdin);
printf("%d\n%s\n", num, string);
You'll seemingly skip the ability to enter anything for the fgets as it really just took int the newline character leftover from the scanf()'s number entry. You'll see on the output something like:
5
5
// <-- and a couple
// <-- of blank lines
Indicating that you picked up a newline character. Even more obvious if you were to look at the ASCII value of the string's first (and only) character:
printf("%d\n", string[0]); // this would yield 10 the ASCII value of \n

string input with spaces [duplicate]

This question already has answers here:
How do you allow spaces to be entered using scanf?
(11 answers)
Closed 6 years ago.
I'm trying to run the following code in the basic ubuntu gcc compiler for a basic C class.
#include<stdio.h>
struct emp
{
int emp_num, basic;
char name[20], department[20];
};
struct emp read()
{
struct emp dat;
printf("\n Enter Name : \n");
scanf("%s", dat.name);
printf("Enter Employee no.");
scanf("%d", &dat.emp_num);
//printf("Enter department:");
//fgets(dat->department,20,stdin);
printf("Enter basic :");
scanf("%d", &dat.basic);
return dat;
}
void print(struct emp dat)
{
printf("\n Name : %s", dat.name);
printf("\nEmployee no. : %d", dat.emp_num);
//printf("Department: %s", dat.department);
printf("\nBasic : %d\n", dat.basic);
}
int main()
{
struct emp list[10];
for (int i = 0; i < 3; i++)
{
printf("Enter Employee data\n %d :\n", i + 1);
list[i] = read();
}
printf("\n The data entered is as:\n");
for (int i = 0; i < 3; i++)
{
print(list[i]);
}
return 0;
}
I want the name to accept spaces.
The problem comes when I'm entering the values to the structures. I am able to enter the name the first time but the subsequent iterations don't even prompt me for an input.
I've tried using fgets, scanf("%[^\n]",dat.name) and even gets() (I was desperate) but am the facing the same problem every time.
The output for the 1st struct is fine but for the rest is either garbage, the person's last name or just blank.
Any ideas?
When reading a string using scanf("%s"), you're reading up to the first white space character. This way, your strings cannot include spaces. You can use fgetsinstead, which reads up to the first newline character.
Also, for flushing the input buffer, you may want to use e.g. scanf("%d\n") instead of just scanf("%d"). Otherwise, a subsequent fgets will take the newline character and not ask you for input.
I suggest that you experiment with a tiny program that reads first one integer number and then a string. You'll see what I mean and it will be much easier to debug. If you have trouble with that, I suggest that you post a new question.
The problem is that scanf("%[^\n",.. and fgets don't skip over any whitespace that may be left over from the previous line read. In particular, they won't skip the newline at the end of the last line, so if that newline is still in the input buffer (which it will be when the last line was read with scanf("%d",..), the scanf will fail without reading anything (leaving random garbage in the name array), while the fgets will just read the newline.
The easiest fix is to add an explicit space in the scanf to skip whitespace:
printf("\n Enter Name : \n");
scanf(" %19[^\n]", dat.name);
This will also skip over any whitespace at the beginning of the line (and blank lines), so may be a problem if you want to have a name that begins with a space.
Note I also added a length limit of 19 to avoid overflowing the name array -- if the user enters a longer name, the rest of it will be left on the input and be read as the employeee number. You might want to skip over the rest of the line:
scanf("%*[^\n]");
This will read any non-newline characters left on the input and throw them away. You can combine this with the prior scanf, giving you code that looks like:
printf("\n Enter Name : ");
scanf(" %19[^\n]%*[^\n]", dat.name);
printf("Enter Employee no. : ");
scanf("%d%*[^\n]", &dat.emp_num);
printf("Enter department : ");
scanf(" %19[^\n]%*[^\n]", dat.department);
printf("Enter basic : ");
scanf("%d%*[^\n]", &dat.basic);
This will ignore any spurious extra stuff that someone enters on a line, but will still have problems with someone entering letters where numbers are expected, or end-of-file conditions. To deal with those, you need to be checking the return value of scanf.
What you have tried was:-
scanf("%[^\n]",dat.name)
In this you forgot to specify the specifier.
You can try to use this:-
scanf ("%[^\n]%*c", dat.name);
or fgets() if you want to read with spaces.
Note:- "%s" will read the input until whitespace is reached.

Stack around variable corrupted? C

I have 2 issues, but this is the more pressing one...
printf("Enter the term: "); scanf("%d", &input);
fprintf(inputf, "%d,", input);
printf("Enter the id: "); scanf("%d", &input);
fprintf(inputf, "%d,", input);
printf("Enter last name: "); scanf("%s", name);
fprintf(inputf, "%s,", name);
printf("Enter first name: "); fgets(name, 15, stdin);
fprintf(inputf, "%s,", name);
printf("Enter the subject: "); scanf("%s", subsec);
fprintf(inputf, "%s,", subsec);
printf("Enter the catalog number: "); scanf("%d", &input);
fprintf(inputf, "%d,", input);
//ISSUE HERE!
printf("Enter the section: "); scanf("%s", subsec);
fprintf(inputf, "%s\n", subsec);
Whenever I input all of this information and press enter on the last variable entry I get a window that says this "Run-Time Check Failure #2 - Stack around the variable 'subsec' was corrupted." I can continue and the program pretty much does what I want it to and works, but why is this happening?
My second part is when I get to entering the last name, and then want to enter the first name, it takes in the "\n" character when I press enter for the firstname string variable, obviously dont want that happening, but the both first and last name need to be capable of holding strings with whitespaces. How do I kill both birds with a single stone? I used fget to allow me to hold whitespace, but it cases my "\n" capture issue, but if I change it back to scanf, I cant hold whitespaces!
EDIT: This is subsec
char subsec[MAX_SUBSEC];
MAX_SUBSEC is set to three, I use it previously as you can see, but I figured the second scanf (the one for section, not subject) would write over the original use of inputting subsec, Im going to say I am wrong? And I am not allowed to do this, thus the issue...
Input for subject will be "CSE" and the input for section will be "R01" And yes this is all going to be put into a file.
If MAX_SUBSEC is 3 and you enter more than 2 characters for the subject or subsection, you'll overrun the subsec array on the stack and corrupt the stack frame (which may or may not cause problems. You should use
scanf("%2s", subsec); /* read up to two non-whitespace characters for subsec */
to ensure it doesn't try to read and store more than 2 characters (plus the trailing NUL) into subsec
You might also want to add a
scanf("%*[^\n]"); /* discard the rest of the input line */
after each scanf you have currently to discard the rest of the input line (in case some enters more than the single data item you want. You can combine the two with
scanf("%2s%*[^\n]", subsec); /* read 2 chars and discard the rest of the line */
if you want.
To enter strings of at most 15 chars (including NUL) with whitespace for first/last name, use:
scanf(" %14[^\n]", name); /* read up to 14 chars from the line */
That will discard any leading whitespace (including the newline from the previous line) and then read into name, but won't discard trailing spaces from the name if someone enters them (you might want to clean them up).
Check if inputf, that I presume that is a pointer to an opened file, do a correctly reading of the variable. In other words, check if the file is open correctly and this file contain all data that you want to read.

gets() only taking input once in while loop

I am new to C and working through some exercises, but having trouble with gets() in a while loop. In searching, I believe that it may have something to do with the \n character, but I was hoping that someone would be able to give me a more thorough explanation of what is going on here:
This loop will only run once - it will print the 'Enter last name' to screen a second time and then drop out of the loop before gets() has a chance to take any input a second time:
while (employee_num <= 10)
{
printf("Enter last name ");
gets(employee[employee_num].last_name);
if(strlen(employee[employee_num].last_name) == 0)
break;
printf("Enter first name ");
gets(employee[employee_num].first_name);
printf("Enter title ");
gets(employee[employee_num].title);
printf("Enter salary ");
scanf("%d", &employee[employee_num].salary);
++employee_num;
}
Thanks in advance!
You'd have a newline character (\n) in the input buffer after reading the salary. That is being picked up as the last name in the second iteration. You can ignore that by adding a getchar() after your last scanf:
while (employee_num <= 10) {
...
printf("Enter salary ");
scanf("%d", &employee[employee_num].salary);
++employee_num;
getchar();
}
Referring to answer by skjaidev,
With gets(), The newline character(\n), if found, is not copied into string and this is the reason for your problem.
Also,
Notice that gets is quite different from fgets: not only gets uses stdin as source, but it does not include the ending newline character in the resulting string and does not allow to specify a maximum size for str (which can lead to buffer overflows).
It is considered to be a bad practise to use gets() in a program

Resources