I checked here and there and wasted around 3 hours checking for a solution. My program just infinite loop itself. Here is my C program:
#include <stdio.h>
#include <string.h>
int main (void)
{
int attempts = 0;
char password[10];
do
{
printf("Enter your password:\n");
scanf("%[^\n]s", password);
printf("\n");
attempts++;
} while (strcmp(password, "awesome 123 ok"));
printf("You entered a correct password in %d attempts!", attempts);
return 0;
}
I tried scanf("%[A-Za-z0-9 ]s", password)"so it can take all characters and numbers including space as an input but it just loop. And I also tried using getchar() but it asks for password again and again even if I enter the correct one. Any help will be appreciated.
Size of awesome 123 ok is 15 including \0. But you are allocating memory for 10 bytes. It causes undefined behavior.
When you are using %[^\n] format specifier no need to use s with that, It will automatically scan the spaces also.
Try the following changes-
int main (void)
{
int attempts = 0;
char password[20]; // Fix 1
do
{
printf("Enter your password:\n");
scanf("%[^\n]", password); // Fix 2
printf("\n");
attempts++;
} while (strcmp(password, "awesome 123 ok"));
printf("You entered a correct password in %d attempts!", attempts);
return 0;
}
You declare char password[10]; but you compare it with awesome 123 ok which has more characters.
From this scanf (and family) reference:
All conversion specifiers other than [, c, and n consume and discard all leading whitespace characters before attempting to parse the input.
That means that the trailing newline (a whitespace character) will be included in the next call to scanf in the loop.
The solution is simple: Tell scanf to read and discard leading whitespace:
scanf(" %[^\n]", password);
/* ^ */
/* | */
/* Note leading space */
Also note that I removed the trailing s in the format, because that tells scanf to expect a literal s in the input. The "%[" format ends with the closing ']'.
You also might want to limit the number of characters read so you don't overflow the buffer you read into:
scanf(" %9[^\n]", password);
Note that the above format set the maximum field width as nine characters, because the buffer needs to include the terminating '\0' character as well. Modify this number if you increase the buffer size, but remember that it should be (at most) one less than the buffer size.
Change the dec password[10] to password[20]
I would use fgets because it is a safer way than gets or scanf:
#include <stdio.h>
#include <string.h>
int main (void) {
int attempts = 0;
char password[20];
do {
printf("Enter your password:\n");
fgets(password, sizeof(password), stdin);
password[strlen(password) - 1] = '\0';
printf("\n");
attempts++;
} while (strcmp(password, "awesome 123 ok"));
printf("You entered a correct password in %d attempts!", attempts);
return 0;
}
Now, this will only work if you increase the size of password[] as I did in my example. When not using fgets it might still work in a bad way because you are comparing a buffer overflow.
The issue is that password is too narrow. Because of this, the program routinely writes past the end of the array, resulting in undefined behaviour.
You can fix this by making password wider. However, your program will still be open to stack smashing: an attacker can potentially execute arbitrary code by entering a long carefully crafted password string.
To fix that, you need to change the scanf() format specifier to limit how many characters it can store in password.
The following changes will fix both:
char password[32]; /* more space: 31 characters + NUL */
do {
...
scanf("%31[^\n]%*c", password); /* format specifier */
The latter will make sure you're never reading more than 31 characters into password; it also consumes the newline without storing it.
Add getchar() to consume the \n character. Find the modified code in below.
int main (void)
{
int attempts = 0;
char password[10];
do
{
printf("Enter your password:\n");
scanf("%[^\n]s", password);
getchar (); // Fix1
printf("\n");
attempts++;
} while (strcmp(password, "awesome 123 ok"));
printf("You entered a correct password in %d attempts!", attempts);
return 0;
}
The array password is not used properly in your code. So change the logic for it. User can enter N numbers of character. So restrict the user input to limited character or use dynamic memory allocation
Related
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
int n=1,i,cont;
char string[50];
scanf("%d",&n);
while(n!=0){
gets(string);
cont=0;
for(i=0;i<strlen(string);i++){
if(string[i]=='.'){
cont++;
}
}
if(cont%2==0){
printf("S\n");
}else{
printf("N\n");
}
scanf("%d",&n);
}
return 0;
}
My problem is quite simple but troublesome, I want to read an integer value n, and then read a string, after that read n again, but whenever I run the program, it only reads the string value... but if I digit 0 the program ends... it's like my scanf is within the gets function.
Mixing scanf with gets or fgets is troublesome because they each handle newlines differently.
Get rid of the gets call (which is unsafe anyway) and replace it with the following scanf call:
scanf("%49s", string);
This will read at most 49 characters into string (i.e. one less that its size).
From OP's comments, it sounds like the goal is to be able to read strings containing spaces. While there are ways to accomplish this using scanf(), it would be better to use fgets(), which is at the least less error-prone.
The fgets() function can be used to read input for the number into a buffer, and this buffer can then be processed by sscanf() to extract the number. Since fgets() keeps the newline character, it is not left behind to interfere with the next I/O operation.
But, when fgets() is used to get the string, since the newline is retained, it may be desirable to remove it. This can be accomplished in a number of ways, but here strcspn() is used to provide the index of the first \r or \n character encountered; a \0 character is then written to this location, removing the terminating newline from the string.
The code below illustrates these suggestions. Note that both buffer[] and string[] are generously allocated to accommodate reasonably large inputs. If a user enters a large number of characters (more than 999 in this case), the extra characters are left behind in the input stream for the next I/O function call. Also note that the main loop has been streamlined a bit; now there is a for(;;) loop that never terminates, broken out of when the user enters 0 for the number. And, there is a nested loop within the main loop that prompts the user to enter a number until a valid number is entered. Since the #include <stdlib.h> was unnecessary, it was removed. Better code would check the values returned from the calls to fgets() for possible errors.
#include<stdio.h>
#include<string.h>
int main(void)
{
int n = 1, cont;
char buffer[1000];
char string[1000];
for (;;) {
/* Loop until user enters a number */
do {
printf("Please enter a number: ");
fgets(buffer, sizeof buffer, stdin);
} while (sscanf(buffer, "%d", &n) != 1);
/* Break on 0 */
if (n == 0) break;
/* Get a string, and remove trailing newline */
printf("Please enter a string\n");
fgets(string, sizeof string, stdin);
string[strcspn(string, "\r\n")] = '\0';
cont = 0;
for (size_t i = 0; i < strlen(string); i++) {
if (string[i] == '.') {
cont++;
}
}
if (cont % 2 == 0){
printf("S\n");
} else {
printf("N\n");
}
}
return 0;
}
When you enter 5 for an example, you hit a new line character afterwards.
So you are entering 2 characters: 5 and a new line character.
That new line character is causing your headache.
The new line character is also considered an input.
In order to ignore this new line char, simply add a new line that acts as a garbage collection:
char garbage[50];
scanf( "%d", &n);
fgets(garbage, sizeof(garbage), stdin);
This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 5 years ago.
I am aware of scanf() usage and is not encouraged. But I've the problem, where scanf sends the stdin value to the next function stdin. I'm wondering why it's doing like this.
code:
#include <stdio.h>
void ffgets() {
char name[40];
printf("What's your name? ");
if (fgets(name, 40, stdin)) {
printf("Hello %s", name);
}
}
int main(int argc, char **argv) {
int a;
printf("enter a number: ");
int res = scanf("%d", &a);
if (res > 0) {
printf("Valid Integer %d.\n", a);
} else {
printf("It's not a number\n");
}
ffgets();
return 0;
}
Output:
Test case 1:
Why the function doesn't ask for stdin, it just print empty string
./a.out
enter a number: 23
Valid Integer 23.
What's your name? Hello
Test case 2: I entered the string with the special character that is passed name.
./a.out
enter a number: random##¤
It's not a number
What's your name? Hello random##¤
I dont want stdin value from main passed to the function, how to do that?
If you input something that scanf can not match to the format specification then it will stop immediately and leave the input in the input buffer for the next input function.
Also, when using scanf it will not consume the trailing newline in the input buffer, also leaving it for the next input function.
To solve both problems consider using fgets to get the whole line from the input, and then use sscanf to parse the string.
I am aware of scanf() usage and is not encouraged.
This is exactly the issue that comes from scanf() (namely, that input not used by scanf is left in the input buffer, contrary to what the user expected). So, as you seem to already know, the solution is to not use the function.
It's not that hard to make a function to read a complete line of input, and parse an int from there with sscanf() or strtol or friends:
#include <stdio.h>
#include <limits.h>
int getint(void)
{
char buffer[120] = {0}; /* arbitrary limit */
fgets(buffer, 120, stdin);
int a;
if (sscanf(buffer, "%d", &a) == 1) {
return a;
}
return INT_MIN;
}
(Of course INT_MIN is a valid number to enter, so you might want to have some better way of returning errors. And perhaps consider what to do with garbage following the number.)
The reason is that in the first case, the matching input is consumed by scanf() but the newline \n is present in the input buffer. That makes a valid input and terminator for fgets() in the first case.
Related , quoting C11, chapter §7.21.6.2
Trailing white space (including new-line characters) is left unread unless matched by a
directive. [....]
In the second case, the matching failure happens, which makes the entire input to be available in the input buffer at the time of fgets() call, so fgets() reads the whole thing.
This question already has answers here:
How do you allow spaces to be entered using scanf?
(11 answers)
Closed 6 years ago.
#include <stdio.h>
int main()
{
char name[20];
printf("Enter name: ");
scanf("%s", name);
printf("Your name is %s.", name);
return 0;
}
Output:
Enter name: Dennis Ritchie
Your name is Dennis.
So far I haven't found any specific valid reason for this question. Can anyone help me out?
scanf only read till it gets to space that is why it is not storing after the first space , so your printf function is not faulty , it is the scanf that is not storing the complete string , stopping on encountering first space.
One should never use gets() , unless they completely know what they are doing , because it does not have buffer overflow protection , it continue to read after the buffer ends until it finds a new line or encounter a EOF. You can read more about that here.Please Check This Why is the gets function so dangerous that it should not be used?
You should instead use fgets().
#include <stdio.h>
int main(){
char name[20];
printf("Enter name: ");
fgets(name,20,stdin);
printf("Your name is %s.", name);
return 0;
}
Remember fgets() also reads newline character(the one you get when you press enter) so you should manually remove that.
Also I highly Recommend this answer for using fgets() to its full potential and avoiding common pitfalls.
This answer tells about using scanf to read string.What it says is the following:
int main(){
char string[100], c;
int i;
printf("Enter the string: ");
scanf("%s", string);
i = strlen(string); // length of user input till first space
do{
scanf("%c", &c);
string[i++] = c; // reading characters after first space (including it)
}while (c != '\n'); // until user hits Enter
string[i - 1] = 0; // string terminating
return 0;
}
How this works? When user inputs characters from standard input, they will be stored in string variable until first blank space. After that, rest of entry will remain in input stream, and wait for next scanf. Next, we have a for loop that takes char by char from input stream (till \n) and appends them to end of string variable, thus forming a complete string same as user input from keyboard.
why doesn't this code work?
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
// local declarations
int len;
char* pStr;
// statements
printf(" how many characters you want to enter?\n");
scanf("%d", &len);
pStr=(char*)calloc(len+1,sizeof(char));
printf("\n enter your string: ");
gets(pStr);
*(pStr+len)='\0';
printf("\n your string: ");
puts(pStr);
printf(" oops! last character deleted.");
getch();
return 0;
}
although it runs correct, when i use scanf function to read the string, but
why it does not with gets?
scanf("%s", pStr) skips to the first non-whitespace character while gets doesn't.
After the first scanf the trailing newline is still in the input buffer so that when you call gets the result is an empty line unless you entered extra characters after the number.
Note that gets is marked as obsolete due to serious security flaws.
It is recommended that any use of gets(var) is replaced with fgets(var, length, stdin).
Because arrays are zero based, and (assuming the input is valid and the correct length, assumption which your code ought not to make) *(ptr + len) already contains \0 and you are just overwriting it. You meant to overwrite ptr[len-1]
This question already has answers here:
How do you allow spaces to be entered using scanf?
(11 answers)
Closed 4 years ago.
I'm using Ubuntu and I'm also using Geany and CodeBlock as my IDE.
What I'm trying to do is reading a string (like "Barack Obama") and put it in a variable:
#include <stdio.h>
int main(void)
{
char name[100];
printf("Enter your name: ");
scanf("%s", name);
printf("Your Name is: %s", name);
return 0;
}
Output:
Enter your name: Barack Obama
Your Name is: Barack
How can I make the program read the whole name?
Use:
fgets (name, 100, stdin);
100 is the max length of the buffer. You should adjust it as per your need.
Use:
scanf ("%[^\n]%*c", name);
The [] is the scanset character. [^\n] tells that while the input is not a newline ('\n') take input. Then with the %*c it reads the newline character from the input buffer (which is not read), and the * indicates that this read in input is discarded (assignment suppression), as you do not need it, and this newline in the buffer does not create any problem for next inputs that you might take.
Read here about the scanset and the assignment suppression operators.
Note you can also use gets but ....
Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.
Try this:
scanf("%[^\n]s",name);
\n just sets the delimiter for the scanned string.
Here is an example of how you can get input containing spaces by using the fgets function.
#include <stdio.h>
int main()
{
char name[100];
printf("Enter your name: ");
fgets(name, 100, stdin);
printf("Your Name is: %s", name);
return 0;
}
scanf(" %[^\t\n]s",&str);
str is the variable in which you are getting the string from.
The correct answer is this:
#include <stdio.h>
int main(void)
{
char name[100];
printf("Enter your name: ");
// pay attention to the space in front of the %
//that do all the trick
scanf(" %[^\n]s", name);
printf("Your Name is: %s", name);
return 0;
}
That space in front of % is very important, because if you have in your program another few scanf let's say you have 1 scanf of an integer value and another scanf with a double value... when you reach the scanf for your char (string name) that command will be skipped and you can't enter value for it... but if you put that space in front of % will be ok everything and not skip nothing.
NOTE: When using fgets(), the last character in the array will be '\n' at times when you use fgets() for small inputs in CLI (command line interpreter) , as you end the string with 'Enter'. So when you print the string the compiler will always go to the next line when printing the string. If you want the input string to have null terminated string like behavior, use this simple hack.
#include<stdio.h>
int main()
{
int i,size;
char a[100];
fgets(a,100,stdin);;
size = strlen(a);
a[size-1]='\0';
return 0;
}
Update: Updated with help from other users.
#include <stdio.h>
// read a line into str, return length
int read_line(char str[]) {
int c, i=0;
c = getchar();
while (c != '\n' && c != EOF) {
str[i] = c;
c = getchar();
i++;
}
str[i] = '\0';
return i;
}
Using this code you can take input till pressing enter of your keyboard.
char ch[100];
int i;
for (i = 0; ch[i] != '\n'; i++)
{
scanf("%c ", &ch[i]);
}
While the above mentioned methods do work, but each one has it's own kind of problems.
You can use getline() or getdelim(), if you are using posix supported platform.
If you are using windows and minigw as your compiler, then it should be available.
getline() is defined as :
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
In order to take input, first you need to create a pointer to char type.
#include <stdio.h>
#include<stdlib.h>
// s is a pointer to char type.
char *s;
// size is of size_t type, this number varies based on your guess of
// how long the input is, even if the number is small, it isn't going
// to be a problem
size_t size = 10;
int main(){
// allocate s with the necessary memory needed, +1 is added
// as its input also contains, /n character at the end.
s = (char *)malloc(size+1);
getline(&s,&size,stdin);
printf("%s",s);
return 0;
}
Sample Input:Hello world to the world!
Output:Hello world to the world!\n
One thing to notice here is, even though allocated memory for s is 11 bytes,
where as input size is 26 bytes, getline reallocates s using realloc().
So it doesn't matter how long your input is.
size is updated with no.of bytes read, as per above sample input size will be 27.
getline() also considers \n as input.So your 's' will hold '\n' at the end.
There is also more generic version of getline(), which is getdelim(), which takes one more extra argument, that is delimiter.
getdelim() is defined as:
ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
Linux man page
If you need to read more than one line, need to clear buffer. Example:
int n;
scanf("%d", &n);
char str[1001];
char temp;
scanf("%c",&temp); // temp statement to clear buffer
scanf("%[^\n]",str);
"%s" will read the input until whitespace is reached.
gets might be a good place to start if you want to read a line (i.e. all characters including whitespace until a newline character is reached).
"Barack Obama" has a space between 'Barack' and 'Obama'. To accommodate that, use this code;
#include <stdio.h>
int main()
{
printf("Enter your name\n");
char a[80];
gets(a);
printf("Your name is %s\n", a);
return 0;
}
scanf("%s",name);
use & with scanf input