I have been trying to get a string input from a user using fgets
but fgets does not wait for input so upon investagation I learned of the gets function which seems to be working fine. My questions are: 1. Why does gets work when I input more than 10 characters if I declared an array of only ten elements. Here is my code
#include<stdio.h>
int main(void){
char name[10];
printf("Please enter your name: ");
gets(name);
printf("\n");
printf("%s", name);
return 0;
}
my input when testing: morethantenletters
will output: 'morethantenletters'
Surely, this should have caused some errors, no? Since name is only ten elements long.
2. My next question is that my code also works when I use gets(&name) instead of gets(name)-- I do not understand why. The &name is sending the address of name.while name is just sending the value of it, no?
That is exactly why you should always use fgets to replace gets. The array name has only 10 elements, but you are trying to store in it more than it's capable of. fgets prevents the program from buffer overflow, but gets doesn't.
It's undefined behavior when you are using gets in this way, don't use it.
Since name is only ten elements long.
Anything accepted more than 10 will be buffer overrun and may cause run time issues. So make sure your size is right. hint: Use getline or fgets instead.
while name is just sending the value of it, no?
For char arrays, name is also address to its starting position.
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 9 months ago.
Improve this question
I am new to C, I have written a very simple program to get the first name and surname, here is my code...
#include <stdio.h>
#include <conio.h>
int main(){
int num,bankpin;
char fn[20],sn[20];
printf("Welcome to authorization. We ill now begin the process");
printf("\nFirst, please enter your first name: ");
scanf(" %s",fn);
printf("\nEnter your surname: ");
scanf(" %s",sn);
printf("\nWelcome to the system %c %c",&fn,&sn);
return 0;
}
Welcome to authorization. We ill now begin the process
First, please enter your first name: A
Enter your surname: A
Welcome to the system α
Why is this strange "a" appearing on my screen instead of "A A"?
In fact it appears on my screen even if I try a different combination of letters
I have even tried recompiling the code
I'm guessing this is because you are trying to print &fn, which is a pointer, as char. You're basically telling the program to interpret the address o as a symbol code.
Try changing the
printf("\nWelcome to the system %c %c",&fn,&sn) to
printf("\nWelcome to the system %s %s",fn,sn)
Short answer
You are sending the array pointer's address as an argument, and telling printf to interpret it as a single char, resulting in undefined behavior. The fix is to replace the line
printf("\nWelcome to the system %c %c",&fn,&sn);
with
printf("\nWelcome to the system %s %s",fn,sn);
Long answer
The weird character is due to your code reading an unintended value, and trying to interpret it. If you run your code a few times, you will find that you don't always get this symbol, but many other ones, including nothing at all (seemingly). What is going here ?
The short answer is that you are misinforming the printf function by giving her a false symbol and a false value. Let's look at a similar example :
char myString[20] = "Hello!";
printf("%c", &myString);
In this snippet we create an array of characters, which actually means creating a pointer of char* type, and allocating its size (here to 20). Pointers are often confusing when starting with C, but they are in principle pretty simple : they are simply variables that, instead of containing a value, contain an address. Since arrays in C store their value sequentially, that is one after the other, it makes quite a lot of sense to have them be pointers : if you know where the array starts, and that its members are spaced evenly, it makes it quite easy to go over the array.
So since your array is a pointer, reading it directly will print something along the lines of "0x7ffc5a6dbb70". Putting '&' before it gives a very similar result : this operator consists in asking for the address of a variable, which is then in your code transmitted to the printf as an argument.
This doesn't make any sense there : a char is, in C, behind the scene, actually an integer variable with very small capacity, from 0 to 255 to be precise. For example the two lines in the following snippet produce the same result :
printf("%c", 'a');
printf("%c", 97);
Now you see what is happening in the original printf : the function is expecting to receive a very small integer to convert to one character, and instead receives an address, which is the reason why the output is so weird. Since addresses change basically at every run of the code, that is also the reason why the output changes very often.
You thus need to adapt the information in the printf function. First, inform that you wish to print a char array with the symbol "%s". This will make the function expect to receive a pointer to the first element of a char array, which it will then iterate over. Thus, as argument, you need to send this pointer, that you directly have in the form of the myString variable.
Thus running
char myString[20] = "Hello!";
printf("%s", myString);
prints 'Hello!', as expected :)
The funcion scanf is a little tricky, please delete the leading space, inside quotes only include what are you expecting to receive, ever.
scanf("%s",fn);
The printf function needs %s, same as scanf, to deal with string, later you don't need the & operator in this case.
printf("\nWelcome to the system %s %s",fn,sn);
#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 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've been struggling with this code for quite some time now.
This is my first time posting here. I am new to C, and I feel that I almost got it.
I have to ask for your name, middle initial, and last name. Then I greet you and tell you the length of your name. Sounds simple enough. I have the following code, I have to use the header file as it is here and that makes things worse. Any help would be greatly appreciated, I feel that I already applied all my knowledge to it and still can't get it to work.
This is my header file:
#ifndef NAME_H_
#define NAME_H_
struct name{
char first[20];
char middle;
char last[20];
};
#endif
and this is my .c file:
#include "name.h"
#include <stdio.h>
#define nl printf("\n");
int strlen(char*s);
char first;
char middle;
char last;
main()
{
printf("enter your first name : ");
scanf("%c", &first);
printf("\n enter your middle initial name : ");
scanf("%c", &middle);
printf("\n enter your last name: ");
scanf("%c", &last);
printf("\n\n Hello %c",first, " %c" ,middle, " %c", last);
printf("\n The String returned the following length: ",strlen);
}
I have t use printf and scanf, then store the name components a name "structure" imported from name.h and lastly use int strlen(char *s); to calculate it.
I get this output with the weird indentation and everything:
enter your first name : Joe
enter your middle initial name :
enter your last name:
Hello J
The String returned the following length: [-my user id]$
Thanks!
Several things about this are not quite right.
First, you shouldn't be declaring strlen yourself. It's a standard C library function, which means you should include the appropriate header. In this case,
#include <string.h>
Second, you're storing the input in variables of type char. Those are literally what they say: they store a single character. So unless you're only allowing people to have single-character names, you need a bit more than that. This sort of string input problem is actually rather tricky in C, since you have to do explicit memory management and don't know how much data the user is going to send you in advance. One of the simpler things is to just use a large buffer and truncate, but for a more complex program you'd want to do error handling and possibly dynamically resize the buffer. But for starters:
char first[1024];
char middle[1024];
char last[1024];
will at least get you started. Your struct name has some of this, but you're not currently using it (and the sizes are pretty small).
Next, scanf is a tricky way to get input strings. scanf of a %s pattern will happily read more than 1024 characters and write over the end of the buffer and destroy your program. This is why C programmers usually read input data using fgets instead, since then you can more easily say how big of a buffer you're willing to read:
fgets(first, sizeof(first), stdin);
Be aware that if the user enters more than 1023 characters, it will read the first 1023 characters and then leave the rest there, where you'll end up reading it as part of the middle name. String handling in C is complex! C is not good at this sort of thing; that's why people tend to use Perl or similar languages for this sort of interactive string handling where you don't know sizes in advance. In C, you have to pursue a strategy like repeatedly calling fgets until you get a newline at the end of the result and then deciding whether to dynamically resize your data structure or throw an error. Alternately, you can use scanf with %1023s but you need to qualify the format to specify the maximum length. The syntax is a bit weird and tricky; fgets is simpler when you're reading character strings.
As mentioned in the other answer, strlen is a function that you need to call on a char * variable (or char array) to get the length of the string it holds. You probably want to call it on first, middle, and last and add them together.
Finally, in your last printf, you have to pass one format and then all of the arguments for that format. You want something more like:
printf("\n\n Hello %s %s %s", first, middle, last);
(once you fix the type of those variables).
This is a lot of random detail. I hope it helps some. The important brief takeaway is that a string in C is a sequence of char ending in a char with a value of 0, and all C data structures have to be sized in advance (either statically or dynamically with malloc). C furthermore has no bounds checking, so it's completely up to you to ensure that you only read as much data as you created space for.
use
strlen(first)
to get the length of variable first ..similarly for other varibles... To get the cumulative length use
printf("\n Length: ",strlen(first)+strlen(middle)+strlen(last));