How to get rid of buffer overflow on taking input from user? - c

How to get rid of buffer overflow on taking input from user? By using fgets or scanf? If fgets then how it prevents. Some explanation required as a beginner.
#include <stdio.h>
#include <stdlib.h>
int main(){
char choice[5];
char one='1', two='2', three='3';
printf("%c. Create new account\n",one);
printf("%c. Update information of existing account\n",two);
printf("%c. For transactions\n",three);
printf("Enter your choice: ");
// fgets(choice, sizeof choice, stdin); // This OR
// fgets(choice, 3, stdin); // This one
scanf("%s",choice); // This one
printf("Here is your choice: %s", choice);
return 0;
}

A well-written program reports invalid input with a comprehensible error message, not with a crash.
Fortunately, it is possible to avoid scanf buffer overflow by either specifying a field width or using the a flag.
When you specify a field width, you need to provide a buffer (using malloc or a similar function) of type char *.You need to make sure that the field width you specify does not exceed the number of bytes allocated to your buffer.
On the other hand, you do not need to allocate a buffer if you specify the a flag character -- scanf will do it for you. Simply pass scanf an pointer to an unallocated variable of type char *, and scanf will allocate however large a buffer the string requires, and return the result in your argument. This is a GNU-only extension to scanf functionality.
Here is a code example that shows first how to safely read a string of fixed maximum length by allocating a buffer and specifying a field width, then how to safely read a string of any length by using the a flag.
int main()
{
int bytes_read;
int nbytes = 100;
char *string1, *string2;
string1 = (char *) malloc (25);
puts ("Please enter a string of 20 characters or fewer.");
scanf ("%20s", string1);
printf ("\nYou typed the following string:\n%s\n\n", string1);
puts ("Now enter a string of any length.");
scanf ("%as", &string2);
printf ("\nYou typed the following string:\n%s\n", string2);
return 0;
}
There are a couple of things to notice about this example program. First, notice that the second argument passed to the first scanf call is string1, not &string1. The scanf function requires pointers as the arguments corresponding to its conversions, but a string variable is already a pointer (of type char *), so you do not need the extra layer of indirection here. However, you do need it for the second call to scanf. We passed it an argument of &string2 rather than string2, because we are using the a flag, which allocates a string variable big enough to contain the characters it read, then returns a pointer to it.

Related

How do I write a short C program that accepts words and prints them?

I wrote the below code but I keep getting a "Command terminated by signal 11".
#include<stdio.h>
int main()
{
char *goodnight_message[20];
printf ("Enter the goodnight message.\n");
scanf ("%s", &goodnight_message);
printf ("%s Buddy.\n", *goodnight_message);
return 0;
}
I suspect that you want one char array with 20 chars, not an array of 20 char* which is what you've got now.
Note that when passing arrays to functions, like scanf and printf, they decay into pointers to the first element. Also note that when using scanf to read strings, always set a maximum number of characters to read (one less than the size of the array to leave room for the null terminator). Otherwise the user may enter more characters and your program will write out of bounds.
You should also always check if scanf is successful by checking if it returns the same number of conversions you requested. You request one only, so check if it returns 1.
A working program would then look like this:
#include <stdio.h>
int main() {
char goodnight_message[20]; // now a char[] instead
printf("Enter the goodnight message.\n");
if(scanf("%19s", goodnight_message) == 1) { // decays into a char*
printf("%s Buddy.\n", goodnight_message); // decays into a char*
}
}
This will however not read more than one word. To make scanf read until a newline you can add a set of characters to match in the conversion specifier with [characters].
If the first character of the set is ^, then all characters not in the set are matched.
We want all characters except \n so lets add the set [^\n]
#include <stdio.h>
int main() {
char goodnight_message[20];
// an alternative to printf when you don't need formatting is puts:
puts("Enter the goodnight message.");
if(scanf("%19[^\n]", goodnight_message) == 1) {
printf("%s Buddy.\n", goodnight_message);
}
}
There seems like you have a misconception of array and pointers..
While using array-like goodnight_message[20];
The correct way to address its address is to use &goodnight_message[0] indicating the beginning of the array or to use goodnight_message simply. Both of these point to the 0th index of the array..
#include<stdio.h>
int main()
{
char *goodnight_message[20];
printf ("Enter the goodnight message.\n");
scanf ("%s", goodnight_message);
printf ("%s Buddy.\n", goodnight_message);
return 0;
}
Tip: You should use gets(goodnight_message) instead of scanf when you want a string that includes a space. You can also do this by using scanf("%[^\n]s",goodnight_message);, like this:
#include<stdio.h>
int main()
{
char *goodnight_message[20];
printf ("Enter the goodnight message.\n");
scanf ("%[^\n]s", goodnight_message);
printf ("%s Buddy.\n", goodnight_message);
return 0;
}
line char *goodnight_message[20]; creates an array of strings (array of char pointers)
to create single string use char *goodnight_message; or char goodnight_message[20];
warning: if you use char *goodnight_message;, you have to malloc it, so just stick to [20] for now
scanf ("%s" reads one string from input, but note that it is only to the next whitespace
for example, input good night would read only good and output good buddy
to read whole line use gets(goodnight_message) or getline
warning: getline is a bit complicated (explanation)

c - scanf not storing input properly

My code looks like this:
int nameFull;
printf("What is your name?\n");
scanf("%d\n", &nameFull); \\up until here it seems to work
printf("Hello %d", nameFull);
return 0;
But my output every time I run the program is "Hello 0" no matter what I input.
Does anyone know how to fix this?
First of all scanf() doesn't emit a prompt so its not a good idea to use any trailing whitespace character in the format string like \n here , It will cause it to read and discard character until next non-whitespace character.
To read a name you can do it like :
char name[50];
scanf("%49s",name); // 49 to limit the buffer input to prevent buffer overrun , this is a security issue.
You should also check the return value of scanf to see if the operation was successful. Personally , I don't prefer using scanf() at all because of various potential problems. It takes as input only what the program author expects it to, not considering other inputs which user might accidentally input. Check out here and here. Also check the scanf() man page
A better and safer method would be use fgets(),
fgets(name,sizeof(name),stdin);
You want to read a string, but you are an integer to store the input. That's not the right approach.
A better aproach would be to use an array of characters, to store the string in it.
char nameFull[100]; // can store up to 100 characters, 99 + 1 for the null-terminator ideally
Now, you could use scanf, like this:
scanf(" %99[^\n]", nameFull);
Note that I used 99, as a guard for not overflowing your array nameFull, if the user inputs too many characters for the size of your array. I didn't use %s, which would stop at a whitespace, and you seem to want to input a full name, which is usually two words and a space in between.
An alternative would be to use fgets(), which provides more safety, like this:
fgets(nameFull, sizeof(nameFull), stdin)
It will read the whole line though and store the trailing newline, while scanf() will read a single string.
Moreover, use the string identifier to print, not the integer one (%s is for string, %d is for integers). Like this:
printf("Hello %d", nameFull);
to this:
printf("Hello %s", nameFull);
as discussed about the string format.
%s reads a string of characters.
%d reads a integer.
So, your correct code will be like following code :
#include <stdio.h>
int main(){
char nameFull[100];
printf("What is your name?\n");
scanf("%99s", nameFull); //to avoid potential buffer overflow
printf("Hello %s\n", nameFull);
return 0;
}
N.B: Check this comment for nice explanation.
Well, int stores a number, a name is not a number. A name is a set of characters (aka strings). So this program would work (no error checking and such since you are in an introductory course):
char name[1024]; // 1024 is more than enough space for a name
scanf("%s", name); // %s reads a string of characters
printf("Hello %s\n", name);
return 0;
You are trying to assign an array of character (commonly referred as string) to an integer variable.
That's not correct.
Just change your variable as such
char nameFull[1024] = {0};
And then use scanf(3) with the appropriate format specifiers for strings, which is %s
scanf("%s", nameFull);
Normally you would check for the return of scanf to know if errors occurs, and in such cases, handle them.
Anyway, I would advice you to use fgets(3) which prevents buffer overflow
char *fgets(char *s, int size, FILE *stream);
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte (aq\0aq) is stored after the last character in the buffer.

How to get inputs accepted in this program?

I can't take inputs except string.
If I give inputs in code itself, program is working.
But when I try to take inputs, its not working.
How do I get it to accept given inputs?
For example, if s were "codebook", and from == 'o' and to == 'e', s would become "cedebeek".
#include<stdio.h>
#define MAX 50
void replace(char *s, char from, char to)
{
int i=0;
while(s[i]!='\0')
{
if(s[i]==from)
{
s[i]=to;
}
i++;
}
}
int main()
{
char str[MAX];
char from;
char to;
printf("Enter the string");
scanf("%[^\n]s",&str[0]);
printf("\nEnter the character to be replaced");
scanf("%c",&from);
printf("\nEnter the character to be replaced with");
scanf("%c",&to);
replace(str, from, to);
printf("\nThe modified string is %s",str);
return(0);
}
There are a couple of problems in the posted code. Since arrays decay to pointers to their first elements in most expressions, there is no need for the address operator & in the call to scanf(); also, the trailing s is not part of the scanset conversion specifier:
scanf("%[^\n]", str);
As pointed out by #M.M in the comments, it is not incorrect to use &str[0] here instead of str, but it is more idiomatic, and I personally find it more clear, to use the less cluttered str.
When scanf() returns, a newline character will be left in the input stream, so you should add a leading space in the next call to scanf() to skip over this \n character before reading the user input:
scanf(" %c",&from);
And this call to scanf() will also leave a \n character in the input stream, so again:
scanf(" %c",&to);
Note that you should really specify a maximum width to avoid buffer overflow when reading user input into a string; there is no easy way to do this with MAX, but you can do:
scanf("%49[^\n]", str);
You could further improve code and ensure that input is as expected by checking the values returned by the calls to scanf().

C - Not printing out the whole string

int main()
{
//Define Variables
char studentName;
//Print instructions to fill the data in the screen
printf("Please type in the Students name:\n");
scanf("%s", &studentName);
printf("\n\n%s", &studentName);
return 0;
}
Seeing the above code, I am only printing to screen out the first word when I type in a sentence.
I know it is a basic thing, but I am just starting with plain C.
Read scanf(3) documentation. For %s is says
s Matches a sequence of non-white-space characters; the next
pointer must be a pointer to character array that is long
enough to hold the input sequence and the terminating null
byte ('\0'), which is added automatically. The input string
stops at white space or at the maximum field width, whichever
occurs first.
So your code is wrong, because it should have an array for studentName i.e.
char studentName[32];
scanf("%s", studentName);
which is still dangerous because of possible buffer overflow (e.g. if you type a name of 32 or more letters). Using %32s instead of %s might be safer.
Take also the habit of compiling with all warnings enabled and with debugging information (i.e. if using GCC with gcc -Wall -g). Some compilers might have warned you. Learn to use your debugger (such as gdb).
Also, take the habit of ending -not starting- your printf format string with \n (or else call fflush, see fflush(3)).
Learn about undefined behavior. Your program had some! And it misses a #include <stdio.h> directive (as the first non-comment significant line).
BTW, reading existing free software code in C will also teach you many things.
There are three problems with your code:
You are writing a string into a block of memory allocated for a single character; this is undefined behavior
You are printing a string from a block of memory allocated for a single character - also an undefined behavior
You are using scanf to read a string with spaces; %s stops at the first space or end-of-line character.
One way to fix this would be using fgets, like this:
char studentName[100];
//Print instructions to fill the data in the screen
printf("Please type in the Students name:\n");
fgets(studentName, 100, stdin);
printf("\n\n%s", &studentName);
return 0;
Try scanf("%[^\n]", &studentName); instead of scanf("%s", &studentName);
This is happening because %s stops reading the input as soon as a white space is encountered.
To avoid this what you can do is declare an array of the length required for your string.
Then use this command to input the string:-
scanf("%[^\n]s",arr);
This way scanf will continue to read characters unless a '\n' is encountered, in other words you press the enter key on your keyboard. This gives a new line signal and the input stops.
int main()
{
//Define Variables
char studentName[50];
//Print instructions to fill the data in the screen
printf("Please type in the Students name:\n");
scanf("%[^\n]s", &studentName);
printf("\n\n%s", &studentName);
return 0;
}
Alternatively you can also use the gets() and puts() method. This will really ease your work if you are writing a code for a very basic problem.
[EDIT] : As dasblinkenlight has pointed out...I will also not recommend you to use the gets function since it has been deprecated.
int main()
{
//Define Variables
char studentName[50];
//Print instructions to fill the data in the screen
printf("Please type in the Students name:\n");
gets(studentName); printf("\n\n");
puts(studentName);
return 0;
}
make the changes below and try it. I added [80] after the studentName definition, to tell the compiler that studentName is an array of 80 characters (otherwise the compiler would treat it as only one char). Also, the & symbol before studentName is not necessary, because the name of the array implicitly implies a pointer.
int main()
{
//Define Variables
char studentName[80];
//Print instructions to fill the data in the screen
printf("Please type in the Students name:\n");
scanf("%s", studentName);
printf("\n\n%s", studentName);
return 0;
}
Your problem is here
char studentName;
It is a char, not a string.
Try:
Define it as an array of chars like char studenName[SIZE];.
allocating memory dynamically using malloc:
.
char buffer[MAX_SIZE];
scanf("%s", &buffer);
char * studentName = malloc (sizeof(buffer) + 1);
strcpy (studentName , buffer);

Using the scanf() function

I intend to modify each other letter of a particular string. But for the purposes of this program none of that occurs. So far I've grabbed a string from the user and stored it in userinput and intend to print it.
#include <stdio.h>
#include <string.h>
int main(void) {
char userinput[256] ="";
printf("Enter somthing to change:\n");
scanf("%s", &userinput);
printf("%s\n", userinput);
int k = 2; // This is just here to do something every time k is even
int j = strlen(userinput);
for (int i = 0; i < j; i++) {
if(k % 2 == 0) {
printf("%s", userinput[i]);
k++;
}
else {
printf("%s", userinput[i]);
k++;
}
}
}
The strlen() function however does not work on the userinput. I figure this is because strlen() is supposed to take the address of the first char of a string and then iterate until reaching a null char but scanf doesn't actually create a null char.
I couldn't figure out a way of adding the '\0' after the string without first knowing the length of the string.
How would I go about accessing the length of a stored character sequence if it's stored in an array?
This:
scanf("%s", &userinput);
should be:
scanf("%s", userinput);
The address of operator & is unrequired, and incorrect. Arrays decay to the address of their first element when passed to a function. scanf("%s") will append a null terminating character so it is unnecessary to explicitly insert one.
To prevent potential buffer overrun specify the maximum number of characters that scanf() should write to userinput. This should be one less than the size of userinput, leaving room for the terminating null character:
scanf("%255s", userinput);
The incorrect format specifier (which is undefined behaviour) is being used to print the characters of userinput: use %c not %s. This:
printf("%s", userinput[i]);
must be:
printf("%c", userinput[i]);
Change
scanf("%s", &userinput);
to
scanf("%s", userinput);
The & operator is not required in the case of String capture. The scanf() automatically appends the null character('\0') to the end of the string so int j = strlen(userinput); should work.
If you still want to calculate the length without this function efficiently here is the link How to calculate the length of a string in C efficiently?
Change this
scanf("%s", &userinput);
with
scanf("%s", userinput);
we have to use addresses for scanf:
If we will scan into an int a then we have to call scanf() with the address of a => &a
If we will scan into a double a then we have to call scanf() with the address of a => &a
But If we will scan data into with pointer (memory address) int *a; or char array char a[50]; then we have to call scanf() with the pointer or with the array without adding &
From the scanf() page
Depending on the format string, the function may expect a sequence of
additional arguments, each containing a pointer to allocated storage
where the interpretation of the extracted characters is stored with
the appropriate type. There should be at least as many of these
arguments as the number of values stored by the format specifiers.
Additional arguments are ignored by the function. These arguments are
expected to be pointers: to store the result of a scanf operation on a
regular variable, its name should be preceded by the reference
operator (&) (see example).
You're confused about types, as others have indicated. Using scanf and printf when you're confused about types is dangerous!
scanf("%s", &userinput);
The type of &userinput is char (*)[256], but scanf expects %s to correspond to a char *. Since the type expected and the type given differ and aren't required to have the same representation, the behaviour is undefined.
I figure this is because strlen is supposed to take the address of the
first char of a string and then iterate until reaching a null char but
scanf doesn't actually create a null char.
Wrong. scanf certainly does assign a null character, when you use the %s format specifier. That is, providing scanf doesn't encounter an error or EOF. On that note, you should probably check for errors from scanf:
if (scanf("%s", userinput) != 1) {
/* Insert error handling here */
}
... as you should with all standard library functions in C.
k is pointless. Your loop already increments i at the same frequency as k.
strlen returns a size_t. Make sure you store return values in the right types. If a function returns size_t, then you store the return value in size_t. If a function returns int, then you store the return value in an int. Got it? Whatever the return type is, is whatever type you use to store the return type. Use the manual to find that out.
printf("%s", userinput[i]);
There's that type confusion again. userinput[i] is a char. %s tells printf to expect a char *. When the argument is invalid, the behaviour is undefined. That may cause your program to malfunction. Consider printf("%c", userinput[i]); or printf("%s", &userinput[i]);.

Resources