My objective is to change the delimiter of scanf to "\n".
I tried using scanf("%[^\n]s",sen); and works fine for single inputs.
But when i put the same line inside a for loop for multiple sentences it gives me garbage values.
Does anyone know why?
Here's my code:
char sen[20];
for (i=0;i<2;i++)
{
scanf("%[^\n]s",sen);
printf("%s\n",sen);
}
Consider this (C99) code:
#include <stdio.h>
int main(void)
{
char buffer[256];
while (scanf("%255[^\n]", buffer) == 1)
printf("Found <<%s>>\n", buffer);
int c;
if ((c = getchar()) != EOF)
printf("Failed on character %d (%c)\n", c, c);
return(0);
}
When I run it and type in a string 'absolutely anything with spaces TABTABtabs galore!', it gives me:
Found <<absolutely anything with spaces tabs galore!>>
Failed on character 10 (
)
ASCII (UTF-8) 1010 is newline, of course.
Does this help you understand your problem?
It works in this case (for a single line) but if I want to take multiple lines of input into an array of arrays then it fails. And I don't get how scanf returns a value in your code?
There are reasons why many (most?) experienced C programmers avoid scanf() and fscanf() like the plague; they're too hard to get to work correctly. I'd recommend this alternative, using sscanf(), which does not get the same execration that scanf() and fscanf() do.
#include <stdio.h>
int main(void)
{
char line[256];
char sen[256];
while (fgets(line, sizeof(line), stdin) != 0)
{
if (sscanf(line, "%255[^\n]", sen) != 1)
break;
printf("Found <<%s>>\n", sen);
}
int c;
if ((c = getchar()) != EOF)
printf("Failed on character %d (%c)\n", c, c);
return(0);
}
This reads the line of input (using fgets() which ensures no buffer overflow (pretend that the gets() function, if you've heard of it, melts your computer to a pool of metal and silicon), then uses sscanf() to process that line. This deals with newlines, which are the downfall of the original code.
char sen[20];
for (i=0;i<2;i++)
{
scanf("%[^\n]s",sen);
printf("%s\n",sen);
}
Problems:
You do not check whether scanf() succeeded.
You leave the newline in the buffer on the first iteration; the second iteration generates a return value of 0 because the first character to read is newline, which is the character excluded by the scan set.
The gibberish you see is likely the first line of input, repeated. Indeed, if it were not for the bounded loop, it would not wait for you to type anything more; it would spit out the first line over and over again.
Return value from scanf()
The definition of scanf() (from ISO/IEC 9899:1999) is:
§7.19.6.4 The scanf function
Synopsis
#include <stdio.h>
int scanf(const char * restrict format, ...);
Description
2 The scanf function is equivalent to fscanf with the argument stdin interposed
before the arguments to scanf.
Returns
3 The scanf function returns the value of the macro EOF if an input failure occurs before
any conversion. Otherwise, the scanf function returns the number of input items
assigned, which can be fewer than provided for, or even zero, in the event of an early
matching failure.
Note that when the loop in my first program exits, it is because scanf() returned 0, not EOF.
%[^\n] leaves the newline in the buffer. %[^\n]%*c eats the newline character.
In any case, %[^\n] can read any number of characters and cause buffer overflow or worse.
I use the format string %*[^\n]%*c to gobble the remainder of a line of input from a file. For example, one can read a number and discard the remainder of the line by %d%*[^\n]%*c. This is useful if there is a comment or label following the number, or other data that is not needed.
char sen[20];
for (i=0;i<2;i++)
{
scanf("%[^\n]s",sen);
printf("%s\n",sen);
getchar();
}
Hope this helps ... actually "\n" remains in stream input buffer... Ee need to flush it out before scanf is invoked again
I know I am late, but I ran into same problem after testing C after a long time.
The problem here is the new line is considered as input for next iteration.
So, here is my solution, use getchar() to discard the newline the input stream:
char s[10][25];
int i;
for(i = 0; i < 10; i++){
printf("Enter string: ");
scanf("%s", s[i]);
getchar();
}
Hope it helps :)
While using scanf("%[^\n]", sen) in a loop, the problem that occurs is that the \n stays within the input buffer and is not flushed. As a result next time, when the same input syntax is used, it reads the \n and considers it as a null input. A simple but effective solution to address this problem is to use:
char sen[20];
for (i=0;i<2;i++)
{
scanf("%[^\n]%*c",sen);
printf("%s\n",sen);
}
%*c gets rid of the \n character in the input buffer.
Related
I was using scanf for all my inputs in C. Now I saw other similar questions about scanf() and they suggested using fgets() instead of scanf(). I will do so in the future. However, at the moment this particular part of code with scanf() never seems to work. I know there is a solution.
My code is:
#define LENGTH 1000
#define WORD 100
int main(){
int i = 0;
char s[WORD][LENGTH];
do {
scanf("%s", s[i]);
i++;
}
while (s[i][strlen(s[i])] != EOF);
printf("%s\n", s);
return 0;
}
There should be something instead of EOF in the while loop which checks for the end of line. The final result should be an array of words in s[] and the program should print that array of words without spaces.
Unfortunately scanf() does not read the character you need to check for end of line, or at least not using "%s" as the specifier.
Instead, use the following
char line[100];
if (scanf("%99[^\n]", line) == 1) {
fprintf(stdout, "%s\n", line);
}
This way, it does not stop at white space characters, and it behaves similar to fgets(), except that it does not read the '\n' character and that might be a problem if you call it again.
I'm newcomer to C and I am stuck. I want to write simple program, which will take input from keyboard and output it if it isn't an 'exit' word. I've tried few different approaches and none of them works. Almost in all cases I get infinite output of the first input.
Here is one of my approaches:
#include <stdio.h>
int main() {
char word[80];
while (1) {
puts("Enter a string: ");
scanf("%79[^\n]", word);
if (word == "exit")
break;
printf("You have typed %s", word);
}
return 0;
}
I thought after it finish every loop it should give me prompt again, but it doesn't.
What I am doing wrong.
Please if you know give me some advice.
Thanks in advance. Really, guys I will be so happy if you help me to understand what I am doing wrong.
Oh, by the way I've noticed that when I typed some word and press 'Enter', the result string also include Enter at the end. How can I get rid of this ?
Improper string compare - use strcmp().
if (word == "exit") simply compares 2 address: the address of the first char in word and the address of the first char in string literal "exit". Code needs to compare the content beginning at those addresses: strcmp() does that.
Left-over '\n' from the previous line's Enter. Add a space to scanf() format to consume optional leading white-space. Also check scanf() results.
scanf() specifiers like "%d", "%u" and "%f" by themselves consume optional leading white-space. 3 exceptions: "%c", "%n" and "%[".
Add '\n' at end of printf() format. # Matt McNabb
#include <stdio.h>
int main() {
char word[80];
while (1) {
puts("Enter a string: ");
// v space added here
if (scanf(" %79[^\n]", word) != 1)
break; // Nothing saved into word or EOF or I/O Error
if (strcmp(word, "exit") == 0)
break;
printf("You have typed %s\n", word);
}
return 0;
}
Nice that OP used a proper width limited value of 79 in scanf()
Oh, by the way I've noticed that when I typed some word and press 'Enter', the result string also include Enter at the end. How can I get rid of this ?
This is because you don't output a newline after printf("You have typed %s", word);. The next statement executed is puts("Enter a string: "); . So you will see You have typed helloEnter a string:. To fix this, change to printf("You have typed %s\n", word);
As others have mentioned, use strcmp to compare strings in C.
Finally, the scanf format string "%79[^\n]" does not match a newline. So the input stream still contains a newline. Next time you reach this statement the newline is still in the stream , and it still doesn't match because you specifically excluded newlines.
You will need to discard that newline (and any other input on the line) before getting the next line. One way to do that is to change the input to scanf("%79[^\n]%*[^\n]", word); getchar(); That means:
Read up to 79 non-newlines
Read all the non-newline things , and don't store them
Read a character (which must be a newline now) and don't store it
Finally it would be a good idea to check the return value of scanf so that if there is an error then you can exit your program instead of going into an infinite loop.
The specifier [^\n] will abort scanf if the next character is a newline (\n), without reading the newline. Because of that, the scanf calls after the first one won't read any input.
If you want to read single words, use the %79s specifier and the following code to remove the \n at the end of your string:
if(word[strlen(word)]=='\n')
word[strlen(word)]='\0';
If you want to read whole lines, you can remove the newline from the input buffer this way:
char line[80];
int i;
while(1)
{
puts("Enter a string:");
i=-1;
scanf("%79[^\n]%n",line,&i);
//%n returns the number of characters read so far by the scanf call
//if scanf encounters a newline, it will abort and won't modify i
if(i==-1)
getchar(); //removes the newline from the input buffer
if(strcmp(line,"exit")==0)
break;
printf("You have typed %s\n",line);
}
return 0;
It is better to clear (to have a reproducible content) with memset(3) the memory buffer before reading it, and you should use strcmp(3) to compare strings. Also, consider using fflush(3) before input (even if it is not actually necessary in your case), don't forget to test result of scanf(3), also most printf(3) format control strings should end with a \n -for end-of-line with flushing- so:
#include <stdio.h>
int main() {
char word[80];
while(1) {
puts("Enter a string: ");
memset (word, 0, sizeof(word)); // not strictly necessary
fflush(stdout); // not strictly necessary
if (scanf("%79[^\n]", word)<=0) exit(EXIT_FAILURE);
if (!strcmp(word,"exit"))
break;
printf("You have typed %s\n", word);
};
return 0;
}
I would suggest reading a whole line with fgets(3) and getting rid of its ending newline (using strchr(3)). Also read about getline(3)
Don't forget to compile with all warnings and debug info (e.g. gcc -Wall -g) and learn how to use the debugger (e.g. gdb)
Your first problem is that you can't compare a string with '=='. So:
if (word == "exit")
should be
if ( strncmp( word, "exit", 4 ) == 0 )
(You could also use strncmp( word, "exit", strlen(word) ) if you know that word is zero-terminated and safe from bad values. There's a few other options also.)
Your second problem is that scanf() is not consuming the input, probably because it's not matching what you've told it to expect. Here is a good explanation of how to do what you want to do:
http://home.datacomm.ch/t_wolf/tw/c/getting_input.html
Having this piece of code:
int main(void)
{
char str[4];
do
{
if (fgets(str,sizeof(str),stdin) == NULL)
break;
printf("\n %s \n", str);
}while (strncmp(str,"q\n",sizeof("q\n")));
return 0;
}
if i type more than 4 characters, then two lines are displayed. if i type 123456 and then press enter, does input store ['1','2','\n','\0'] or ['1','2','3','\0']? hen the second time printf is reached if i only press enter key one time?. How i can avoid this behaviour? I would like type 123456 and then get:
1234
The reason why fgets is only reading partial input is because the str array is too small. You need to increase the buffer size of str array.
Also remember that fgets will pick up \n ( enter / return ) that you press after giving your input.
To get rid of the \n do this:
fgets(str,sizeof(str),stdin);
str[strlen(str)-1] = '\0';
There is one MAJOR issue with your while condition ... I am not sure what your are trying to do there but strcmp is used to see if two strings are the same or not ... what you are doing is trying to compare a string to the size of something ...
There are multiple problems in your code:
you do not include <stdio.h>.
fgets() is given a very short buffer: 4 bytes, allowing for only 3 characters to be input at a time, including the '\n'. If you type more characters, they are buffered by the terminal and the standard stream library. It will take several calls to fgets() to read them all, 3 bytes at a time.
Your termination test is bogus: strncmp(str, "q\n", sizeof("q\n")) compares the string read by fgets() with "q\n" upto a maximum number of characters of 3 because sizeof("q\n") counts the q, the \n and the null terminator. You should just use strcmp() for this test.
You print the string with printf("\n %s \n", str);. Note however that a regular line read into str will contain the trailing newline so the printf call will actually output 2 lines.
Here is a modified version:
#include <stdio.h>
#include <string.h>
int main(void) {
char str[80];
while (fgets(str, sizeof(str), stdin) != NULL) {
str[strcspn(str, "\n")] = '\0'; // strip the newline if present
printf("\n %s \n", str);
if (!strcmp(str, "q"));
break;
}
return 0;
}
Try using getc() or fgetc() before using fgets()
When you use a scanf(), you press enter key (newline) which operates as accepting the input and transferring the input from stdin (standard input device) to your program.
scanf() itself does not consume the newline pressed. So, we need something down the code which will accept this newline and prevent this newline from acting as an input to the subsequent fgets(). This newline can be accepted using getc() or fgetc(), which should be written before fgets().
fgetc(stdin); OR getc(stdin);
I am writing a decryption program and I need to scan in an unknown number of strings and decode each string as it is entered. The program must end once it reaches EOF.
I am having difficulty getting the program to end. when I scan in the first char in the string in my while loop condition statement, it is doing this but when I scan in the actual string bellow the condition statement the string is missing the first char. Should I scan in the first char and then somehow put that char at the beginning of the string?
How do I properly test for EOF in my situation?
#include <stdio.h>
#include<string.h>
int main(void)
{
int i;
char code[300];
while(scanf("%c", &code[0])!=EOF)
{
scanf("%s", code);
for(i=0; i<strlen(code); i++)
{
decrypt message one char at a time
}
printf("\n");
}
return 0;
}
while (scanf("%s", code) == 1)
{
// no need for second scanf call
...
while (scanf("%c", &code[0]) == 1)
{ scanf("%s", &code[1]);
...
Using scanf at all is a bad idea for this particular problem.
while(scanf("%c", &code[0])!=EOF)
This scanf call reads a single character. Just use getchar().
scanf("%s", code);
for(i=0; i<strlen(code); i++)
{
decrypt message one char at a time
}
The scanf call can read arbitrarily many characters (after skipping whitespace; are you sure you want to skip whitespace?). That means that if there are too many characters to be read from stdin, you have a buffer overflow, one that you can't avoid unless you have complete control over what appears on stdin.
You then loop over the code array, calling strlen() for each character you process. Since strlen() generally has to scan from the beginning of the array to the terminating '\0', this is inefficient. If you need to traverse the characters of a string, either call strlen() once and save the value, or look for the terminating '\0' character.
But you're just processing one character at a time, so just read one character at a time:
while ((c = getchar()) != EOF) {
/* process a character */
}
Don't worry about reading one character at a time being inefficient; buffering will take care of that.
i write a little code to simply read a char from the keyboard but the program fails, why? How must i read a char?
int main(int argc, char** argv)
{
char op;
do
{
printf("¿Sigues?");
scanf("%c",&op);
}while(op=='s' || op=='S');
return 0;
}
Your problem is that the %c conversion specifier doesn't cause scanf() to skip leading whitespace. You need to handle the newline character that's still in the stream after reading your input.
The input stream is empty when scanf() is called the first time through the loop, so it waits for you to type something. You type s and hit the Enter key, so the input stream contains the characters s and \n (newline). scanf() removes the s from the input stream and assigns it to op. When scanf() is called the second time, the input stream is not empty; it still has the \n character in it, so scanf() reads it and assigns it to op, which causes the loop condition to fail, so your loop exits.
There are several ways to get around this problem. I'm going to recommend reading strings as opposed to individual characters using fgets(), as follows:
char op[3] = {0}; // input character + newline character + 0 terminator
do
{
printf("¿Sigues?");
if (fgets(op, sizeof op, stdin))
{
/**
* Check for a newline character in the input. If it's not there
* then the user typed in too many characters. In order to keep
* the input stream from getting clogged up with bad input, read
* until we find a newline character.
*/
char tmp[3];
char *newline = strchr(op, '\n');
while (!newline && fgets(tmp, sizeof tmp, stdin))
{
newline = strchr(tmp, '\n');
}
}
else
{
printf("Error while reading input\n");
op[0] = 0;
}
} while (tolower(op[0]) == 's');
op = getc(stdin);
scanf flushes only after reading a newline. it cant be done in platform independent way
You're seeing the line "Sigues" twice because there's a \n still in the input stream. If you type in a character and hit enter there are now two characters in your input stream. Your scanf formatter only specifies one char, so scanf reads in one char and then advances. However, the next character in the stream is a \n, hence the exit from the loop on the second go.
NB. #eduffy's technique of getc(stdin) will do the exact same thing, there's still a \n in stdin. You need to advance past that \n somehow.
How about reading in your char, and then chomping the rest of the stream up to the \n char? I tried this and it works for me:
char op;
do
{
printf("¿Sigues?");
scanf("%c",&op);
while(getchar() != '\n') continue;
}while(op=='s'|| op=='S');