This question already has answers here:
Program didn't crash when buffer overflow
(2 answers)
Closed 6 years ago.
If I input string of more than size 10 then why is not generating compile time error as I have declared str of size 10? For example I have input welcome to the world, then it is compiling and running with no error.
#include <stdio.h>
#include <conio.h>
int main() {
int i = 0, length;
char str[10];
printf("enter string: ");
gets(str);
while (str[i] !='\0') {
i = i + 1;
}
length = i;
printf("the length of string is %d", length);
}
An input string is a runtime entity. Any computation involving it cannot be performed at compile time, so the best you can do is raise a runtime error.
Furthermore, gets is marked deprecated in C99 and simply removed from C11 because exactly this insecure behavior cannot be prevented: without anyone complaining, you can write beyond array bounds, which is undefined behavior. Use fgets instead, which provides a higher level of security.
Because gets does not take a length parameter it does not know how large your input buffer is.
you can use fgets instead
It is a undefined behaviour. Anything can happen.
Never use gets() because it does not prevent buffer overflowing which is what your program is doing. Use fgets() instead of gets().
fgets() prevent the size of array beyond that.
fgets(array, sizeOfArray, stdin);
Because you defined the string length as 10, so if the value increases the program stops executing, moreover you have not made handling error mechanism for the code. So resulting the following error you mentioned. Use fgets
Related
visual studio erro
dev c++
this code is working in dev c++, ut not working visual studio. erro is
Error C4996 'scanf': This function or variable may be unsafe. Consider using scanf_s instead.
code is...
#include<stdio.h>
int main() {
int arr[5] = { 0 };
int i = 0;
printf("Enter the number :");
for (i = 0; i < 5; i++) {
scanf("%d", &arr[i]);
}
return 0;
Short answer: scanf doesn't provide protection from arithmetic overflow, thus, it's unsafe to use.
Detailed answer:
The original issue begins with the Buffer Overflow problem of gets in C. Link: Issue of gets and solution
It was because of gets function that one of first most widespread worm was able to propagate itself throughout the internet. Because gets overwrites the stack/memory allocated to variable used to store it. This leads to buffer overflow.
Scanf link: Disadvantages of scanf() and its alternative
Unlike gets, scanf does provide safety with string buffers by limiting the size, but, it is not possible for arithmetic input. Arithmetic input will overwrite the stack buffer. Although scanf provides a way to avoid buffer overflow problem with strings but, usually we (lazy programmers) won't specify the limits while using the scanf, hence we wrote an alternative scanf_s
Other alternatives of scanf are, strtol, strtok, and atoi, among others.
Edit 1: Changed from sscanf to scanf_s in ...hence, we wrote an alternative...
plz help me to remove SIBABRT error for the following code,plz suggest me why this error occurs even after getting correct output
#include<stdio.h>
#include<string.h>
int main()
{
char x[25],y[25];
int i,j=0;
scanf("%s",x);
for(i=0;i<strlen(x);i++)
{
if(x[i]>=97 && x[i]<=122)
{
y[j]=x[i]-32;
j++;
}
else if(x[i]>=65 && x[i]<=90)
{
y[j]=x[i]+32;
j++;
}
}
printf("%s",y);}
Think of the difference between the source and the destination array, something is missing in the destination. The null-terminator.
Note: Both the arrays are local variable with automatic storage and unless initialized explicitly, their content is indeterminate.
Without a null-terminator in place, printf() will go out of bound for the supplied array while printing with %s which invokes undefined behavior.
The easiest way to handle this is zero-initilize the arrays, like
char x[25] = {0} ,y[25] = {0};
which makes all the elements of the arrays set to 0, and the same value being used as null-terminator, you are not required to add one manually to the destination array.
Also, FWIW,
You should length-limit the input to prevent buffer overflow from longer than expected input, using something along the line scanf("%24s",x);
better to use fgets() to take the user input. If, iff, you have to use scanf(),you can use it but please use proper error checking.
If the input is less than 25 characters, then the string will be null terminated. If the size exceeds the array size specified then it overwrites the memory not belonging to the array.
So fgets() is the alternative for scanf() in such case.
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));
I found a C Program whose purpose is to input a string while using dynamic memory allocation.
However I am having difficulty understanding the logic behind it.
#include <stdio.h>
#include <stdlib.h>
#define MAX 10
int main(void)
{
char *A;
int max_int=0;
printf("Enter max string length: ");
scanf("%d",&max_int);
while ((getchar())!='\n');
A=(char *)malloc(max_int+1); //room for null char
printf("Enter string: ");
fgets(A,max_int,stdin);
}
What is the purpose of while ((getchar())!='\n'); ? It seems redundant to me, since your only inputing a number before it gets called.
while ((getchar())!='\n');
The above line is used to flush anything on the line not read by scanf, for example non-digits and spaces, so the next input starts in a new line.
Also:
scanf-call should check the number of assigned matches (0 matches is possible.
the result of malloc should never be cast (that just hides bugs).
the result of malloc should be checked for NULL. (Warning: Undefined Behavior)
fgets expects the buffer length and guarantees 0-termination. Passing one less means you get a shorter string.
I am using Linux.
I am trying to write a program in c that will print a string backward.
Here is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (){
char string[100];
printf ("Enter string:\n");
gets (string);
int length = strlen (string)-1;
for (length = length; length>=0; length--){
puts (string[length]);
}
}
And here is the error:
a.c:10: warning: passing argument 1 of ‘puts’ makes pointer from integer without a cast
/usr/include/stdio.h:668: note: expected ‘const char *’ but argument is of type ‘char’
/tmp/cc5rpeG7.o: In function `main':
a.c:(.text+0x29): warning: the `gets' function is dangerous and should not be used.
What should I do?
Forget that the function gets() exists - it is lethal. Use fgets() instead (but note that it does not remove the newline at the end of the line).
You want to put a single character at a time: use putchar() to write it to stdout. Don't forget to add a newline to the output after the loop.
Also, for (length = length; length >= 0; length--) is not idiomatic C. Use one of:
for ( ; length >= 0; length--)
for (length = strlen(string) - 1; length >= 0; length--)
for (int length = strlen(string) - 1; length >= 0; length--)
The last alternative uses a feature added to C99 (which was available in C++ long before).
Also, we could debate whether length is the appropriate name for the variable. It would be better renamed as i or pos or something similar because, although it is initialized to the length of the input, it is actually used as an array index, not as the length of anything.
Subjective: Don't put a space between the name of a function and its parameter list. The founding fathers of C don't do that - neither should you.
Why is gets() lethal?
The first Internet worm - the Morris worm from 1988 - exploited the fingerd program that used gets() instead of fgets(). Since then, numerous programs have been crashed because they used gets() and not fgets() or another alternative.
The fundamental problem is that gets() does not know how much space is available to store the data it reads. This leads to 'buffer overflows', a term which can be searched for in your favourite search engine that will return an enormous number of entries.
If someone types 150 characters of input to the example program, then gets() will store 150 characters in the array which has length 100. This never leads to happiness - it usually leads to a core dump, but with carefully chosen inputs - often generated by a Perl or Python script - you can probably get the program to execute arbitrary other code. This really matters if the program will ever be run by a user with 'elevated privileges'.
Incidentally, gets() is likely to be removed from the Standard C library in the next release (C1x - see n1494 from WG14). It won't vanish from actual C libraries for a long time yet (20 years?), but it should be replaced with this implementation (or something similar):
#undef NDEBUG
#include <assert.h>
char *gets(char *buffer)
{
assert("Probability of using gets() safely" == 0);
}
One other minor detail, discussed in part under the comments to the main question.
The code shown is clearly for C99; the declaration of length part way through the function is invalid in C89. Given that, it is 'OK' for the main() function not to explicitly return a value, because the C99 standard follows the lead of the C++ standard and allows you to omit the return from main() and the effect is the same as return(0); or return 0; at the end.
As such, the program in this question cannot strictly be faulted for not having a return at the end. However, I regard that as one of the more peculiar standardizing decisions, and would much prefer it if the standards had left that provision out - or done something more radical like allowing the ubiquitous but erroneous void main() observing that when control returns from that, the result is that a success status is returned to the environment. It isn't worth fighting to get that aspect of the standard changed - sadly - but as a personal style decision, I don't take advantage of the licence granted to omit the final return from main(). If the code has to work with C89 compilers, it should have the explicit return 0; at the end (but then the declaration of length has to be fixed too).
You can also use recursion to do it. I think it looks nicer then when using a loop.
Just call the method with your string, and before printing the char in the method, call the method again with the same string, minus the first char.
This will print out you string in reversed order.
First:
NEVER NEVER NEVER NEVER NEVER use gets(); it will introduce a point of failure in your code. There's no way to tell gets() how big the target buffer is, so if you pass a buffer sized to hold 10 characters and there's 100 characters in the input stream, gets() will happily store those extra 90 characters in the memory beyond the end of your buffer, potentially clobbering something important. Buffer overruns are an easy malware exploit; the Morris worm specifically exploited a gets() call in sendmail.
Use fgets() instead; it allows you to specify the maximum number of characters to read from the input stream. However, unlike gets(), fgets() will save the terminating newline character to the buffer if there's room for it, so you have to account for that:
char string[100];
char *newline;
printf("Enter a string: ");
fflush(stdout);
fgets(string, sizeof string, stdin);
newline = strchr(buffer, '\n'); // search for the newline character
if (newline) // if it's present
*newline = 0; // set it to zero
Now that's out of the way...
Your error is coming from the fact that puts() expects an argument of type char *, but you're passing an argument of type char, hence the "pointer from integer without cast" message (char is an integral type). To write a single character to stdout, use putchar() or fputc().
You should use putchar instead of puts
So this loop:
for (length = length; length>=0; length--){
puts (string[length]);
}
Will be:
for (length = length; length>=0; length--){
putchar (string[length]);
}
putchar will take a single char as a parameter and print it to stdout, which is what you want. puts, on the other hand, will print the whole string to stdout. So when you pass a single char to a function that expects a whole string (char array, NULL terminated string), compiler gets confused.
Use putc or putchar, as puts is specified to take a char* and you are feeding it a char.