Writing 5 character to char[5] affects int - c

Easy code down below.
Mac OS X 10.10.5, Xcode 7.2, C-file.
If I input 1, and afterwards qwert, I get 0 and qwert back.
1 and qwer gives 1 and qwer.
1 and e.g. qwerty gives 121 and qwerty.
What have I missed - why can I write more than 4 chars (+null) to a 5 char variable?
Why is the integer affected?
#include <stdio.h>
int main() {
int userInput;
char q[5];
printf("Hello\n");
scanf("%d", &userInput);
printf("%d\nAnd\n", userInput);
scanf("%s", q);
printf("\n");
printf("%d\n%s", userInput, q);
return 0;
}

What have I missed - why can I write more than 4 chars (+null) to a 5 char variable?
There is nothing stopping you from accessing out of bounds portions of an array in c. This will compile:
char a[2];
a[10000] = 10;
Why is the integer affected?
What you are causing is undefined behavior and is likely the reason that your int is affected. You can learn more about this by reading about c arrays. This is happening because you are putting a 5 character string plus a null terminating character ( ie 6 chars) into a space only meant for 5. You are going outside the bounds of your array.
As a further note, scanf("%s" offers no method of protecting against this behavior. If a user puts in a string that is too long then too bad. That is why you should protect your input by using something like a format string of "%4s" or use fgets:
fgets(q, sizeof q, stdin);
Which are both ways you can protect your input from entering more than 4 characters.

[Edit] User/code can try to "write more than 4 chars (+null) to a 5 char variable". C does not specify what should happen when code does not prevent such an event. C is coding without the safety net/training wheels.
scanf("%s", q); reads and saves the 5 characters of "qwert" and it also appends a null character '\0'. #Weather Vane
Since q[] has only room to 5 characters, undefined behavior occurs (UB). In OP's case, it appear to have over-written userInput.
To avoid, use a width limit on "%s" such as below. It will not consume more than 4 non-white-space from the user. Unfortunately, extra text will remain in stdin.
char q[5];
scanf("%4s", q);
Or better, review fgets() for reading user input.

The reason that the int userInput is affected is that you are writing past the end of the char array (q). Since both of these are stack variables, the compiler you're using seems to be allocating memory on the stack for the local variables in "reverse order", it, they are being "pushed" in the order defined, so the first local variable listed is lower on the stack. So, in your case, when you write past the end of q, you are writing in the memory space allocated for userInput, which is why it is affected.

Related

Character Array and Null character

#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
char str[4];
scanf("%s",str);
printf("%s",str);
}
input scan
output scan
Here I declare an array of 4 characters. I used '%s' that is used for strings. I am not able to understand how can we input 4 char elements and get correct answer when one space should be utilized for the NULL character. The input should only work with up to 3 elements.
scanf() does not check its arguments. You could even enter more than 4 characters and scanf() would happily overwrite the memory area that comes after your array. After that, your program might crash or all kinds of funny things might happen. This is called a buffer overflow and it is a common cause of vulnerabilities in software.
as mentioned when you take more than 3 character as input ,and extra chars and \0 will be written outside of array memory(after it) and over write memory which doesn't belong to array.which will cause undefined behavior.
but you can use these to prevent buffer overflow from happening:
scanf("%3s",str);
or
fgets(str, sizeof str, stdin)

Array Declaration causing weird behavior with while loop

I have recently encountered very weird behaviour with my c program. I gutted out most of the code just to isolate where the issue is happening for you guys.
The purpose of the program in its current state is to read in jobs from a txt file and print the contents to the screen. Here it is:
#include <stdio.h>
int main(){
char* user;
char process;
int arrival;
int duration;
scanf("%*[^\n]"); //skipping header in the file.
while(!feof(stdin))
{
scanf("%s\t%c\t%d\t%d\n", user, &process, &arrival, &duration);
printf("%s\t%c\t%d\t%d\n", user, process, arrival, duration);
}
int x[5]; //<----- Causing the weird behaviour
}
The file I pipe into it is:
User Process Arrival Duration
Jim A 2 5
Mary B 2 3
Sue D 5 5
Mary C 6 2
The issue that I'm running into is whenever I declare the int x array, whether it is at the bottom or top of my code, the while loop enters an infinite loop or the program seg faults.
It will go into an infinite loop or seg fault depending on the size I declare the array at. For example, if I declare the array to be size 5, it enters an infinite loop. However, if I declare the array to be size 2, it will seg fault.
I am compiling my program by running:
gcc -o myprog myprog.c
and I am piping the file by running:
cat jobs.txt | ./myprog
It is also worth noting that the program runs fine without the int x array declaration.
I am completely stumped as to what might be the issue, any thought?
You have an undefined behavior because of the pointer user which is not initialized. user must point to a memory area capable of storing what you want (see malloc() for example).
As you have found from the other answer, your initial problem is with char *user; which declares a character pointer that is uninitialized (e.g. it does not point to any valid block of memory). While you can dynamically allocate with malloc, calloc, or realloc, that may be an over-complication for your circumstance.
All you really need is to declare a character array sufficient to hold the user names. 16 chars is more than sufficient here.
Next while (!feof(fp)) is almost always wrong. (see link in my comment). scanf provides a return of the number of valid conversions that take place. In your case, with "%s..%c..%d..%d" (4-conversion specifiers), a return of 4 will indicate that no matching or input failure occurred. So instead of your feof check, just use the scanf return, e.g.
scanf("%*[^\n]"); //skipping header in the file.
while (scanf ("%15s %15s %d %d", user, process, &arrival, &duration) == 4)
printf ("%s\t%c\t%d\t%d\n", user, *process, arrival, duration);
(note: for the simplified scanf format string "%15s %15s %d %d", arrival is declared as a character array (see below) and read as a string (to take advantage of leading white-space skipping) and then *arrival is used to pick off the character. This provides a bit more robust way to read your input in the event your input is space separated instead of *tab separated)
To avoid using magic numbers in your code (e.g. 16), declare a constant if you need one for the max characters in your arrays, e.g.
#define MAXC 16
int main (void) {
char user[MAXC] = "", process[MAXC] = "";
note: it may look like "%15s %15s %d %d" breaks this rule, but sadly, there is no way to include a constant of variable in the scanf field width specifier that protects against reading more than 15 chars into your arrays -- remember, you must leave room for the final character -- the nul-terminating character.
Putting it altogether, you could do something like the following:
#include <stdio.h>
#define MAXC 16
int main (void) {
char user[MAXC] = "", process[MAXC] = "";
int arrival, duration;
scanf("%*[^\n]"); //skipping header in the file.
while (scanf ("%15s %15s %d %d", user, process, &arrival, &duration) == 4)
printf ("%s\t%c\t%d\t%d\n", user, *process, arrival, duration);
return 0;
}
Example Use/Output
$ ./bin/scanf_usr_arriv <dat/userprocarriv.txt
Jim A 2 5
Mary B 2 3
Sue D 5 5
Mary C 6 2
You may also want to consider reading all "lines of input" with a line-oriented input function like fgets and then calling sscanf on the resulting buffer to parse each of the variables. This has the benefit of allowing separate validation on the line being read, and then an independent validation on the parse of each variable from the line.
Look things over and let me know if you have any questions.

inputting a character string using scanf()

I started learning about inputting character strings in C. In the following source code I get a character array of length 5.
#include<stdio.h>
int main(void)
{
char s1[5];
printf("enter text:\n");
scanf("%s",s1);
printf("\n%s\n",s1);
return 0;
}
when the input is:
1234567891234567, and I've checked it's working fine up to 16 elements(which I don't understand because it is more than 5 elements).
12345678912345678, it's giving me an error segmentation fault: 11 (I gave 17 elements in this case)
123456789123456789, the error is Illegal instruction: 4 (I gave 18 elements in this case)
I don't understand why there are different errors. Is this the behavior of scanf() or character arrays in C?. The book that I am reading didn't have a clear explanation about these things. FYI I don't know anything about pointers. Any further explanation about this would be really helpful.
Is this the behavior of scanf() or character arrays in C?
TL;DR - No, you're facing the side-effects of undefined behavior.
To elaborate, in your case, against a code like
scanf("%s",s1);
where you have defined
char s1[5];
inputting anything more than 4 char will cause your program to venture into invalid memory area (past the allocated memory) which in turn invokes undefined behavior.
Once you hit UB, the behavior of the program cannot be predicted or justified in any way. It can do absolutely anything possible (or even impossible).
There is nothing inherent in the scanf() which stops you from reading overly long input and overrun the buffer, you should keep control on the input string scanning by using the field width, like
scanf("%4s",s1); //1 saved for terminating null
The scanf function when reading strings read up to the next white-space (e.g. newline, space, tab etc.), or the "end of file". It has no idea about the size of the buffer you provide it.
If the string you read is longer than the buffer provided, then it will write out of bounds, and you will have undefined behavior.
The simplest way to stop this is to provide a field length to the scanf format, as in
char s1[5];
scanf("%4s",s1);
Note that I use 4 as field length, as there needs to be space for the string terminator as well.
You can also use the "secure" scanf_s for which you need to provide the buffer size as an argument:
char s1[5];
scanf_s("%s", s1, sizeof(s1));

scanf string in c - why can i scan more than the char[] declaration?

I have a program where I need to scanf a string, which I know it will be only 2 characters long. (for example: "ex").
what is the proper way to do that?
I was going for:
char myStr[3];
scanf("%s", myStr);
It works just fine, but when I enter a 10-letter word it also works just fine. How come? Does the [3] has no meaning? How should I do this the proper way?
Thanks.
The proper way to limit the input using scanf() is
if (scanf("%2s", myStr) != 1) /* error */;
But consider using fgets() rather than scanf()
if (fgets(myStr, sizeof myStr, stdin) == NULL) /* error */;
It works just fine, but when I enter a 10-letter word it also works
just fine.
It only appears to work fine but it's actually undefined behaviour. That is because scanf stores the characters it reads from stdin into the buffer pointed to by myStr. The size of myStr is 3. Therefore, there's space for only 2 characters. One character space is saved for the terminating null byte to mark the end of the string which is added by scanf automatically. When the input string is longer than 2 characters, scanf overruns the buffer accessing memory out of the bound of the array. It is illegal to access memory out of the array bound and invokes undefined behaviour.
The next time, it may very well crash. It's unpredictable and you should always avoid it.
To guard against it, you should specify maximum field width for the conversion specifier %s in the format string of scanf. It should be one less than the array size to accommodate the terminating null byte.
char myStr[3];
scanf("%2s", myStr);
Better still, I suggest you to use fgets.
char myStr[3];
// read and store at most one less than
// sizeof(myStr) chars
fgets(myStr, sizeof myStr, stdin);
but when I enter a 10-letter word it also works just fine. How come? Does the [3] has no meaning?
I doesn't work fine. See in this example:
#include <stdio.h>
int
main(int argc, char **argv)
{
char second[5] = "BBBB";
char myStr[3] = {0};
scanf("%s", myStr);
printf("second = %s\n", second);
printf("myStr = %s\n", myStr);
return 0;
}
writing only two characters in myStr is fine:
a.exe
AA
second = BBBB
myStr = AA
writing more data overrides the near by memory of second:
a.exe
AAAAAAA
second = AAAA
myStr = AAAAAAA
You need to limit the number of characters scanf reads using something like
scanf("%2s", myStr);, 2 is the size of myStr - 1.
You canĀ“t do that.
scanf will do nothing to prevent it, but it can (or, in larger programs, will)
lead to problems later on. Like unexpectly changed variable values, program crashes...
Use fgets

String decleration length in C

So I'm writing a small program (I'm new to C, coming from C++), and I want to take in a string of maximum length ten.
I declare a character array as
#define SYMBOL_MAX_LEN 10 //Maximum length a symbol can be from the user (NOT including null character)
.
.
.
char symbol[SYMBOL_MAX_LEN + 1]; //Holds the symbol given by the user (+1 for null character)
So why is it when I use:
scanf("%s", symbol); //Take in a symbol given by the user as a string
I am able to type '01234567890', and the program will still store the entire value?
My questions are:
Does scanf not prevent values from being recorded in the adjacent
blocks of memory after symbol?
How could I prevent the user from entering a value of greater than length SYMBOL_MAX_LEN?
Does scanf put the null terminating character into symbol automatically, or is that something I will need to do manually?
You can limit the number of characters scanf() will read as so:
#include <stdio.h>
int main(void) {
char buffer[4];
scanf("%3s", buffer);
printf("%s\n", buffer);
return 0;
}
Sample output:
paul#local:~/src/c/scratch$ ./scanftest
abc
abc
paul#local:~/src/c/scratch$ ./scanftest
abcdefghijlkmnop
abc
paul#local:~/src/c/scratch$
scanf() will add the terminating '\0' for you.
If you don't want to hardcode the length in your format string, you can just construct it dynamically, e.g.:
#include <stdio.h>
#define SYMBOL_MAX_LEN 4
int main(void) {
char buffer[SYMBOL_MAX_LEN];
char fstring[100];
sprintf(fstring, "%%%ds", SYMBOL_MAX_LEN - 1);
scanf(fstring, buffer);
printf("%s\n", buffer);
return 0;
}
For the avoidance of doubt, scanf() is generally a terrible function for dealing with input. fgets() is much better for this type of thing.
Does scanf not prevent values from being recorded in the adjacent blocks of memory after symbol?
As far as I know, No.
How could I prevent the user from entering a value of greater than length SYMBOL_MAX_LEN?
By using buffer safe functions like fgets.
Does scanf put the null terminating character into symbol automatically, or is that something I will need to do manually?
Only if the size was enough for it to put the nul terminator. For example if your array was of length 10 and you input 10 chars how will it put the nul terminator.
I am able to type '01234567890', and the program will still store the entire value?
This is because you are Unlucky that you are getting your desired result. This will invoke undefined behavior.
Does scanf not prevent values from being recorded in the adjacent blocks of memory after symbol?
No.
How could I prevent the user from entering a value of greater than length SYMBOL_MAX_LEN?
Use fgets.
Does scanf put the null terminating character into symbol automatically, or is that something I will need to do manually?
Yes

Resources