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
Related
I'm new to this, and I'm assuming there is an easy solution to my issue. My first formula works exactly how I'd like it to. If the user input matches dogage99, then it prints "Correct". I want to do something similar, but using words instead of numbers. I've switched double for char, and adjusted the formula accordingly.
The problem is, the second formula doesn't work as I expected. When the user input matches dogname1, it doesn't print "Correct", it just continuously asks to "enter dog name".
What can I do to fix my issue?
int main()
{
double guess99;
double dogage99 = 3;
while (guess99 != dogage99) {
printf ("enter dog age:");
scanf ("%lf", &guess99);
}
printf ("Correct\n");
char guess1;
char dogname1= "spot";
while (guess1 != dogname1) {
printf ("enter dog name:");
scanf ("%s", &dogname1);
}
printf ("Correct\n");
First of all the line
char dogname1= "spot";
should be corrected to
char *dogname1= "spot";
This way the char array dogname1 will be correctly initialized as a character array and will contain the null-terminator "\0" at the end of the array.
You must also ensure, that guess has enough memory secured, so you must either create a array of sufficiently enough bytes (for e.g. 256), or dynamically allocate memory. In this example I would do the first changing char guess1; to char guess1[256];
Knowing that guess1 has sufficiently enough memory and a null-terminator we can next rewrite the while loop to
while(strcmp(guess1, dogname1)) { ... }
The strcmp() standard library function returns 0 if and only if both character arrays match lexicographical and that is also the time we want to go out of the loop. It is also important to know, that you must ensure both arrays have null-terminators when using this exact function. If you cannot ensure it, then use strncmp().
For reference about all the different compare functions and their implications: https://www.ibm.com/docs/en/aix/7.1?topic=s-strcmp-strncmp-strcasecmp-strcasecmp-l-strncasecmp-strncasecmp-l-strcoll-strcoll-l-subroutine
I am sure the compiler is complaining big time at you about
char dogname = "spot";
in c the type char represent a single character not a string. Strings in C are a sequnce of characters followed by a char set to \0. The compiler will set that up for you if you do
char *dogname="spot";
It will allocate 5 bytes , load s,p,o,t,\0 into those bytes and set the dogname variable to point at the first character.
If you want to compare string you have to use the c library function called strcmp - https://man7.org/linux/man-pages/man3/strcmp.3.html.
Alos you need a char array to receive the input. We just say we want 50 characters. Must also tell scanf to not allow more than 50 charaters. Note that I asked for 51 character array to allow for the trailing 0 that must always be present.
so your loop becomes
char guess1[51];
char *dogname1= "spot";
while (guess1 != dogname1) {
printf ("enter dog name:");
scanf ("%50s", guess1);
}
printf ("Correct\n");
note you must #include string.h
check this out https://www.tutorialspoint.com/cprogramming/c_strings.htm
Edit: for my class I have to use scanf. So recommending other ways of input is not the solution I am looking for (if there is one that involves scanf).
If I am reading in user input for a small project (for example, a game). Lets say I ask would you like to play? This would accept a yes or no answer. So i write up some simple code like this:
#include <stdio.h>
int main(void)
{
char string[3]; //The max number of letters for "yes".
printf("Would you like to play?");
scanf("%s", string);
}
So this code should simply ask them to input yes or no. I am setting the length of my char array to size 3. This way it is large enough to hold yes and also no. But if someone were to enter invalid input such as yesss, I know how to compare the string afterwards to handle such an event, but wouldn't this technically/possibly overwrite other local variables I have declared because it would extend outside the length of my array? If so, is there a way to handle this to restrict 3 input characters or something? And if not, why/how does it know to only input for the size of 3?
Your array needs to be able to hold four chars, since it must also contain the 0-terminator. With that fixed, specifying a maximal length in the format,
scanf("%3s", string);
ensures that scanf reads no more than 3 characters.
the safest way is to use
fgets(string, 4, stdin);
here you can store maximum 3 characters including one space reserved for NULL ('\0') character.
You should use the width modifier of scanf() and set it to be one less than the size of your string, so that you ensure that space exists for the NULL terminator.
So, if you want to store "yes", you will firstly need a bigger array than the one you have; one with size 4, 3 characters plus 1 for the null terminator. Moreover, you should instruct scanf() to read no more than size - 1 characters, where size is the length of your array, thus 3 in this case, like this:
#include <stdio.h>
int main(void)
{
char string[4];
scanf("%3s", string);
}
http://www.cplusplus.com/reference/clibrary/cstdio/scanf/
use the "width" modifier;
%[*][width][modifiers]type
#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)
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.
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