void someFunction(){
char *buffer;
size_t bufsize = 32;
int bytes_read;
for (;;) {
buffer = (char *) malloc(bufsize * sizeof(char));
if (buffer == NULL) {
perror("Unable to allocate buffer");
exit(1);
}
FILE *ptr;
ptr = fopen("sample.txt", "a");
printf("Enter Stuff to write down:\n");
//getline(&buffer,&bufsize,stdin);
//fgets(buffer, 30, stdin);
//scanf("%[^\n]%*c", buffer);
//scanf("%s", buffer);
if (buffer[0] == '0') {
break;
}
WriteWithFprintf(ptr, buffer);
free(buffer);
fclose(ptr);
}
}
The problem is: if I use
getline(&buffer,&bufsize,stdin);
or
fgets(buffer, 30, stdin);
then it escapes the first like so:
Enter Stuff to write down:
Enter Stuff to write down:
0
If I use:
scanf("%[^\n]%*c", buffer);
then I get an infinite loop.
It does work with:
scanf("%s", buffer);
but I want input with space so this is not an option for me.
All of the behaviors described for different variations on your code are consistent with the next character available to be read from stdin being a newline, presumably from a preceding line of input.
In that case,
the getline() and fgets() alternatives will read the newline (and any preceding characters) as a line, and then loop to read the line you actually want on the second pass.
the first scanf() variation will read nothing on account of a matching failure for the %[^\n] field (leading whitespace is not skipped for %[ directives). Not having matched anything to that, there will be no attempt to match anything to the %*c.
the second scanf() alternative will work as you describe, because scanf will automatically consume leading whitespace when processing a %s directive, including any newline.
There is a variety of things you could do, depending on exactly how want to handle input. Here is one:
int c = fgetc(stdin);
if (c == EOF) {
// handle eof ...
} else if (c != '\n') {
ungetc(c, stdin);
}
// your choice for reading the wanted data ...
That will consume up to one leading newline from stdin to get it out of your way.
getline and fgets failed to get input on first attempt
Neither failed. Both simply read a '\n' and immediately returned. This '\n' was left-over from a previous input function like scanf("%s", ...), that did not consume the entire line. getline() is not part of the standard C library.
scanf("%[^\n]%*c", buffer); fails to read anything when the first available character is '\n'.
scanf("%s", buffer); consumes all optional leading white space like '\n'. This may appear to work for OP.
scanf("%[^\n]%*c", buffer); and scanf("%s", buffer); are both poor code as they do not have a width limit, risking buffer overflow.
I recommend for a learner to not use scanf() at all and perform all input with fgets(), including the part of code not posted.
Related
What is the use of scanf("\n"); statement before scanf("%[^\n]%*c", s) ?
int main()
{
char ch;
char str [100];
char s[100];
scanf("%c",&ch);
printf("%c",ch);
scanf("%s",&str);
printf("\n%s",str);
scanf("\n"); // <<< what is the purpose of this line
scanf("%[^\n]%*c",s);
printf("\n%s",s);
return 0;
}
So what is the use of scanf("\n"); statement before scanf("%[^\n]%*c", s) ?
What is the use of scanf("\n");
The true answer is probably that the original author of this code was flailing, desperately trying to get scanf to work, despite scanf's various foibles.
Other evidence that the original author was having problems:
scanf("%c", &ch);
When reading individual characters, the %c often does not work as expected or as desired. Most of the time, at least in code like this, it is necessary to add a space, like this: " %c".
scanf("%[^\n]%*c", s);
This line, also, is difficult to understand. It is attempting to read one full line of text, a task which scanf is not well-suited for.
Overall the code appears to be attempting to read one single character, followed by one string (not containing whitespace), followed by one full line of text (possibly containing whitespace).
Given its shortcomings (and scanf's shortcomings), I'd say it's not even worth trying to figure out what the original code will do. A considerably cleaner way of accomplishing this task (still using scanf) would be
if(scanf(" %c", &ch) != 1) exit(1);
printf("%c\n",ch);
if(scanf("%99s", str) != 1) exit(1);
printf("%s\n", str);
if(scanf(" %99[^\n]", s) != 1) exit(1);
printf("%s\n", s);
Note these changes:
checking return value of scanf
extra space in " %c", as mentioned
%99s instead of plain %s, to avoid array overflow
no & before str with %s
extra space with %[…] also
length modifier 99 with %[…] also
no %*c after %[…]
(cosmetic/stylistic) printing \n at the end of each line
If you're trying to do anything at all fancy, it's often much easier to just skip scanf, and go with more powerful techniques. I might use something like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char chbuf[5];
char ch;
char str [100];
char s[100];
printf("enter a character:\n");
if(fgets(chbuf, 5, stdin) == NULL) exit(1);
ch = *chbuf;
printf("%c\n", ch);
printf("enter a string:\n");
if(fgets(str, 100, stdin) == NULL) exit(1);
str[strcspn(str, "\n")] = 0; /* strip \n */
printf("%s\n", str);
printf("enter a line:\n");
if(fgets(s, 100, stdin) == NULL) exit(1);
s[strcspn(s, "\n")] = 0;
printf("%s\n", s);
}
This simply used fgets to read all input, one line at a time. To fetch a single character, it then grabs the first character of a short line. (Also it's printing explicit prompts, since that helps to avoid confusion.)
One small drawback of fgets is that it always leaves the \n in the buffer. I've used a common albeit somewhat obscure trick to strip it back off; see this question for an explanation.
This modified program works, although it is different from the original in one significant respect: it will allow whitespace in the first string read as well as the second.
Also, the modified program insists that the three inputs be on three separate lines, while the original would have accepted them all on the same line (or on two lines, or on three lines). Whether that is an improvement or a disimprovement, I can't say. :-)
If you want to limit yourself to a subset of scanf's full complexity, using simple invocations of it for the simple uses it's well-suited for, and avoiding it for the more complicated problems that it's dreadfully painful to use for, you might read the suggestions at this answer.
After this incorrect call of scanf
scanf("%s",&str);
where the second parameter shall be
scanf("%s",str);
the input buffer can contain the new line character '\n' and the next call of scanf
scanf("%[^\n]%*c",s);
can read as a result an empty string.
So this call
scanf("\n");
is an attempt to remove the new line character from the input buffer.
However it will be better just to write
scanf(" %[^\n]%*c",s);
See the leading space in the format string. It allows to skip white space characters in the input buffer.
So here's my code:
main()
{
char *iochar;
printf(" Enter a standard line: ");
scanf ( "%s", &iochar);
if (iochar != NULL)
{
printf(" Here's what you entered: %s ", &iochar);
}
else
{
printf(" Oops! Looks like you forgot to enter something! ");
}
}
My problem is that I can scan the user entry and store it and if something exists it puts out the correct message. But if I just hit return to test for no input (null, empty, etc) the program neither quits nor outputs my error message. It just hangs until I input something.
I've been programming in Java for the last two semesters so C is totally lost on me right now. So any help would be much appreciated.
scanf ( "%s", &iochar); is not useful for detecting an empty line.
"%s" first directs scanf() to read and discard all leading white-space, including '\n' before proceeding to read non-white-space characters. So code has lost the '\n'.
Instead use fgets()
// Enough room for 80 characters + \n + \0
#define LINE_SIZE (80 + 1 + 1)
char buf[LINE_SIZE];
if (fgets(buf, sizeof buf, stdin) == NULL) {
puts("end-of-file or input error detected");
} else if (buf[0] == '\n') {
puts("Empty line entered");
} else {
printf("Input line: <%s>\n", buf);
}
Input
Hello World (and <Enter>)
Output (Note the \n read in is still retained)
Input line: <Hello World
>
To be clear: In C, a string is a sequence of characters up to and including a terminating null character '\0'. Users do not enter strings. User input is usually a line of text up to and including a terminating line feed '\n'. fgets() reads a line of input and then appends a null character to the resultant buffer is a string`.
Here's my advice: Don't use scanf. Its rules are confusing, and it's very difficult to get the behaviour you want.
Instead, I recommend you use getch to manually read each character into a buffer until the user enters a newline character '\n'. Then you can zero terminate the buffer with a 0, and then use the buffer as a normal string. For it to be empty, just check the length of the string with strlen(x).
I am currently having an issue replacing gets() with fgets(). I have looked at multiple examples of doing this and it seems very straight forward however I am getting unexpected output in doing so. Using the gets() method in comments below, I get good behavior from my shell program I am writing, however when I change to the fgets() call, I get output ": no such file or directory" when giving input "ls". Like I said, with the gets() call it is working fine. code below:
int main(void) {
while(1) {
int i = 0;
printf("$shell: ");
scanf("%s", first);
/* gets(input);*/
fgets(input, sizeof(input), stdin);
//...parse input into tokens for exec system call...
execvp(first, args);
}
return 0;
}
Unlike gets, fgets will read the newline and store it in the string.
From the man page:
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 '\0' is stored after the last character in the
buffer.
You can remove the newline (if it is present) by replacing it will a null byte:
fgets(input, sizeof(input), stdin);
if (input[strlen(input)-1] == '\n') input[strlen(input)-1] = '\0';
I have to take inputs like below, and print the same (only the sentences):
2
I can't believe this is a sentence.
aarghhh... i don't see this getting printed.
Digit 2 shows the number of lines to be followed (2 lines after this here).
I used all the options scanf and fgets with various regex used.
int main() {
int t;
char str[200];
scanf ("%d", &t);
while (t > 0){
/*
Tried below three, but not getting appropriate outputs
The output from the printf(), should have been:
I can't believe this is a sentence.
aarghhh... i don't see this getting printed.
*/
scanf ("%[^\n]", str);
//scanf("%200[0-9a-zA-Z ]s", str);
//fgets(str, 200, stdin);
printf ("%s\n", str);
t--;
}
}
I am sorry, i have searched all related posts, but I am not able to find any answer to this:
All versions of scanf() produce no results, and fgets() prints only the first sentence.
Thanks in advance.
You should just use fgets(). Remember that it will keep the linefeed, so you might want to remove that manually after reading the line:
if(scanf("%d", &t) == 1)
{
while(t > 0)
{
if(fgets(str, sizeof str, stdin) != NULL)
{
const size_t len = strlen(str);
str[len - 1] = '\0';
printf("You said '%s'\n", str);
--t;
}
else
printf("Read failed, weird.\n");
}
}
To make it easier let's say the input is "2\none\ntwo\n".
When you start your program, before the first scanf() the input buffer has all of it and points to the beginning
2\none\ntwo
^
After the first scanf(), the "2" is consumed leaving the input buffer as
2\none\ntwo
^^
And now you attempt to read everything but a newline ... but the first thing in the buffer is a newline, so nothing gets read.
Suggestion: always use fgets() to read full lines, and then parse the input as you think is better.
To use regex in C you must include regex.h. In this case, you do not need regex. Where you have "%[^\n]", replace it with "%s". Make sure that you include stdio.h.
will this actually verify my users input has only two elements then a newline?
char newline
scanf(" %s %s%c", out, in, &newline);
if(newline != '\n'){
error();
}
You must check the return status from scanf(); if it does not return 3, you failed the validation. Your checks will ensure that there are two 'words' (possibly preceded by some space). You won't be allowed trailing space after the second word. Note that you might need to 'eat' the rest of the line if the validation fails - you won't if you have a newline in newline.
Yes, that will work. But only if the input matches exactly: word word<enter>.
If the user types anything different from that format, for instance, a space between the 2nd word and enter, your logic will fail.
char newline;
char out[50];
char in[50];
scanf("%s %s%c", out, in, &newline);
if(newline != '\n')
{
printf("error!");
}
Also, scanf shouldn't be used to read from the input like that. Consider using fgets to read the input and strtok to parse the data.
No! scanf will work incorrect if there are some whitespace character between second string and newline. use getc() for that:
scanf("%s%s", buf1, buf2);
char newline = 0;
while((newline = getc()) == ' ' || newline == '\t');
if(newline != '\n'){
error();
}
Edit:
Adding case for trailing whitespaces.