Difference between gets() and scanf("%s") [closed] - c

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I declared a character pointer, and used it for to scan a string in runtime; I don't know the number of characters that I'm going to enter, so I didn't use calloc or malloc. The program ends when it reached the line scanf("%s", NewMsg_au8).
I'm using CodeBlocks 17.12 editor.
I tried hard coding one of the input case like, NewMsg_au8="0123456789ABCDEF"; — that works fine.
uint8 * NewMsg_au8;
scanf("%s",NewMsg_au8);//<==
printf("Your entered message is: %s\n",NewMsg_au8);
return NewMsg_au8;

gets(s) and scanf("%s", s) are both unsafe and potentially incorrect because:
with those calls as shown, there is no way for either function to determine the maximum number of characters to store into the array pointed to by s, hence overlong input will cause a buffer overrun leading to undefined behavior.
in your case, it is even worse as s is an uninitialized pointer, so both functions would try a store data into a random address in memory causing undefined behavior in all cases.
gets() cannot be used safely and has been deprecated in and then removed from the C Standard.
However, scanf() can be given a limit with a numeric value between % and s:
#include <stdio.h>
#include <string.h>
char *read_string(void) {
char buf[100];
if (scanf("%99s", buf) == 1) {
printf("Your entered message is: %s\n", buf);
return strdup(buf); /* return an allocated copy of the input string */
} else {
/* no input, probably at end of file */
return NULL;
}
}
Note how only 99 characters can be stored into the array buf to allow for the null byte terminator that marks the end of a C string. The %99s conversion specification lets scanf() store at most 100 bytes into buf, including the '\0' terminator.

That is a typical beginners error. You do not save data in pointers (with gets() or scanf()) but in buffers.
Therefore, you have 2 solutions:
Use an array big enough to hold the data. You have to decide yourself what "big enough" means, according to the details of your application.
Use a pointer, and then allocate memory with malloc() - the size, again, you have to decide it. Do not forget to deallocate the memory when you no longer need it.
I tried hard coding one of the input case like, NewMsg_au8="0123456789ABCDEF"; — that works fine.
That is normal, because in that case the compiler automatically allocates enough memory to hold the string.
Please always remember when working with strings: you always need to allocate an extra byte for the terminating null character - the mark of the end of the string. Otherwise, you will need to ask questions again :)

Related

strlen doesn't return the correct value with pointer to an array [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have the following code:
char* realtor_command[120];
for(int i=0;i<REALTOR_MAX_COMMAND_LENGTH;i++){
realtor_command[i]=malloc(sizeof(120));
}
realtor_command[0]="test_string"
realtor_command[1]="next_test_string"
When I use strlen(realtor_command[0]) I get wrong value, I read in previous questions this happens because its an array and not pointer, yet I haven't found any fix for this problem.
My question is if there is anyway to get the length of realtor_command[i]?
Thank you very much.
EDIT :
This is how I invoke strlen :
char* matrix=malloc(strlen(realtor_command[8])+1);
In this code:
char* realtor_command[120];
for(int i=0;i<REALTOR_MAX_COMMAND_LENGTH;i++){
realtor_command[i]=malloc(sizeof(120));
}
You create an array of 120 strings, then loop through REALTOR_MAX_COMMAND strings (presumably this should be 120?) and set them to newly allocated 4- or 8-byte strings (sizeof(120) means sizeof(int) which is either 4 or 8 bytes). Since those strings are newly allocated, they will contain arbitrary data, and may not end with a null-terminator.
This is important because strlen() just loops over the string until it finds a null terminator, so it can't work with non-null-terminated strings.
You could add a null terminator yourself, but then the strings would contain arbitrary garbage up to the end of the string, and they may have null terminators inside them. You could make them start with a null-terminator, but then strlen() would always return 0.
What might be better is to allocate these strings when you actually fill them, and leave them as null pointers until then:
char* realtor_command[120];
for (int i = 0; i < 120; i++) {
realtor_command[i] = NULL;
}
char input_buffer[REALTOR_MAX_COMMAND];
// Read in one string, then copy it so we can re-use the buffer
fgets(input_buffer, REALTOR_MAX_COMMAND, stdin);
realtor_command[0] = strdup(input_buffer);
This will also avoid the memory leak in your code.
Note that you'll probably want to make sure the string read by fgets contains a newline, to make sure the input fit in your buffer:
if (strstr(input_buffer, "\n") == NULL) {
// error, input didn't fit in our buffer!
}

Why does C hold a large string in a tiny char array? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Disclaimer: Been doing Java for a while, but new to C.
I have a program that I wrote, and I'm purposely trying to see what happens with different inputs and outputs.
#include <stdio.h>
int main() {
printf("whattup\n");
char str1[1], str2[1];
printf("Enter something: ");
scanf("%s", &str1);
printf("Enter something else: ");
scanf("%s", &str2);
printf("first thing: %s\n", str1);
printf("second thing: %s", str2);
}
This is the program flow:
whattup
Enter something: ahugestatement
Enter something else: smallertext
first thing: mallertext
Things I don't understand:
Why does "first thing" print out the str2?
Why does str2 have it's first letter cut off?
Why does "second thing:" not print out?
I made the char array with a size of 1, shouldn't it only hold 1 letter?
To answer your questions specifically, you'll have to keep in mind that what happens is very much implementation-specific. The specific behavior you're seeing doesn't have to hold true on all C implementations. This is what the C standard calls "undefined behavior". With that in mind:
Why does "first thing" print out the str2?
Why does str2 have it's first letter cut off?
You have allocated storage for two chars on the stack. The compiler allocates them next to each other, with str2 preceding str1 in memory. Therefore, after your first scanf, part of the stack will look like this:
str1 is allocated here
v
? a h u g e s t a t e m e n t \0
^
str2 is allocated here
Then, after the second scanf, the same part of memory will look like this:
str1 is allocated here
v
s m a l l e r t e x t \0 e n t \0
^
str2 is allocated here
In other words, the second input simply overwrites the first, since it goes beyond the bounds of the storage you allocated for it. Then, when you print out str1, it simply prints whatever is at the address of str1, which, as you can see in the figure above, is mallertext.
Why does "second thing:" not print out?
This is because of two effects interacting. For one thing, where you print str2, you do not end the output with a newline. stdout is normally line-buffered, which means that data written to it is not actually written to the underlying terminal until either A) a newline is written, B) you explicitly call fflush(stdout), or C) the program exits.
It would, therefore, print it when the program exited, but your program never exits. Since you overwrite parts of the stack that you don't manage, in this case you overwrite the return address from main, and therefore, when you return from main, your program promptly crashes, and thus never arrives to the point where it would flush stdout.
In the case of your program, the stack-frame layout of main looks like this (assuming AMD64 Linux):
RBP+8: Return address
RPB+0: Previous frame address
RBP-1: str1
RBP-2: str2
Since ahugestatement including its NUL terminator is 15 bytes, the 14 of those bytes that don't fit in str1 overwrite the entire previous frame address and 6 bytes of the return address. Since the new return address is entirely invalid, your program segfaults when the return from main jumps to an address that isn't even mapped in memory.
I made the char array with a size of 1, shouldn't it only hold 1 letter?
Yes, and it does. It's just that you clobber the memory that follows it.
As a general statement, scanf is not really a terribly useful function if you want to do even any most basic form of checking for illegal input. If you're hoping to do interactive input at all, it is almost always better to use something like fgets() instead and then parse the read input. fgets(), unlike scanf, takes an additional input for the size of the receiving buffer, and will then make sure to not write outside it.
You have to do the bounds checking in C, to make sure your buffers don't overflow. So your output is undefined. If you run that code many times, its bound to crash at some point because the overflown buffers will end up overwriting something important.
That's called buffer overflow. You allocated one character to hold your input, but you are writing beyond that (messing up the rest of your program's memory).
Unlike Java, the C compiler and runtime do not enforce array bounds. That is one of the main differences between "(memory-) managed languages" and low-level languages.
Your array only holds one character and the rest is out of bounds.
Access out of the range of an array is undefined and usually disastrous.

Inputting an arithmatic statement in c and return the value [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
(I am very bad at inputting/processing strings in C. Hope this question will teach me a lot.)
I am trying to make a function that will input an arithmatic string from stdin, e.g 23 + 45 * 6 - 5, and return the value.
There are multiple strings, entered one after another, and can be of any length and the operator precedence doesn't matter, i.e., it processes string sequentially.
The problems that I faced are :-
\n from previous string is also considered a string.So if I input 3 strings , it will actually be 6, 3 strings and 3 \n.
I used a char pointer and used char * input; scanf(" %s",input);, but in addition to above problem, I also get segmentation fault, which I guess is due to missing \0.
My question is forget what mess I did, what would you have done or what's the best way to handle string input in the above scenario. A dummy code is sufficient.Thanks.
What I was doing
#include <stdio.h>
int main()
{
int t; //no of test cases
char input;
scanf("%d",&t);
while(t--)
{
while((input=getchar())!='\n')
{
//use switch to identify char and follow appropriate action
printf("%c\n",input );
}
}
return 0;
}
As suggested by Joachim Pileborg, use fgets. Use a char array, instead of one char variable, to store the string.
char input[100];
fgets(input, sizeof(input), stdin);
The advantage of fgets over sscanf is that fgets can read spaces in your input.
It will include the end-of-line byte \n, so 3 strings will not turn into 6 strings.
As usual with fgets, there is an arbitrary limit on the length of the input. If the user inputs something longer than 98 bytes, the system cannot fit it all (plus end-of-line \n and end-of-string \0 bytes), and the program will receive truncated string.
If you cannot tolerate that, use getline (it's harder to use, so use fgets if in doubt).
After you scan your string in, check to see if it is a '\n', if it is just ignore processing it and move to the next one.
Or you could try:
char input[101];
scanf("%s\n", &input);
First of all. Your idea of writing an fomular expression analyzer as a first projekt is not a very good one. Start with a simpler project.
You get the sagmentation fault, because you try to read data (with the scanf()) into a not initialized pointer.
char *input;
will not allocate any memory for the string you want to read with scanf(). You have to use a buffer something like
char input[256];
and give the pointer to the buffer to scanf("%s",input) (oder for better understanding scanf("%s",&input[0]);
Anywhere, this buffer has only 255 chars to store and you must be aware, that if you enter more then 255 chars in the scanf() you will get an illegal memory access as well.
Claus

Can this code contain buffer overflows? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
These days I have read about buffer overflow attacks, and actually I can't say that I have understand the big picture, I have some doubts in my mind.
So to kill my doubts the question arises, if my program is written in C and all of code used to get input or to copy/merge buffers, checks for bounds, can buffer overflow occur? Or saying directly, is input (wherever that comes) the only method that an attacker can use to cause buffer overflow?
For example, consider the following code:
int main(){
int size = 15;
char buf[size];
fgets(buf, size , stdin);
printf("%s",buf);}
Is susceptible to buffer overflows?
Thank you!:)
Actually guys there is an error in the code, and there could be a potential security problem, coding like that in certain applications! In short checking returns values matter.
Whilst it may be argued that his program is indeed safe, the bigger picture is about the pattern on the code, and ensuring the assumed invariants of the code, which is that buf, contains a NULL terminated string between 0 and 14 bytes long.
From man page :
The fgets() function shall read bytes from stream into the array pointed to by s, until n-1 bytes
are read, or a is read and transferred to s, or an end-of-file condition is encountered.
The string is then terminated with a null byte.
RETURN VALUE
Upon successful completion, fgets() shall return s. If the stream is at end-of-file, the
end-of-file indicator for the stream shall be set and fgets() shall return a null pointer.
If a read error occurs, the error indicator for the stream shall be set, fgets() shall return
a null pointer, [CX] [Option Start] and shall set errno to indicate the error.
Arranging for an error condition, may mean no NULL may be appended to the string and the buffer is automatically allocated, so printf(3) may leak information.. think about Heardbleed.
As chux points out initialising the automatically allocated buffer buf[0] = '\0';, or declaring buf statically so it's system initialised to 0, ought not be relied upon as in event of error, the state of buf is undefined.
So a check on the return value of fgets is necessary. So something more like :
{
char *s;
if ((s = fgets( buf, sizeof buf, stdin)) {
puts( s);
}
}
Here's a link to an article on secure programming, which may be of interest http://www.dwheeler.com/secure-programs/
The use of 'fgets' does prevent the buffer overflow. According to the man page:
The fgets() function reads at most one less than the number of characters specified by size from the given stream and stores them in the string str. Read-
ing stops when a newline character is found, at end-of-file or error. The newline, if any, is retained. If any characters are read and there is no error,
a `\0' character is appended to end the string.
Notice the 'prevent' above. If you set the size larger than the actual buffer, you can then pull in more information than the buffer can hold leading to a buffer overflow. It is advisable to use
sizeof(buf)
to prevent possibly going over the buffer size.

Arrays Stack Overflow [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
#include
int main(void)
{
char str[100]="88888888888888";
char t[20]="";
gets(t);
puts(str);
puts(t);
return 0;
}
The first line
555555555555555555555555555555555
is put in.
Why str is 55555555555? Why str isn't 88888888888888888 or 55555555555588888?
You overriden the t buffer, and reached the str buffer, where the rest of the input, and the null terminator was set. And puts prints only until the null terminator.
Pretty much looks like that:
[ t (20) ][str(100) ]
55555555555555555555 5555555555555\0
Note that although t is declared as char[20], when you print it you get the full input (longer than 20), since puts stops at the null terminator (again).
BTW, this is a buffer overflow, not a stackoverflow, but stack overflow is possible on this codeas well.
As Binyamin said it is caused by the overflow you trigger because of the input string being too long. However it is a bit random thing - sometimes the two memory allocations will happen just next to each other and the string will extend to the neighbouring variables, sometimes it might not happen.
I advise you to place guard conditions for such kind of overflows.
If you see in the gets documentation:
Notice that gets does not behave exactly as fgets does with stdin as
argument: First, the ending newline character is not included with
gets while with fgets it is. And second, gets does not let you specify
a limit on how many characters are to be read, so you must be careful
with the size of the array pointed by str to avoid buffer overflows.
In your case if you do not know the size apriory maybe it is better idea to use fgets as it is more secure (though a bit slower).
When you enter a string of more than 20 5s, it overruns the buffer that was allocated to t and extends into the buffer that was allocated to str.
Then it displays the contents of str, which is the string you entered, starting at the 21st character.
Finally, it displays the contents of t, but since that string doesn't end with a null character, it continues displaying memory (which is the buffer assiged to str) until it encounters the null character after all the 5s.
In order to avoid those allocation overlapping issues you can try this alternative, so that the allocation takes place at runtime if I'm not wrong:
#include <iostream>
int main(void)
{
char *str;
char *t;
str = new char(100);
str = (char*)"88888888888888";
t = new char(20);
std::cin >> t;
puts(str);
puts(t);
return 0;
}

Resources