reading string with space - c

Say for example I have the following main function:
int main()
{
char a[1023];
while (scanf("%s",a) != EOF)
{
printf("%s ",a);
}
}
If I input
a ab abc(newline)
it should output:
a ab abc(newline)
but the main function output
a ab abc (newline) // there is a space between newline and the last string
I want to read the string one by one. What is the problem and how can I delete that space? Thank you.

Your printf("%s ",a); statement outputs a space after each string it outputs, regardless. You need to instead output a space only if there are going to be more strings. Equivalently (and easier), output a space before each string if it is not the first:
int first = 1;
while (scanf("%s",a) != EOF) {
if (!first) printf(" ");
printf("%s",a);
first = 0;
}
also, you never output a newline, despite describing a newline as being output...

A little note about independent learning:
The first time you use any standard library function, you should read its corresponding manual at least once. The reason is that as soon as you know about any issues (or helpful features), you'll know to avoid those issues (or use the helpful features). Reading the manual really helps you learn the full potential and avoid the pitfalls of C.
The first time you read something, you may not entirely understand it. Don't let that bother you; Just keep reading. If this happens, I suggest that you read it again once you're at the bottom of the page, and try to understand it completely the second time. Please, read the fscanf manual at least once.
That's out of the way, now. You might notice little ^ superscripts here and there. My intention is to annotate facts that you would have learnt by reading and understanding the manual I linked to above.
The format specifier %s discards as much whitespace as possible prior to attempting to consume as much non-whitespace as possible^. Suppose you were to input something with four leading bytes of whitespace, your output wouldn't have those four leading bytes of whitespace.
"This uses four spaces" translates to "This uses four spaces".
It seems logical that this violates your program specification, which extends your problem^. Perhaps you should be using the %[ format specifier, instead^. In that case, an empty line would be considered a match failure and the destination for the line would be indeterminate, so you'd need to handle the return value of scanf better^ (which I encourage you to do, anyway).
#include <stdio.h>
int main(void) {
char line[512];
int x;
do {
x = scanf("%511[^\n]", line);
if (x == 0) {
/* Match failure caused by inputting an empty line. Print empty line? */
putchar('\n');
}
else if (x == 1) {
/* Success. */
puts(line);
}
/* Read and discard the remainder of a line */
do { x = getchar(); } while (x >= 0 && x != '\n');
} while (x != EOF);
}
From the length of this loop and the simplicity of the problem, you might reason that using scanf for this is probably the wrong way to solve the problem. You can eliminate the line array, the calls to scanf and the resulting scanf error checking by using a derivation of the inner-most loop. Something like this looks nice:
#include <stdio.h>
int main(void) {
int c;
do {
c = getchar();
} while (c >= 0 && putchar(c) >= 0 && c != '\n');
}
PS. There's also a manual for getchar, putchar and many other standard things.

Related

How to fix infinite loops when user enters wrong data type in scanf()?

C beginner here. For the program below, whenever the user inputs a character or a string it enters an infinite loop. How would you fix this while still using scanf? And what would be the better methods of writing this program rather than using scanf? Thanks to those who will answer.
#include <stdio.h>
#include <ctype.h>
int main() {
int rounds = 5;
do {
printf("Preferred number of rounds per game. ENTER NUMBERS ONLY: ");
scanf("%d", &rounds);
} while(isdigit(rounds) == 0);
return 0;
}
Using 'scanf' require the input to be formatted. Scanf has very limited ability to handle bad input. The common solution will be to use fgets/sscanf, following the structure below:
char buff[256] ;
int rounds = 0 ;
while ( fgets(buff, sizeof(buff), stdin) ) {
if ( sscanf(buff, "%d", &rounds) == 1 ) {
// additional verification here
break ;
} ;
} ;
// Use rounds here ...
The fgets/sscanf will allow recovery from parsing error - the bad input line will be ignored. Depending on requirement, this might be accepted solution.
I'd say there are just two "fixes".
Retain the scanf call(s), warts and all. Carefully refrain from typing non-digits when scanf is expecting digits.
Abandon scanf and use something else. We've just been discussing this tactic over at this new question.
Once you're using scanf, it's always tempting to try to "fix" it, so there's potentially a third answer lurking here, explaining how to do better, more user-friendly, more error-tolerant input while still using scanf. In my opinion, however, this is a fool's errand, a waste of time. The easy, obvious fixes for scanf's many deficiencies are themselves imperfect and have further deficiencies. You will probably spend more time trying to fix a scanf-using program than you would have spent rewriting it to not use scanf -- and you'll get overall better results (not to mention a cleaner program) with the non-scanf-using rewrite anyway.
Change
scanf("%d", &rounds);
To
int ret;
if ((ret = scanf(" %d", &rounds)) != 1) { // Skip over white space as well
if (ret == EOF) break;
scanf("%*[^\n\r]"); // Consume the rest of the line
}
If you really like scanf, you can use getch to discard non-numeric input:
int rounds = MIN_INT;
while (scanf("%d", &rounds)) != 1)
if (getc() == EOF) /* discard a rubbish character */
break; // or other error-handling return
// rounds is only valid if we did not break, when its value should be MIN_INT.
// but you might need another indicator
C beginner here as well. Like you, I use scanf, and it can be problematic sometimes.
I've had your same problem and tried to solve it with scanf and basic stuff before finding a better solution.
I've tried different solution from here but I continue to have the same problems again and again, like if I type:
a number followed by a character (e.g. 123a), the result is a valid number (which i don't want); the result is '123'.
a string of numbers and chars that begin with a number (e.g. 1a2b3), the result is still a valid number which is '1'.
a char at the beginning (e.g. a123) can generate infinite loop.
... and so on... I've tried do...while, only while, for... nothing.
The only solution I have found to prompt the user until he/she writes only numbers is the following, but...
NOTE: if the user type a space, the program considers only the part before it, e.g. '12 3', only 12 is considered, 3 doesn't exist... unless you want use an infinite loop like I did so, in this case, you can enter multiple numbers, check them and run your program on them all at once. e.g.: '12 23 34 45' ...
NOTE 2: this is a very basic beginner solution, I am learning, and this is just what I found with what I know. Can't do any better right now and, as I said, I didn't find any other solution that I liked the output.
NOTE 3: I use the counter to sum up all the inputs that are not numbers and store the value if it finds one. If I don't use this solution I'll end up in the case where if the first character is a number but the rest aren't, it's still valid (e.g.: '12w3' is 12, which I don't want)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main (void)
{
while (1) // try also multiple inputs separated by space
{
char str[10]; // should be enough for short strings/numbers (?!)
int strlength, num, counter;
do
{
printf("Enter a number: ");
scanf("%s", str);
strlength = strlen(str);
counter = 0;
for (int i = 0; i < strlength; i++)
{
if (!isdigit(str[i]))
counter++;
}
if (counter != 0)
printf("%s is not a number.\n", str);
} while (counter != 0);
num = atoi(str);
printf("%d is a number. Well done!\n\n", num);
}
}
You can also put it in a function and away from the main().

Missing value with scanf in C89

Hope you guys can help me with a problem I'm having.
So I have this C code snippet:
int i = 0;
int q = 0;
scanf("%d %d", &i, &q);
When the user enters 4 5, the values 4 and 5 are stored in i and q respectively.
But when the user enters 99.99, 99 is stored in i, but the other 99 after the point goes missing. I do know how scanf works and I understand that scanf will stop scanning after ., but where does the second value go to?
Even if I do:
int i = 0;
int q = 0;
int k = 0;
scanf("%d %d", &i, &q);
scanf("%d", &k);
I still cant get the second value. Where does the second value go and how can I get store it in my variable?
It is trying to look for integer but it is not integer that is left in stdin so it fails.
You can get desired behavior if you do this
int a,b;
scanf("%d.%d",&a,&b);
printf("%d,%d",a,b);
This prints 99,99 as expected.
For your information,
scanf stops at the first mismatch and leaves the rest of the target objects untouched.
Also the unmatched data is left in the input buffer, available for a subsequent read using scanf etc.
Also you can check the return value to determine how many "items" scanf matched.
scanf() doesn't ignore the . while expects to read an int. I suggest you use fgets() and then try to parse with sscanf() which is a better approach. Something like:
#include <stdio.h>
int main(void)
{
int i = 0;
int q = 0;
char line[256];
if (fgets(line, sizeof line, stdin)) {
if (sscanf(line, "%d.%d", &i, &q) == 2) {
printf("i=%d, j=%d\n", i, q);
} else {
printf("Coudn't scan 2 ints\n");
}
} else {
printf("Couldn't read a line\n");
}
}
Note that fgets() will also read in the newline character if there's space in the buffer. It doesn't matter in this case.
But you need to be aware of it and may be undesirable in some cases (e.g., reading a name).
Also see: Why does everyone say not to use scanf? What should I use instead?
Let X be the following statement...
I do know how scanf works
Let Y be the following statement...
... but where does the second value go to?
X and Y do not correspond. Either you know about the return value of scanf, or you don't know how scanf works. That's the bottom line.
... but where does the second value go to?
According to the fscanf manual,
The fscanf() functions shall execute each directive of the format in turn. If a directive fails, as detailed below, the function shall return. Failures are described as input failures (due to the unavailability of input bytes) or matching failures (due to inappropriate input).
The space directive won't match the . input, which will cause a matching failure, scanf will return, meaning that nothing beyond the . byte will be consumed from stdin. In fact, scanf will even put the . back into stdin for you, just before it returns... Isn't that nice?
I gather you understand this (because you said "I do know how scanf works"), yet you seem to be asking about that second value which couldn't have been read due to a previous matching failure... thus, the answer to your first question is, the second value doesn't exist. It can't exist yet, because an input format error exists prior to it.
While we're on the topic of scanf, return values and matching failures, for the remaining question I'm going to assume your code actually looks something more like this:
int i = 0;
int q = 0;
if (scanf("%d %d", &i, &q) != 2) {
puts("Discarding invalid input");
scanf("%*[^\n]"); // discard up to the next newline and...
getchar(); // discard that newline, too.
// XXX: You might want to `return` or `continue` or something
}
... and how can I get store it in my variable?
As mentioned earlier, the space directive doesn't match the period. You need to replace that with something which manipulates the input stream as you intend... That's difficult for me to answer, because I don't have that information, but here's what I'd suggest: Split the two conversions up into two separate calls to scanf. This should give you a nice place in between the two calls to scanf to insert your period-handling code.
Here's a before & after, side-by-side, of the idiom I've adopted for that kind of input:
// BEFORE // AFTER
if (scanf("%d %d", &i, &q) != 2) { if (scanf("%d", &i) != 1) {
// ... puts("Invalid first input...");
// XXX: Handle this???
// XXX: `return` or `continue` or something
}
// XXX: Read a character, check if it's a space (or a dot, or something else which you have in your mind and I don't have in mine)
if (scanf("%d", &q) != 1) {
// ...
Handling the erroneous period could be as simple as exiting the process or calling getchar() to discard a single character, then continueing in order to try again. These solutions won't solve all user input errors, and might even confuse or frustrate some users. I recommend sticking with the discard the rest of the line method, at least until you learn about all of the alternatives for user input and what they're each best at. After all, people tend to avoid using software which confuses them...
... hence the reason people tend to discourage scanf... because I guess there's no such thing as literature which sets a standard, and thus there's no way to correct my scanf-related misunderstandings.

Reading until I manage to enter an integer

I'm pretty new in C, I used to work in Python, and I'm trying to see if something that I read is integer number. If not, to read until I manage to entry a number.
I did some research and I found out that the function scanf actually returns 1 if the read is done suitably, and 0 otherwise.
So, I have written this code, and I don't understand why this is an infinite loop, writing "Give an integer" on the console
#include <stdio.h>
int main() {
int a;
int b = 1;
do {
printf("Give an integer\n");
b = scanf("%d", &a);
} while (b == 0);
}
The problem with scanf() is that it stops reading when the first white space is encountered for most specifiers like "%d", so it's left in the input and that's why reading again would cause a problem if you don't discard such white space because it will then return immediately the next time you call it. There is a mandatory white space that is introduced when you press Enter or Return, the '\n' new line character (or line feed).
If you want to read an integer and make sure you did you can try like this
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int
main(void)
{
long int value; // You can adapt this to use `int'
// but be careful with overflow
char line[100];
while (fgets(line, sizeof(line), stdin) != NULL) {
char *endptr;
value = strtol(line, &endptr, 10);
if ((isspace(*endptr) != 0) && (endptr != line))
break;
}
fprintf(stdout, "%ld\n", value);
return 0;
}
read strtol()'s manual to understand this code
You could as suggested in the comments, remove the white space characters from the input, but IMHO that is harder and you would still have other problems with scanf(), like handing empty input which is not straight forward.
I don t understand why this is an infinite loop, writing "Give an intiger" on the console
The problem is that scanf() does not consume data that it cannot match against the specified format. It leaves such characters unread in the input stream. Therefore, if you try reading again from the same stream with the same format, without consuming at least one character by some other means, then you can be certain that the input will again not be matched. And again. And again.
To avoid your infinite loop, you need to consume at least one character of the non-matching input after each matching failure. There are many ways you could do that; here's a fairly simple one:
#include <stdio.h>
int main() {
int a;
do {
printf("Give an intiger\n");
if (scanf("%d", &a)) {
// breaks from the loop on a successful match or an error
break;
}
// consume the remainder of one line of input without storing it
if (scanf("%*[^\n]") == EOF) {
break;
}
} while (1);
}
That consumes the whole remainder of the line on which the non-matching input is encountered, which will yield less surprising interactive behavior for some inputs than many alternatives would.
If you've a penchant for writing terse code, or if you don't like to break out of the middle of a loop, then you might write the same thing like this:
#include <stdio.h>
int main() {
int a;
do {
printf("Give an intiger\n");
} while ((scanf("%d", &a) == 0) && (scanf("%*[^\n]") != EOF));
}
Because the && operator short circuits, the second scanf() call will be executed only if the first returns zero, and the loop will exit after the first iteration wherein either the first scanf() call returns nonzero or the second returns EOF (indicating an error).

C: scanf and program exit

I'm trying to learn C programming with some practical exercises.
This one for example should read 2 series of numbers (days of the month) input by the user.
The problem that I'm having is that after the first serie, that works ok, the program skips the other scanf commands and terminates.
Why?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int f = 0;
int days1[31];
int days2[31];
printf("Insert first serie \n");
while(scanf("%d",&days1[f])) {
f++;
}
// the following scanf loop is skipped
f = 0;
printf("Insert second serie \n");
while(scanf("%d",&days2[f])) {
f++;
}
}
thanks
Read documentation of scanf. It returns the number of scanned items, and you should keep and test it. It could return -1 on failure (and that is seen as a true value) then don't consume any input. Its %n conversion specifier is often useful and not enough known.
So code
while(f < 31 && scanf("%d",&days1[f])>0) f++;
But you probably need to end the first series with something which makes scanf fail, and then you need to skip that something. You should define and document a convention about that. Let's pretend that you will type a semicolon ; then you'll code perhaps:
f=0;
while(f < 31 && scanf("%d",&days1[f])>0) f++;
if (getchar() != ';') exit(EXIT_FAILURE);
f=0;
while(f < 31 && scanf("%d",&days2[f])>0) f++;
I'm not sure the above work. You might need to care about spaces or empty lines. You could read each individual line with fgets or getline and parse each line (using sscanf or strtol).
Actually, I would recommend declaring a large enough buffer char buf[256];, use fgets to read a single line containing all the number series, then parse that line using strtol in a loop and caring about the end pointer given to strtol.
You need to document the input format, at least as comments. You could use EBNF notation for that, then use standard parsing techniques.
Of course you should compile with all warnings and debug info (e.g. gcc -Wall -Wextra -g if using GCC...). Then learn to use the debugger (e.g. gdb). It is a necessary skill to have.

C while loop feof

This is part of a much bigger program to make a filmgenie and for some reason the program crashes as it reaches this while loop and i don't understand what my problem is.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
FILE *fp, *fopen();
char *arrayoffilms[45];
int main()
{
char line[100],junk[100];
fp=fopen("filmtitles.txt","r");
int i=0;
while(!feof(fp)) {
fscanf(fp,"%[^\n]s",line);
strcpy(arrayoffilms[i],line);
fscanf(fp,"%[\n]s",junk);
i++;
}
fclose(fp);
printf("%s\n\n\n",arrayoffilms[i]);
return 0;
}
feof will never return true until an actual read attempt is made, and EOF has been reached. The read attempts usually have return values that indicate failure. Why not use those, instead?
Don't confuse the %[ and %s format specifiers; %[ doesn't provide a scanset for %s; %[^\n]s tells scanf to read "one or more non-'\n' characters, followed by a 's' character". Does that make sense? Think about it, carefully. What is the purpose of this format specifier? What happens if the user merely presses enter, and scanf doesn't get it's "one or more non-'\n' characters"? Before we look for non-'\n' characters, it's important to get rid of any '\n' characters. Any whitespace bytes in the format string will cause scanf to consume as much whitespace as possible, up until the first non-whitespace character. I'm going to presume you wanted %[^\n], or perhaps even %99[^\n], which would prevent overflows of line.
Perhaps you'd also want to count the number of bytes processed by scanf, so you can malloc the correct length and copy into arrayoffilms, for some reason I can't imagine. You can use the %n format specifier, which will tell you how many bytes scanf processed.
I noticed that you want to read and discard the remainder of a line. In my example, the remainder of a line will only ever be discarded if 99 characters are read before a newline is encountered. I'll use the assignment suppression '*': %*[^\n].
Combining these format specifiers results in a format string of " %99[^\n]%n%*[^\n]", two arguments (a char * for %[ and an int * for %n), and an expected return value of 1 (because 1 input is being assigned). The loop will end when the return value isn't 1, which will likely be caused by an error such as "reading beyond eof".
int length;
while (fscanf(fp, " %99[^\n]%n%*[^\n]", line, &length) == 1) {
arrayoffilms[i] = malloc(length + 1);
strcpy(arrayoffilms[i], line);
i++;
}
The problem might be about the feof. You want your while loop to terminate when you reach the end of the file, or in other words, when you can not get anything using fscanf.
You can go for the code below:
while(fscanf(fp,"%[^\n]s",line)) {
strcpy(arrayoffilms[i],line);
fscanf(fp,"%[\n]s",junk);
i++;
}
Also, error checking associated with file pointers is absolutely necessary and is a good habbit. You would definitely want to use it:
fp=fopen("filmtitles.txt","r");
if(fp == NULL) /* error handling */
printf("Could not open file: filename\n");
else{
/* do stuff */
}
A similar thing happens with fgets() so some people say to never use it. Look at it this way, if you say
while (!feof(ipf)) {
by the time feof() is true you've hit the end of the file. The byte you just read is garbage, maybe a NULL. Don't use it. This works:
while (!feof(ipf)) {
if (!feof(ipf)) {
ch = fgetc(ipf);
And it works for fgets() too, I've used it this way for years. If this were Pascal (or maybe Perl) and you read "until" feof that would work, it's a pre-test vs a post-test issue. So test twice.

Resources