I've been working on a problem. I need to scan for a \n to end the cycle and delete it to not remain in a variable with other text. So far I have this:
do {
scanf("%[^\n]", userinput); //loads stdin to char[] variable
end = userinput[0]; //loads one char to char variable
scanf("%*c"); //should remove \n
strcpy(inputstorage[i], userinput); //copies userinput into 2d array of
i++; //string with \n removed
} while (end != '\n'); //should end cycle when I hit enter
What this does is, when I press enter it keeps the last char in the variable end.
For example I enter: 'Hello'
In userinput is: 'Hello'
In end is 'H'
When I hit enter afterwards the end variable should contain \n but it contains 'H' for some reason. I appreciate all the help you can provide
end = userinput[0]; saves the first character of input. scanf("%[^\n]", userinput); does not put a '\n' in userinput[], so testing if end is an end-of-line is not useful.
Use fgets() to read a line
char userinput[100];
if (fgets(userinput, sizeof userinput, stdin)) {
Then lop off the potential '\n' via various means.
size_t len = strlen(userinput);
if (len > 0 && userinput[len-1] == '\n') userinput[--len] = '\0';
If code is obliged to use scanf(),
int count;
do {
char userinput[100];
// Use a width limiter and record its conversion count : 1, 0, EOF
// scanf("%[^\n]", userinput);
count = scanf("%99[^\n]", userinput);
// Consume the next character only if it is `'\n'`.
// scanf("%*c");
scanf("%*1[\n]");
// Only save data if a non-empty line was read
if (count == 1) {
strcpy(inputstorage[i], userinput);
i++;
}
} while (count == 1);
// Input that begins with '\n' will have count == 0
A re-formed loop could use
char userinput[100];
int count;
while ((count = scanf("%99[^\n]", userinput)) == 1) {
scanf("%*1[\n]");
strcpy(inputstorage[i++], userinput);
}
scanf("%*1[\n]");
Note OP's code use '/n' in while (end != '/n');. This is not the end of line character '\n' but a rarely used multi-character constant. Certainly not what OP wanted. It also implied that warnings were not fully enabled. Save time enable all warnings. #aschepler.
You can use use scanf, getline or fgets to get the line and then strcspn to remove the "\n".
eg. userInfo[strcspn(userInfo, "\n")] = 0;
Related
What I'm trying to accomplish is to take no more than "x" characters (spaces included) as input. I only know how to do both of them separately with scanf,
like the following:
scanf("%20s",str)
This takes no more than 20 characters.
scanf("%[^\n]s",str) takes spaces as well, but it has no limit.
I tried getline but it takes the \n as a value in the string as well and I don't want that. I hope I was clear enough about what I'm asking.
From what #chqrlie has told me I wrote this fuction:
void getstring(char *str, int len)
{
do
{
if (fgets(str, len, stdin))
{
fflush(stdin);
// if is not the first character to be the new line then change it to '\0' which is the end of the string.
if (str[0] != '\n')
str[strcspn(str, "\n")] = '\0';
}
}while (str[0] == '\n'); // Check if the user has inserted a new line as first character
}
The format for character classes does not have a trailing s, it is written this way:
scanf("%[^\n]", str)
If you wish to limit the maximum number of characters stored into the destination array, specify this number between the % and the [:
scanf("%20[^\n]", str)
Note however that the conversion will fail and scanf() will return 0 if there is an empty line pending for this conversion specification.
It is a common mistake to omit the test on the return value of scanf(), causing undefined behavior in case of conversion failures because the destination variables are left in their previous state (uninitialized in many cases).
It may be more effective to use fgets() and remove the trailing newline this way:
if (fgets(s, 20, stdin)) {
/* line was read, can be an empty line */
s[strcspn(s, "\n")] = '\0'; /* remove the trailing newline if any */
...
} else {
/* fgets() failed, either at end-of-file or because of I/O error */
...
}
You can use the following:
for(i = 0; i < x; i++)
{
getchar(c);
if(c == '\n') break;
str[i] = c;
}
But you must have to be aware of the existing newlines in the buffer. :)
I was trying to take a full line input in C. Initially I did,
char line[100] // assume no line is longer than 100 letters.
scanf("%s", line);
Ignoring security flaws and buffer overflows, I knew this could never take more than a word input. I modified it again,
scanf("[^\n]", line);
This, of course, couldn't take more than a line of input. The following code, however was running into infinite loop,
while(fscanf(stdin, "%[^\n]", line) != EOF)
{
printf("%s\n", line);
}
This was because, the \n was never consumed, and would repeatedly stop at the same point and had the same value in line. So I rewrote the code as,
while(fscanf(stdin, "%[^\n]\n", line) != EOF)
{
printf("%s\n", line);
}
This code worked impeccably(or so I thought), for input from a file. But for input from stdin, this produced cryptic, weird, inarticulate behavior. Only after second line was input, the first line would print. I'm unable to understand what is really happening.
All I am doing is this. Note down the string until you encounter a \n, store it in line and then consume the \n from the input buffer. Now print this line and get ready for next line from the input. Or am I being misled?
At the time of posting this question however, I found a better alternative,
while(fscanf(stdin, "%[^\n]%*c", line) != EOF)
{
printf("%s\n", line);
}
This works flawlessly for all cases. But my question still remains. How come this code,
while(fscanf(stdin, "%[^\n]\n", line) != EOF)
{
printf("%s\n", line);
}
worked for inputs from file, but is causing issues for input from standard input?
Use fgets(). #FredK
char buf[N];
while (fgets(buf, sizeof buf, stdin)) {
// crop potential \n if desired.
buf[strcspn(buf, "\n")] = '\0';
...
}
There are to many issues trying to use scanf() for user input that render it prone to mis-use or code attacks.
// Leaves trailing \n in stdin
scanf("%[^\n]", line)
// Does nothing if line begins with \n. \n remains in stdin
// As return value not checked, use of line may be UB.
// If some text read, consumes \n and then all following whitespace: ' ' \n \t etc.
// Then does not return until a non-white-space is entered.
// As stdin is usually buffered, this implies 2 lines of user input.
// Fails to limit input.
scanf("%[^\n]\n", line)
// Does nothing if line begins with \n. \n remains in stdin
// Consumes 1 char after `line`, even if next character is not a \n
scanf("%99[^\n]%*c", line)
Check against EOF is usual the wrong check. #Weather Vane The following, when \n is first entered, returns 0 as line is not populated. As 0 != EOF, code goes on to use an uninitialized line leading to UB.
while(fscanf(stdin, "%[^\n]%*c", line) != EOF)
Consider entering "1234\n" to the following. Likely infinite loop as first fscanf() read "123", tosses the "4" and the next fscanf() call gets stuck on \n.
while(fscanf(stdin, "%3[^\n]%*c", line) != EOF)
When checking the results of *scanf(), check against what you want, not against one of the values you do not want. (But even the following has other troubles)
while(fscanf(stdin, "%[^\n]%*c", line) == 1)
About the closest scanf() to read a line:
char buf[100];
buf[0] = 0;
int cnt = scanf("%99[^\n]", buf);
if (cnt == EOF) Handle_EndOfFile();
// Consume \n if next stdin char is a \n
scanf("%*1[\n]");
// Use buf;
while(fscanf(stdin, "%[^\n]%*c", line) != EOF)
worked for inputs from file, but is causing issues for input from standard input?
Posting sample code and input/data file would be useful. With modest amount of code posted, some potential reasons.
line overrun is UB
Input begins with \n leading to UB
File or stdin not both opened in same mode. \r not translated in one.
Note: The following fails when a line is 100 characters. So meeting the assumption cal still lead to UB.
char line[100] // assume no line is longer than 100 letters.
scanf("%s", line);
Personally, I think fgets() is badly designed. When I read a line, I want to read it in whole regardless of its length (except filling up all RAM). fgets() can't do that in one go. If there is a long line, you have to manually run it multiple times until it reaches the newline. The glibc-specific getline() is more convenient in this regard. Here is a function that mimics GNU's getline():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long my_getline(char **buf, long *m_buf, FILE *fp)
{
long tot = 0, max = 0;
char *p;
if (*m_buf == 0) { // empty buffer; allocate
*m_buf = 16; // initial size; could be larger
*buf = (char*)malloc(*m_buf); // FIXME: check NULL
}
for (p = *buf, max = *m_buf;;) {
long l, old_m;
if (fgets(p, max, fp) == NULL)
return tot? tot : EOF; // reach end-of-file
for (l = 0; l < max; ++l)
if (p[l] == '\n') break;
if (l < max) { // a complete line
tot += l, p[l] = 0;
break;
}
old_m = *m_buf;
*m_buf <<= 1; // incomplete line; double the buffer
*buf = (char*)realloc(*buf, *m_buf); // check NULL
max = (*m_buf) - old_m;
p = (*buf) + old_m - 1; // point to the end of partial line
}
return tot;
}
int main(int argc, char *argv[])
{
long l, m_buf = 0;
char *buf = 0;
while ((l = my_getline(&buf, &m_buf, stdin)) != EOF)
puts(buf);
free(buf);
return 0;
}
I usually use my own readline() function. I wrote this my_getline() a moment ago. It has not been thoroughly tested. Please use with caution.
So i have a while loop to read comments off a text file as follows. There could be things after the comments so that shouldn't be ruled out. Here is my code as follows:
int i = 0;
while(!feof(fd) || i < 100) {
fscanf(fd, "#%s\n", myFile->comments[i]);
printf("#%s\n", myFile->comments[i]);
getch();
i++;
}
Comment format:
# This is a comment
# This is another comment
Any idea why it only returns the first character?
EDIT:
Here is my comments array:
char comments [256][100];
The comments array allows for 256 strings of up to 100 characters each.
The scanset " %99[^\n]" will skip leading whitespace and scan up to 99 (to allow for a terminating '\0') characters or to a newline whichever comes first.
The if condition will print the line and increment i on a commented line.
int i = 0;
char comments[256][100];
while( i < 256 && ( fscanf(fd, " %99[^\n]", comments[i]) == 1)) {
if ( comments[i][0] == '#') {
printf("%s\n", comments[i]);
i++;
}
}
Because scanf with %s reads until ' ' or '\n' or EOF. Use something like fgets.
"%s" does not save spaces.
It reads and discards leading white-space and then saves non-white-space into myFile->comments[i]
// reads "# This ", saving "This" into myFile->comments[i]
fscanf(fd, "#%s\n", myFile->comments[i]);
// Prints "This"
printf("#%s\n", myFile->comments[i]);
// reads and tosses "i"
getch();
// next fails to read "s a comment" as it does not begin with `#`
// nothing saved in myFile->comments[i]
fscanf(fd, "#%s\n", myFile->comments[i]);
// output undefined.
printf("#%s\n", myFile->comments[i]);
Instead, avoid scanf(). To read a line of input use fgets()
char buf[100];
while (fgets(buf, sizeof buf, stdin)) {
if (buf[0] == '#') printf("Comment %s", &buf[1]);
else printf("Not comment %s", buf);
}
this is my code below. What it does is not the issue. The issue is that once it is run, I put in my input and if its too small it will ask for input again on the second line which appears to have no affect the flow of my program. If I fill the buffer (which I'm assuming 100 or more) then I am not asked for a second prompt.
#include <stdio.h>
#include <string.h>
int main()
{
int ch;
char x[3];
char *word, string1[100];
x[0]='y';
while(x[0]=='y'||x[0]=='Y')
{
fgets(string1, 100, stdin);
while ( (ch = fgetc(stdin)) != EOF && ch != '\n');
printf("The string is: %s", string1);
word = strtok(string1, " ");
while(word != NULL)
{
printf("%s\n", word);
word = strtok(NULL, " ");
}
printf("Run Again?(y/n):");
fgets(x, 2, stdin);
while ( (ch = fgetc(stdin)) != EOF && ch != '\n');
}
return 0;
}
EDIT:
I have replaced,
fgets(string1, 100, stdin);
while ( (ch = fgetc(stdin)) != EOF && ch != '\n');
With,
fgets(string1, 100, stdin);
if (string1[98] != '\n' && string1[99] == '\0')
{
while ( (ch = fgetc(stdin)) != EOF && ch != '\n');
}
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 terminating null byte ('\0') is stored after the
last character in the buffer.
fgets will place all input, up to 99 chars, into string1. If you input 98 characters and hit enter (creating a 99th \n), then all 100 will be used as the last one is a \0 terminator.
Then you fall into that small while loop which does nothing but consume another line of input. If you input less than the max for your string, then input is halted while that loop waits for a \n.
If you input >98 characters, then the first 99 are saved to your input string, and the remainder along with that final \n are immediately run through that while loop, causing it to exit quickly enough that it may seem to be skipped.
I hope that helps. Unfortunately I can't comment and ask for clarification, so I'll say here that it's a little difficult to tell what exactly you want fixed or made clear.
The answer to your question is right here: man fgets
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 terminating null byte ('\0') is stored after the last character in the buffer.
To know if fgets used the whole buffer, write some non-NUL byte into the end of the buffer. If, after calling fgets, that byte has been overwritten with a NUL, it means the buffer is full. If the character directly before it is not a newline, then there's more input still to be read.
buffer[size - 1] = 'a'; // any character that's not '\0'
fgets(buffer, size, stdin);
if (buffer[size - 1] == '\0' && buffer[size - 2] == '\n') {
// handle extra input
}
Alternatively, you could just read bytes one at a time using getchar.
I think you need this:
Note: x must be int if you want to compare it against EOF
int main()
{
int x;
char *word, string1[100];
do
{
fgets(string1, 100, stdin);
printf("The string is: %s", string1);
word = strtok(string1, " ");
while(word != NULL)
{
printf("%s\n", word);
word = strtok(NULL, " ");
}
printf("Run Again?(y/n):");
x = fgetc(stdin);
fgetc(stdin); // absorb `\n`
}
while( (x=='y'||x=='Y') && x != EOF) ;
return 0;
}
This program essentially asks for a secret string, then asks a user to repeatedly guess single chars of that string until he guesses it all. It works however every second time the while loop is run it skips user input for the guessed char. How do I fix this?
int main(){
char guess;
char test2 [50];
char * s = test2;
char output [50];
char * t = output;
printf("Enter the secret string:\n");
fgets(test2, 50, stdin);
for (int i=0;i<49;i++){ //fills ouput with _ spaces
*(output +i)='_';
while(strcmp(s,t) != 0){
printf("Enter a guess:");
scanf("%c",&guess);
printf("You entered: %c\n", guess);
showGuess(guess,s, t ); // makes a string "output" with guesses in it
printf("%s\n",t);
}
printf("Well Done!");
}
For a quick and dirty solution try
// the space in the format string consumes optional spaces, tabs, enters
if (scanf(" %c", &guess) != 1) /* error */;
For a better solution redo your code to use fgets() and then parse the input.
As pointed out in some other answers and comments, you need to "consume" the "newline character" in the input.
The reason for that is that the input from your keyboard to the program is buffered by your shell, and so, the program won't see anything until you actually tell your shell to "pass the content of its buffer to the program". At this point, the program will be able to read the data contained in the previous buffer, e.g. your input, followed by one the character(s) used to validate your input in the shell: the newline. If you don't "consume" the newline before you do another scanf, that second scanf will read the newline character, resulting in the "skipped scanf" you've witnessed. To consume the extra character(s) from the input, the best way is to read them and discard what you read (what the code below does, notice the
while(getc(stdin) != '\n');
line after your scanf. What this line does is: "while the character read from stdin is not '\n', do nothing and loop.").
As an alternative, you could tell your shell to not buffer the input, via the termios(3) functions, or you could use either of the curses/ncurses libraries for the I/O.
So here is what you want:
int main(){
char guess;
char test2 [50];
char * s = test2; // 3. Useless
char output [50];
char * t = output; // 3. Useless
int i; // 8. i shall be declared here.
printf("Enter the secret string:\n");
fgets(test2, 50, stdin);
for (i=0;i<50;i++) if (test2[i] == '\n') test2[i] = '\0'; // 4. Remove the newline char and terminate the string where the newline char is.
for (int i=0;i<49;i++){ // 5. You should use memset here; 8. You should not declare 'i' here.
*(output +i)='_';
} // 1. Either you close the block here, or you don't open one for just one line.
output[49] = '\0'; // 6. You need to terminate your output string.
while(strcmp(s,t) != 0){ // 7. That will never work in the current state.
printf("Enter a guess:");
scanf("%c",&guess);
while(getc(stdin) != '\n');
printf("You entered: %c\n", guess);
showGuess(guess,s, t );
printf("%s\n",t);
}
printf("Well Done!");
return 0; // 2. int main requires that.
}
Other comments on your code:
You opened a block after your for loop and never closed it. That might be causing problems.
You declared your main as a function returning an integer... So you should at least return 0; at the end.
You seem to have understood that char * t = output; copies output's value and uses t as a name for the new copy. This is wrong. You are indeed copying something, but you only copy the address (a.k.a reference) of output in t. As a result, output and t refer to the same data, and if you modify output, t will get modified; and vice versa. Otherwise said, those t and s variables are useless in the current state.
You also need to remove the newline character from your input in the test2 buffer. I have added a line after the fgets for that.
Instead of setting all the bytes of an array "by hand", please consider using the memset function instead.
You need to actually terminate the output string after you "fill" it, so you should allocate a '\0' in last position.
You will never be able to compare the test2 string with the output one, since the output one is filled with underscores, when your test2 is NULL terminated after its meaningful content.
While variables at the loop scope are valid according to C99 and C11, they are not standard in ANSI C; and it is usually better to not declare any variable in a loop.
Also, "_ spaces" are called "underscores" ;)
Here is a code that does what you want:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 50
int main()
{
char phrase[LEN];
char guessed[LEN];
char guess;
int i, tries = 0;
puts("Please enter the secret string:");
if(fgets(phrase, LEN, stdin) == NULL)
return 1;
for(i = 0; i < LEN && phrase[i] != '\n'; i++); // Detect the end of input data.
for(; i < LEN; i++) // For the rest of the input data,
phrase[i] = '_'; // fill with underscores (so it can be compared with 'guessed' in the while loop).
phrase[LEN - 1] = '\0'; // NULL terminate 'phrase'
memset(guessed, '_', LEN); // Fill 'guessed' with underscores.
guessed[LEN - 1] = '\0'; // NULL terminate 'guessed'
while(strcmp(phrase, guessed) != 0) // While 'phrase' and 'guessed' differ
{
puts("Enter a guess (one character only):");
if(scanf("%c", &guess) != 1)
{
puts("Error while parsing stdin.");
continue;
}
if(guess == '\n')
{
puts("Invalid input.");
continue;
}
while(getc(stdin) != '\n'); // "Eat" the extra remaining characters in the input.
printf("You entered: %c\n", guess);
for(i = 0; i < LEN; i++) // For the total size,
if(phrase[i] == guess) // if guess is found in 'phrase'
guessed[i] = guess; // set the same letters in 'guessed'
printf("Guessed so far: %s\n", guessed);
tries++;
}
printf("Well played! (%d tries)\n", tries);
return 0;
}
Feel free to ask questions in the comments, if you are not getting something. :)
Newline character entered in the previous iteration is being read by scanf. You can take in the '\n' by using the getc() as follows:
scanf("%c",&guess);
getc(stdin);
..
This changed worked for me. Though the right explanation and c leaner code is the one given by #7heo.tk
Change
scanf("%c",&guess);
with
scanf(" %c",&guess);
It should ignore '\n'.