memory allocation error with scanf - c

I have this simple code, and can't figure out how to allocate memory for scanf
char* string= (char*) malloc (sizeof(char));
printf("insert string: \n");
scanf("%s", string);
free(string);
doesn't matter how many chars my string is, it's an error. I want to use malloc for the char*, any way to set memory for scanf.

You are just request 1 byte. You need to allocate more than that if you want store more than just the 0 terminator in the string:
char* string= malloc (256); //256 bytes, arbitrary value...
I removed:
sizeof(char) because it's always guaranteed to be 1.
(char*) because casting the return value of malloc() is needless.
I would also recommend using fgets() instead of scanf() to prevent overflowing the buffer. The same could be done with scanf() by specifying the length in the format string. But I personally prefer using fgets() and parsing using sscanf() if necessary.

Try
char buf[256];
scanf( "%s" , buf);
Delete your malloc.
You're allocating a tiny piece of memory to what could be a variable sized array of string. By default an array is just a pointer to buf[0] which is what string will give it. You'll need a buffer to capture the initial read and then allocate the proper memory afterwards.
Afterwards you can do string = length(buf) * sizeof(char) <- pseudocode
to assign the correct length of the string.

As #Blue Moon correctly pointed out, you are just allocating memory to store one character, and the only string a single character can store is an empty string or a string without characters. In C, all strings are null terminated, and the 1 byte of memory you have allocated can accommodate only a null character, i.e. '\0'
In order to store more characters in your string, say a hundred characters, you can do the following:
#define MAX_STRING_SIZE 102
char* string= (char*) malloc (sizeof(char) * MAX_STRING_SIZE);
memset(string, '\0', MAX_STRING_SIZE);
printf("Insert string: \n");
scanf("%101s", string);
if (strlen(string) == (MAX_STRING_SIZE - 1))
{
printf("The user entered a string larger than 100 characters!");
free(string);
/****Error handling***/
}
/*****Do something with string****/
free(string)
The above snippet is a nice little trick to find out if the user entered a valid number of characters or not. If you wanted the user to enter a maximum of 100 character and your program is always running in an ideal scenario(where the user listens to you all the time and never enters more than 100 characters) you just need one extra byte to store the null character. Hence, you need space for 101 characters. But you can add space for another character, and allocate 102 bytes instead to find out the cases when the user enters a string longer than 100 characters.
How this works: Say the user enters 100+ characters. The scanf function can read a maximum of 101 characters. So, we can use the strlen function to check if the number of characters input by the user are equal to 101 or not, which will help us to validate the input string.

Related

Why does scanf accept more characters than there is room for in the buffer?

See the following code:
int main()
{
char test[3];
scanf("%s", test);
__fpurge(stdin);
printf("%s", test);
}
The program should record only 3 characters, but when I type, for example, 8 characters, the program records all 8! This should not happen. The correct would record 3 characters, because the scanf do it?
scanf accepts more data than you can fit in test because you allow it to do so by using %s without a limit. This is dangerous, and must be avoided in production code.
Replace %s with %3s to fix this problem. If you want to read three characters, test must be four-characters wide to accommodate null terminator:
char test[4];
scanf("%3s", test);
When you pass test to scanf(), you are passing nothing but a pointer to the first character of your buffer, so scanf() has no idea how large your buffer is. It will happily accept as many characters as you type, and it will store them all in there. So, when you type more than 2 characters, you are causing scanf() to write characters (plus the zero asciiz terminator character) past the end of your buffer. Normally, what is to be expected in such a case is a program crash.
The fact that you did not experience a crash is largely coincidence, what is probably happening is that the compiler has allocated room for more than 3 characters in the stack due to alignment considerations, possibly room for 8 characters or more. If you type enough characters, your program will surely crash.
For this reason, this usage of scanf() is considered completely unsafe. One should never use scanf() like that when doing any serious coding. Instead you should specify the width of your string, like this: "%2s". (Note that you must specify a number which is smaller than the size of your buffer by one, in order to account for the zero asciiz terminator character that will be automatically appended by scanf().)

Bus error caused while reading in a string

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *input = (char *)malloc(sizeof(char));
input = "\0";
while (1){
scanf("%s\n", input);
if (strcmp(input, "0 0 0") == 0) break;
printf("%s\n",input);
}
}
I'm trying to read in a string of integers until "0 0 0" is entered in.
The program spits out bus error as soon as it executes the scanf line, and I have no clue how to fix it.
Below is the error log.
[1] 59443 bus error
You set input to point to the first element of a string literal (while leaking the recently allocated buffer):
input = "\0"; // now the malloc'd buffer is lost
Then you try to modify said literal:
scanf("%s\n", input);
That is undefined behaviour. You can't write to that location. You can fix that problem by removing the first line, input = "\0";.
Next, note that you're only allocating space for one character:
char *input = (char *)malloc(sizeof(char));
Once you fix the memory leak and the undefined behaviour, you can think about allocating more space. How much space you need is for you to say, but you need enough to contain the longest string you want to read in plus an extra character for the null terminator. For example,
char *input = malloc(257);
would allow you to read in strings up to 256 characters long.
The immediate problem, (thanks to another answer) is that you're initializing input wrong, by pointing it at read-only data, then later trying to write to it via scanf. (Yes, even the lowly literal "" is a pointer to a memory area where the empty string is stored.)
The next problem is semantic: there's no point in trying to initialize it when scanf() will soon overwrite whatever you put there. But if you wanted to, a valid way is input[0] = '\0', which would be appropriate for, say, a loop using strcat().
And finally, waiting in the wings to bite you is a deeper issue: You need to understand malloc() and sizeof() better. You're only allocating enough space for one character, then overrunning the 1-char buffer with a string of arbitrary length (up to the maximum that your terminal will allow on a line.)
A rough cut would be to allocate far more, say 256 chars, than you'll ever need, but scanf is an awful function for this reason -- makes buffer overruns painfully easy especially for novices. I'll leave it to others to suggest alternatives.
Interestingly, the type of crash can indicate something about what you did wrong. A Bus error often relates to modifying read-only memory (which is still a mapped page), such as you're trying to do, but a Segmentation Violation often indicates overrunning a buffer of a writable memory range, by hitting an unmapped page.
input = "\0";
is wrong.
'input' is pointer, not memory.
"\0" is string, not char.
You assigning pointer to a new value which points to a segment of memory which holds constants because "\0" is constant string literal.
Now when you are trying to modify this constant memory, you are getting bus error which is expected.
In your case i assume you wanted to initialize 'input' with empty string.
Use
input[0]='\0';
note single quotes around 0.
Next problem is malloc:
char *input = (char *)malloc(sizeof(char));
you are allocating memory for 1 character only.
When user will enter "0 0 0" which is 5 characters + zero you will get buffer overflow and will probably corrupt some innocent variable.
Allocate enough memory upfront to store all user input. Usual values are 256, 8192 bytes it doesn't matter.
Then,
scanf("%s\n", input);
may still overrun the buffer if user enters alot of text. Use fgets(buf, limit(like 8192), stdin), that would be safer.

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

Reading a char array using %s i.e string specifier

char *ptr=(char*)calloc(n,sizeof(int));
using the above, we can allocate memory for char array. But is reading it character-by-character mandatory? How to read and access it using%s` i.e the string format specifier?
Reading character by character is not mandatory and using exactly %s is susceptible to buffer overruns. Specifying the maximum number of characters to read, one less than the number of bytes in the buffer being populated, prevents the buffer overrun. For example "%10s" reads a maximum of ten characters then assigns the null terminating character so the target buffer requires at least 11 bytes.
However, as the code suggests that n is unknown at compile time using %s with a dynamic width is not possible explicitly. But it would be possible to construct the format specifier (the format specifier is not required to be a string literal):
char fmt[32];
sprintf(fmt, "%%%ds", n - 1); /* If 'n == 10' then 'fmt == %9s' */
if (1 == scanf(fmt, ptr))
{
printf("[%s]\n", ptr);
}
An alternative would be fgets():
if (fgets(ptr, n, stdin))
{
}
but the behaviour is slightly different:
fgets() does use whitespace to terminate input.
fgets() will store the newline character if it encounters it.
Casting the return value of calloc() (or malloc() or realloc()) is unrequired (see Do I cast the result of malloc?) and the posted is confusing as it is allocating space for int[n] but is intended to be character array. Instead:
char* ptr = calloc(n, 1); /* 1 == sizeof(char) */
Also, if a null terminated string is being read into ptr the initialisation provided by calloc() is superfluous so a malloc() only would suffice:
char* ptr = malloc(n, 1);
And remember to free() whatever you malloc()d, calloc()d or realloc()d.
Yes, you can read such array using %s but make sure you have allocated enough memory for what you try to read(don't forget the terminating zero character!).

Resources