scanf three times in c doesn`t work? - c

Hello I have a homework from school to make a program that finds a word and replaces it with another in a text. I havent done char string until now and I have a little problem. I need to scan the Text, the find word and the replace word, but only the text scanf work and the other are just skipping..
char w[10000];
char find[10000];
char replace[10000];
int l,c,b,diff,i,k,yes=0,vm;
printf("Text: ");scanf("%[^\n]s",w);
printf("\nFind: ");scanf("%[^\n]s", find);
printf("\nReplace: ");scanf("%[^\n]s", replace);
If you can say why the scanf for find and replace just skips I will be very thankful.
Sorry for bad English not my native language.

Try this
printf("Text: ");scanf("%[^\n]%*c",w);
printf("\nFind: ");scanf("%[^\n]%*c", find);
printf("\nReplace: ");scanf("%[^\n]%*c", replace);
Just consume the newline character and get rid of s after [^\n] which says
Read till newline character is encountered
I would suggest you to use
fgets(w,sizeof(w),stdin);
which is much safer.

scanf("%[^\n]s",w); has multiple problems:
There is no need for s. "%[^\n]" is a complete format specifier. #unwind
There is no input limit. Could use to cope with limits: char w[10000]; scanf("%9999[^\n]", w);
The format does not consume anything is user enters Enter. w remains uninitialized and '\n' remains in stdin for the next scanf() which does the same thing.
// NOT recommended
scanf("%[^\n]%*c", w); This gets stuck on \n only input
Nothing in scanf("%[^\n]",w); consumes the typical trailing '\n'. Code could use the following which also checks the scanf() result.
if (scanf("%9999[^\n]", w) != 1) Handle_EOForEOLonlyInput();
fgetc(stdin);
Suggest instead fgets()
char w[10000];
if (fgets(w, sizeof w, stdin) == NULL) Handle_EOForIOError();
// strip possible ending EOL if needed.
w[strcspn(w, "\n")] = 0;

This should work, since scanf should skip leading whitespace, including newlines.
char w[10000];
char find[10000];
char replace[10000];
/* ... */
printf("Text: ");scanf("%s",w);
printf("\nFind: ");scanf("%s", find);
printf("\nReplace: ");scanf("%s", replace);

Related

What is the use of scanf("\n"); statement before scanf("%[^\n]%*c", s)?

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.

What does scanf("%[^\n]%*c", &s); actually do?

I know for a fact that [^\n] is a delimiter that makes scanf to scan everything until "enter" key is hit. But I don't know what the remainder of "%[^\n]%*c" is used for. Also why do we have to mention "&s" instead of "s" in the scanf function.
I tried running this:
char s[100];
scanf("%[^\n]s",s);
scanf("%[^\n]s",&s);
Both the above scanf statements worked exactly the same for me. If there is any difference between them, What is it?
Also Why should I prefer scanf("%[^\n]%*c", &s); to the above declarations?
scanf("%[^\n]s",&s); has many troubles:
No check of return value.
No overrun protection
No consumption of '\n'
No assignment of s on '\n' only
No need for s in "%[^\n]s"
Wrong type &s with format.
scanf("%[^\n]s",s); only has one less problem (last one).
Use fgets(s, sizeof s, stdin)
if (fgets(s, sizeof s, stdin)) {
s[strcspn(s, "\n")] = 0; // Lop off potential ending \n
// Success
} else {
// failure
}
No check of return value.
Without checking the return value, success of reading is unknown and the state of s indeterminate.
No overrun protection
What happens when the 100th character is inputted? - "Very bad. Not good. Not good." Necron 99, Wizards 1977
No consumption of '\n'
'\n' remains in stdin to foul up the next read.
No assignment of s on '\n' only
If the input begin with '\n', scanf() returns and s unchanged. It is not assigned "".
No need for "s" in "%[^\n]s"
The "s" is not part of the specifier "%[^\n]". Drop it.
Wrong type &s with format.
%[...] matches a char *, not a pointer to a char[100] like &s (UB).
You can take a string as input in C using scanf(“%s”, s). But, it accepts string only until it finds the first space.
In order to take a line as input, you can use scanf("%[^\n]%*c", s); where s is defined as char s[MAX_LEN] where MAX_LEN is the maximum size of s . Here, [] is the scanset character. ^\n stands for taking input until a newline isn't encountered. Then, with this %*c, it reads the newline character and here, the used * indicates that this newline character is discarded.
Note: After inputting the character and the string, inputting the sentence by the above mentioned statement won't work. This is because, at the end of each line, a new line character (\n) is present. So, the statement: scanf("%[^\n]%*c", s); will not work because the last statement will read a newline character from the previous line. This can be handled in a variety of ways and one of them being: scanf("\n"); before the last statement.

Don't understand how to input/print and compare string in loop in C

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

how does fgets internally works?

Well it is a basic question but I seem confused enough.
#include<stdio.h>
int main()
{
char a[100];
printf("Enter a string\n");
scanf("%s",a);
}
Basically the above is what I want to achieve.
If I enter a string
James Bond
then I want that to be stored in array a.
But the problem is because of presence of a blank space in between only James word is stored.
So how can I solve this one.
UPDATE
After the replies given below I understand fgets() would be a better choice. I want to know internal working of fgets as why is it able to store the string with space where as scanf is not able to do the same.
Is this what you need?
freeBSD: http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/stdio/fgets.c?rev=1.14.14.1;content-type=text%2Fplain
open implementation: https://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=7425&lngWId=3
OWP(dead) http://www.koders.com/c/fid042417FA231704B84308A66E1B82EADEDAB22051.aspx
ReactOS http://www.koders.com/c/fidEB3507945463053CEFCD518EA0CDFF9EB78E24C9.aspx?s=fgets.c#L1
All implementations scans the input file(or stream) until it reaches \n or EOF, or the maxSize param is hit...
scanf reads up until the first whitespace character. The solution is to use fgets, if memory serves me correctly, in your instance it'd be:
fgets(a, 100, STDIN);
It will read up to 100 characters (or the first \n) from standard input and store it in a.
Do not use the gets function ever, even if it looks easier.
Usually scanf breaks the input at whitespace (space, tab, newline, ...).
For example, the input " 5 42 -100" is accepted with scanf("%d%d%d") because each %d strips the leading whitespace. The same behaviour happens with %s.
The only conversion specifiers where the ignoring of leading whitespace doesn't happen are %%, %[ and %c (and, for different reasons, %n)
char input[] = " hello world";
char buf[100];
sscanf(input, "%8c", buf); /* buf contains " hello w" */
sscanf(input, "%8[^o]", buf); /* buf contains " hell" */
The fgets function reads as many characters as there are, up to the nest line break.
I use The Open Group Base Specifications Issue 7 for online documentation
You should use gets(a)/fgets(a, sizeof(a), stdin) instead of sscanf().
Try fgets():
char a[100];
printf("Enter a string\n");
fgets(a, sizeof(a), STDIN);
To learn more about STDIN, check this.

What's the better way to read a char?

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');

Resources