C while loop feof - c

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.

Related

Please help! I am trying to get input from a file with spaces I keep getting infinite loop. C programming

I am trying to read every word in a file and print it to the screen. I want The program to accept spaces but it gives me an infinite loop when I use this %[^\n]
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *DoThis;
DoThis = fopen("Encrypppc.txt", "r");
char word2[48];
while(!feof(DoThis)){
fscanf(DoThis,"%47[^\n]s",word2);
printf("%s\n", word2);
}
return 0;
}
Try to create a file and input spaces in the first sentence. It gives an infinite loop in the first sentence when there's space so it never reaches eof.
I found the answer I supposed to
add a space in the fscanf function.
this is what gives me the infinite loop
fscanf(DoThis,"%47[^\n]s",word2);
after I add a space before the sign % there's no infinite loop and the loop stops at EOF
fscanf(DoThis," %47[^\n]s",word2);
notice the change
You have an 's' that doesn't belong in the format string. Try this:
fscanf("%47[^\n]%*c", word2);
That will get you past the failure to read the end of file and on to the next problem. I added the %*c format to read and ignore the next character (either a \n newline or the end of file). That does (more precisely) what you accomplish with the leading space (which discards all spaces and tabs up to the next nonblank character.)
That "next problem" is the one mentioned in comment that feof() only goes true after an attempt to read past the end of file. You'll see your last line twice. The leading space in the format might work for you, but a better solution is to use the return value from fscanf() to tell you if the input read anything:
while (1)
{
int n = fscanf("%47[\n]%*c", word2);
if (n != 1) break;
...do something with word2
}
The ?scanf functions return the number of fields successfully converted and stored. There's only one such field in your format, so the return will be 1 whenever the input succeeded, or something else if it didn't. (Both 0 and EOF are possible returns, depending on the state of the file beforehand.)

C - Enter dead loop after trying to read line by line of a file and lines might contain space character?

I'm trying to read a file line by line and count the characters of each line. Those line might contains space characters and I need also to count them. I'm only allowed to use feof and scanf functions.
Sample Code
...
while(!feof(stdin)){
char inputLineArray[1000];
scanf("%[^\n]s", inputLineArray);
printf(inputLineArray);
}
...
My sample file is a txt file which contains the following content:
hello world
abcdsdsdsdsd
But after it prints:
hello world
My program is stuck into infinite loop which does nothing.
From man 3 scanf:
The scanf() family of functions scans input according to format as described below.
This means that your provided pattern %[^\n]s (don't match newlines) will stop matching after world because there is a newline. You'd need to skip to the next char in the stream.
There are many questions like yours on Stackoverflow, search for scanf infinite loop.
scanf("%[^\n]s", inputLineArray); is incorrect and inappropriate:
the conversion specifier does not have a trailing s, it is just %[^\n] ;
scanf reads the stream and stores any characters before the newline into inputLineArray and leaves the newline pending in the stream ;
scanf should be given the maximum number of characters to store to avoid undefined behavior on long lines: scanf("%999[^\n]", inputLineArray) ;
you should test the return value of scanf() to determine if the conversion was successful. The test while (!feof(stdin)) is pathologically inappropriate: Why is “while ( !feof (file) )” always wrong? ;
you would then see another problem: this conversion fails on empty lines because there are no characters to store into the destination array, and since scanf() leaves the newline pending, the second call fails and all successive ones too.
Note also that it is highly risky to call printf with user supplied data as a format string. The behavior is undefined if the line contains non trivial format specifications.
Here is a better way to read the file line by line:
#include <stdio.h>
#include <string.h>
...
char inputLineArray[1001];
while (fgets(inputLineArray, sizeof inputLineArray, stdin)) {
buf[strcspn(buf, "\n")] = '\0'; // strip the trailing newline if present
printf("%s\n", inputLineArray);
}
...
Note however that input lines with 1000 bytes or more will be broken into multiple output lines.
scanf() is not the right tool for your purpose, indeed it is full of quirks and shortcomings, but if you are required to use scanf(), here is a corrected version:
char inputLineArray[1000];
while (scanf("%c", &inputLineArray[0]) == 1) {
/* one byte was read, check if it is a newline */
if (inputLineArray[0] == '\n') {
/* empty line must be special cased */
inputLineArray[0] = '\0';
} else {
/* set the null terminator in case the next `scanf` fails */
inputLineArray[1] = '\0';
/* attempt to read the rest of the line */
scanf("%998[^\n]", inputLineArray + 1);
/* consume the pending newline, if any */
scanf("%*1[\n]");
}
printf("%s\n", inputLineArray);
}
if (feof(stdin)) {
/* scanf() failed at end of file, OK */
} else {
printf("read error\n");
}
Note that feof() is not used as scanf("%c", ...) will return EOF at end of file, so the while() loop with stop as expected.
feof() is only used to distinguish end of file from read error conditions in stream I/O. Most C programs do not need to distinguish between these as read errors can be handled the same way as truncated input files. This function is almost always used incorrectly. In short, you should never use feof(), nor other error-prone or deprecated functions such as gets() and strncpy(). Be also very careful with sprintf(), strcpy(), strcat()...

Changing the scanf() delimiter

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.

How do I return a printf statement if the user inputs nothing?

I want to execute a statement based on the input of the user:
#include <stdio.h>
#include <string.h>
void main() {
char string_input[40];
int i;
printf("Enter data ==> ");
scanf("%s", string_input);
if (string_input[0] == '\n') {
printf("ERROR - no data\n");
}
else if (strlen(string_input) > 40) {
printf("Hex equivalent is ");
}
else {
printf("Hex equivalent is ");
}
}
When I run it, and just press enter, it goes to a new line instead of saying "ERROR - no data".
What do I do?
CANNOT USE FGETS as we have not gone over this in class.
Use
char enter[1];
int chk = scanf("%39[^\n]%c", string_input, enter);
but string_input will not have a '\n' inside. Your test
if (string_input[0] == '\n') {
printf("ERROR - no data\n");
}
will have to be changed to, for example
if (chk != 2) {
printf("ERROR - bad data\n");
}
use fgets instead of scanf. scanf doesn't check if user enters a string longer than 40 chars in your example above so for your particular case fgets should be simpler(safer).
Can you use a while loop and getch, then test for the <Enter> key on each keystroke?
scanf won't return until it sees something other than whitespace. It also doesn't distinguish between newlines and other whitespace. In practice, using scanf is almost always a mistake; I suggest that you call fgets instead and then (if you need to) use sscanf on the resulting data.
If you do that, you really ought to deal with the possibility that the user enters a line longer than the buffer you pass to fgets; you can tell when this has happened because your entire buffer gets filled and the last character isn't a newline. In that situation, you should reallocate a larger buffer and fgets again onto the end of it, and repeat until either you see a newline or the buffer gets unreasonably large.
You should really be similarly careful when calling scanf or sscanf -- what if the user enters a string 100 characters long? (You can tell scanf or sscanf to accept only a limited length of string.)
On the other hand, if this is just a toy program you can just make your buffer reasonably long and hope the user doesn't do anything nasty.
fgets does what you need. Avoid using scanf or gets. If you can't use fgets try using getchar
The problem is that "%s" attempts to skip white-space, and then read a string -- and according to scanf, a new-line is "whitespace".
The obvious alternative would be to use "%c" instead of "%s". The difference between the two is that "%c" does not attempt to skip leading whitespace.
A somewhat less obvious (or less known, anyway) alternative would be to use "%[^\n]%*[\n]". This reads data until it encounters a new-line, then reads the new-line and doesn't assign it to anything.
Regardless of which conversion you use, you want (need, really) to limit the amount of input entered so it doesn't overflow the buffer you've provided, so you'd want to use "%39c" or "%39[^\n]". Note that when you're specifying the length for scanf, you need to subtract one to leave space for the NUL terminator (in contrast to fgets, for which you specify the full buffer size).
What platform are you running on?
Is the character sent when your press the ENTER key actually '\n', or might it be '\r'? Or even both one after the other (ie. "\r\n").

how to read scanf with spaces

I'm having a weird problem
i'm trying to read a string from a console with scanf()
like this
scanf("%[^\n]",string1);
but it doesnt read anything. it just skips the entire scanf.
I'm trying it in gcc compiler
Trying to use scanf to read strings with spaces can bring unnecessary problems of buffer overflow and stray newlines staying in the input buffer to be read later. gets() is often suggested as a solution to this, however,
From the manpage:
Never use gets(). Because it is
impossible to tell without knowing the
data in advance how many characters
gets() will read, and because gets()
will continue to store characters past
the end of the buffer, it is extremely
dangerous to use. It has been used to
break computer security. Use fgets()
instead.
So instead of using gets, use fgets with the STDIN stream to read strings from the keyboard
That should work fine, so something else is going wrong. As hobbs suggests, you might have a newline on the input, in which case this won't match anything. It also won't consume a newline, so if you do this in a loop, the first call will get up to the newline and then the next call will get nothing. If you want to read the newline, you need another call, or use a space in the format string to skip whitespace. Its also a good idea to check the return value of scanf to see if it actually matched any format specifiers.
Also, you probably want to specify a maximum length in order to avoid overflowing the buffer. So you want something like:
char buffer[100];
if (scanf(" %99[^\n]", buffer) == 1) {
/* read something into buffer */
This will skip (ignore) any blank lines and whitespace on the beginning of a line and read up to 99 characters of input up to and not including a newline. Trailing or embedded whitespace will not be skipped, only leading whitespace.
I'll bet your scanf call is inside a loop. I'll bet it works the first time you call it. I'll bet it only fails on the second and later times.
The first time, it will read until it reaches a newline character. The newline character will remain unread. (Odds are that the library internally does read it and calls ungetc to unread it, but that doesn't matter, because from your program's point of view the newline is unread.)
The second time, it will read until it reaches a newline character. That newline character is still waiting at the front of the line and scanf will read all 0 of the characters that are waiting ahead of it.
The third time ... the same.
You probably want this:
if (scanf("%99[^\n]%*c", buffer) == 1) {
Edit: I accidentally copied and pasted from another answer instead of from the question, before inserting the %*c as intended. This resulting line of code will behave strangely if you have a line of input longer than 100 bytes, because the %*c will eat an ordinary byte instead of the newline.
However, notice how dangerous it would be to do this:
scanf("%[^n]%*c", string1);
because there, if you have a line of input longer than your buffer, the input will walk all over your other variables and stack and everything. This is called buffer overflow (even if the overflow goes onto the stack).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *text(int n);
int main()
{
char str[10];
printf("enter username : ");
scanf(text(9),str);
printf("username = %s",str);
return 0;
}
char *text(int n)
{
fflush(stdin);fflush(stdout);
char str[50]="%",buf[50],st2[10]="[^\n]s";
char *s;itoa(n,buf,10);
// n == -1 no buffer protection
if(n != -1) strcat(str,buf);
strcat(str,st2);s=strdup(str);
fflush(stdin);fflush(stdout);
return s;
}

Resources