Why do I need an ampersand before the array in the printf statement here, but any other time ampersand is only used in scanf?
Completely new so if you could explain as simply as possible that would help.
int main(void) {
char word[1];
scanf("%s", &word[0]);
printf("%s", word[0]);
return 0;
}
You do need one. It's incorrect without one and leads to undefined behavior, which may cause anything to happen (even the program appearing to work correctly). Also, word[1] can only hold the null terminator of an empty string, any more than that and it will cause the buffer to overflow, also causing undefined behavior. It should be:
int main(void) {
char word[10]; // or any value that is big enough for the input that your anticipating
scanf("%9s", &word[0]);
printf("%s", &word[0]);
return 0;
}
And of course you can replace &word[0] with word.
Also note that I put %9s instead of just %s for the scanf call, which means that it will get at most 9 characters, which with the added null terminator fits into the word[10] that we have as an example. This way you don't get undefined behavior if the user enters something that's too big and instead it would just truncate that input.
word[0] is the first character.
the & sign is used to get a pointer to such character.
scanf("%s", &word[0]);
printf("%s", word[0]);
In C, a string (addressed by %s in above statements) is defined as an array. Your declaration of "word":
char word[1];
declares an array, so that array can be a string (I wrote can, because it's a very short string...). If you use the identifier alone, "word", the compiler uses a pointer to the first element of the array. Hence:
scanf("%s", word);
printf("%s", word);
are both correct. But if you use an index into the array, like "word[0]", then you are no more using the array per se, but instead an element of it. This notation does not generate a pointer, but your above statements do need a pointer. So you can use an "&" to get a pointer.
Conclusion: if you have a string, use its simple name without indexing inside the array. Using the ampersand makes it clear that we pass a reference, but "&word[0]" is ugly and, moreover, everybody should know that scanf() writes into its arguments.
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
#include <stdio.h>
int main(){
int age;
char name[] ="";
printf("enter your age: ");
scanf("%d", &age);
printf("enter your name: ");
scanf("%s", &name);
printf("your name is %s and you are %d years old.",name, age);
return 0;
}
If i for example set the age to "20" and the name to "name", it outputs the following:
your name is name and you are 6647137 years old.
Why does it say "6647137" years instead of 20?
char name[] ="";
You do not define name correctly.
#define MAX_NAME_LENGTH 100
char name[MAX_NAME_LENGTH+1];
Defining it incomplete and completing it afterwards you make it point to some region where there may be other variables aound the array defining the string literal, or the string literal can be even in RO memory, making it impossible to write. It is undefined behavior trying to write at the pointer of a string literal (6.4.5.p6 String literals, page 63).
You overwrite beyond the much too short array of chars for name.
It currently is of size 1, holding exactly only the teminating '\0'.
Your weird age value can in many environment be explained by the integer being the first victim.
Make sure to use an array of sufficient size.
Also it is very much recommended to use advanced features of scanf() to avoid buffer overrun.
Please read the documentation:
https://en.cppreference.com/w/c/io/fscanf
And this article might be very helpful:
http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html
Learn this soon and learn this well: C does not have a first-class "string" type!
When you wrote
char name[] = "";
you did not declare a string variable, that initially contained an empty string, but that could and would automatically expand to contain any string you tried to assign to it.
No, what you got was an array of char of size exactly 1, initially containing the empty string, consisting of exactly (and only) the string-terminating character '\0'. This array can't be used for much of anything: the only thing it's ever going to be able to contain is the empty string, because it doesn't (and will never) have room for anything more.
In C, it is generally your responsibility to know how big your strings are going to be, and to explicitly allocate each variable to refer to enough memory for any string it might contain.
For example, you could write
char name[11] = "";
Now what you're saying is, "Give me an array of characters, sufficient to contain strings up to 10 characters long (plus 1 for the terminating \0 character), initially containing the empty string."
Now you can safely say
scanf("%s", name);
But there are two more points to make.
First, you'll notice that I have left out the &. You might have gotten the impression that you always need the & on your variables when you call scanf. And that's a real rule, but it has an exception: it turns out that you do not need the & when you're using %s to read a string into an array. Sometimes the error is innocuous (the code will happen to work anyway), but sometimes it will cause problems (such as when you use %s to read into an array pointed to by a pointer variable). My compiler warns me warning: format specifies type 'char *' but the argument has type 'char (*)[1]' when I do something like this.
But second, if we've declared
char name[11] = "";
, then how do we actually enforce that? How do we arrange that we, or a function like scanf over which we have less control, won't accidentally try to write more than 10 characters to our name array?
As we've already seen, if you just call
scanf("%s", name);
you don't get any protection. scanf will read as many characters as the user types, until it sees a newline or other whitespace, and it will write all those characters to the variable you provided, and if that's more characters than the variable can hold, boom, something bad happens.
One way of protecting against this is to give scanf a limit on the number of characters it can read:
scanf("%10s", name);
Now, by putting that 10 in there, you're telling scanf not to read a string longer than 10 characters, so it won't overflow your name array.
The whole function the question is about is about giving a two dimensional array initialized with {0} as output and making a user able to move a 1 over the field with
char wasd;
scanf("%c", &wasd);
(the function to move by changing the value of the variable wasd is not important i think)
now my question is why using
scanf("%s", &wasd);
does only work partly(sometimes the 1 keeps being at a field and appears a 2nd time at the new place though it actually should be deleted)
and
scanf("%.1s", &wasd);
leads to the field being printed out without stop until closing the execution program. I came up with using %.1s after researching the difference between %c and %s here Why does C's printf format string have both %c and %s?? If one can figure out the answer by reading through that, i am not clever or far enough with c learning to get it.
I also found this fscanf() in C - difference between %s and %c but i do not know anything about EOF which one answer says is the cause of the problem so i would prefer getting an answer without it.
Thank you for an answer
Simple as that, %s is the conversion for a (non-empty) string. A string in C always ends with a 0 byte, so any non-empty string needs at least two bytes. If you pass a pointer to a single char variable, scanf() will just overwrite whatever is in memory after that variable -- you cause undefined behavior and anything can happen.
Side note, scanf("%s", ..), even if you give it an array of char, will always overflow the buffer if something longer is entered, therefore causing undefined behavior. You have to include a field width like
char str[10];
scanf("%9s", str);
Best is not to use scanf() at all. For your single character input, you can just use getchar() (be aware it returns an int). You might also want to read my beginners' guide away from scanf.
A char variable can hold only one byte of memory to hold a single character. But a string (array of characters) is different from a char variable as it is always ended with a null character \0 or numeric 0. So in scanf you specifically mentioned whether you are reading a character or a string so that scanf can add a null character at the end of a string. So you are not suppose to use a %s to read a value for a char variable
I'm trying to read the characters of a character array by number in c. I've stripped the program down to isolate the problem. I know this is about my misunderstanding of how arrays and memory works and I am ready to be called clueless but I would like to know what I am misunderstanding here. Here is what I have:
#include <stdio.h>
int main(int argc, char **argv) {
char buffer[] = "stuff";
printf("buffer is %s\n", buffer);
printf("first character of buffer is %s", (char)buffer[0]);
return 0;
}
You have to write the correct format specifier. Now you used %s ...what happens?
It looks for an string which is null terminated. But it doesn't find one. So it simply cant put anything in the output . That's it.
Use %c instead.
In C there is a very big difference between a character and a string.
A character is simply a number in a range of 256 different options.
A string is not really a type of its own, it is merely an array of chars (which, in C, is simply evaluated as a pointer to the first character of the string).
Now, when you type buffer[0], this is evaluated to the value at the beginning of the string (first value in the array). Indeed, this is of char type (and therefore you do not need the (char) casting, because this will not do anything in the case of your code).
What you need is to tell printf() how to evaluate the input that you give it. %s is for a string (an array of chars). But note and remember that buffer[0] is not an array of chars, but rather a char.
So you actually want to use %c, instead of %s. This tells printf() to evaluate the parameter as a char type.
What your code currently does is take the value buffer[0] (which is just a number) and consider it as a pointer to a location in memory where a string is kept, and printf() tries to print this string. But this memory location is simply invalid. It is not a location you've accessed before.
In conclusion you want:
printf("first character of buffer is %c", (char)buffer[0]);
or even simpler:
printf("first character of buffer is %c", buffer[0]);
For other specifiers of the printf() function, look here:
http://www.tutorialspoint.com/c_standard_library/c_function_printf.htm
If you want to print only a single char use %c format.
printf("first character of buffer is %c\n", (char)buffer[0]);
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