When I run the program the last data in the file gets displayed twice.
#include<stdio.h>?//heder
#include<conio.h>//header
int main(){//main
int cn,clas;//variable declaration
char fn[15],ln[15],pn[10],adds[15];//variable declaration
float mr;//variable declaration
int i=1;//variable declaration
FILE *fp;//file pointer declaration
fp=fopen("student.txt","r");// opening a file
if (fopen("student.txt","r") == NULL) {
printf("Error: file pointer is null.");
return 0;
}
while(! feof(fp) ){//here the program reads the data from file
fscanf(fp,"%d",&cn);
fscanf(fp,"%s",&fn);
fscanf(fp,"%s",&ln);
fscanf(fp,"%d",&clas);
fscanf(fp,"%s",&adds);
fscanf(fp,"%s",&pn);
fscanf(fp,"%f",&mr);
//from here the data is printed on output string
printf("%d",cn);printf("\n");
printf("%s",fn);printf("\n");
printf("%s",ln);printf("\n");
printf("%d",clas);printf("\n");
printf("%s",adds);printf("\n");
printf("%s",pn);printf("\n");
printf("%f",mr);printf("\n");
printf("\n");
printf("\n");
}
}
the file i acessed is this
this is the file that i accesed
and the output that the program gives is this
the last one gets repeated
this is output
please help me with this
Normally, this is only worthy of a comment, but in this case it is precisely the root cause of your problem. You are using feof incorrectly. feof does not return true until after a read has failed. So your program reads the last line, then goes to the top of the loop when feof returns false. Then the first scanf fails (and all of them fail), then the printf's are executed with the data that is still available from the previous iteration of the loop, then feof returns true and the loop is terminated. You must check the return value of each scanf and break out of the loop if any of them fail to read data. Or, better yet, avoid scanf, use fread and parse the buffer.
Related
I just started learning files in c few days ago. In order to understand how to manipulate correctly the functions, I wrote a code who create a new file (w+) read a string and using fputs() put it in the file. Using a function it find how many characters are there. the problem is if I don't rewind before calling the function, the output returned is very large compared to the string the output+string is exactly 4096 every time no matter how big the array. I don't understand why it should just return 0 if I don't rewind the pointer, and why it doesn't return 4096 when I rewind it, instead it returns the correct answer. Here is my code:
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int daft(FILE* f){
int s=0,c;
while((c=fgetc(f))!=EOF){
if(!isspace(c))
s++;
}
return s;
}
int main(){
char *ch;
ch=malloc(20*sizeof(char));
FILE *f;
f=fopen("test.txt","w+");
if(f!=NULL){
gets(ch);
fputs(ch,f);
printf("n= %d\n",daft(f));
fclose(f);
}
free(ch);
return 0;
}
You need to flush the stream after writing and before reading:
7.21.5.3 The fopen function
...
7 When a file is opened with update mode ('+' as the second or third character in the
above list of mode argument values), both input and output may be performed on the
associated stream. However, output shall not be directly followed by input without an
intervening call to the fflush function or to a file positioning function (fseek,
fsetpos, or rewind), and input shall not be directly followed by output without an
intervening call to a file positioning function, unless the input operation encounters end-of-file. Opening (or creating) a text file with update mode may instead open (or create) a
binary stream in some implementations.
C 2011 Online Draft
Emphasis added. By not flushing after writing and by not rewinding, the stream is not in a good state to be read from. You've entered the realm of undefined behavior - fgetc returns something that's not EOF for many iterations, and as a result s is incremented to a very large value.
This is why it worked when you used the rewind function, because you reset the stream to be in a good state for reading.
EOF is not necessarily stored in the file. Usually, files does not. It is what the function returns when it fails to read.
Also, never use gets()
I just read in a string using the following statement:
fgets(string, 100, file);
This string that was just read in was the last line. If I call feof() now will it return TRUE? Is it the same as calling feof() right at the start before reading in any lines?
No, don't use feof() to detect the end of the file. Instead check for a read failure, for example fgets() will return NULL if it attempts to read past the end of the file whereas feof() will return 0 until some function attempts to read past the end of the file, only after that it returns non-zero.
Does feof() work when called after reading in last line?
No.
feof() becomes true when reading past the end of data. Reading the last line may not be pass the end of data if the last line ended in '\n'.
The short answer is NO. Here is why:
If fgets successfully read the '\n' at the end of the line, the end-of-file indicator in the FILE structure has not been set. Hence feof() will return 0, just like it should before reading anything, even on an empty file.
feof() can only be used to distinguish between end-of-file and read-error conditions after an input operation failed. Similarly, ferr() can be used to check for read-error after an input operation failed.
Programmers usually ignore the difference between end-of-file and read-error. Hence they only rely on checking if the input operation succeeded or failed. Thus they never use feof(), and so should you.
The behavior is somewhat similar as that of errno: errno is set by some library functions in case of error or failure. It is not reset to 0 upon success. Checking errno after a function call is only meaningful if the operation failed and if errno was cleared to 0 before the function call.
If you want to check if you indeed reached to the of file, you need to try and read extra input. For example you can use this function:
int is_at_end_of_file(FILE *f) {
int c = getc(file);
if (c == EOF) {
return 1;
} else {
ungetc(c, file);
return 0;
}
}
But reading extra input might not be worthwhile if reading from the console: it will require for the user to type extra input that will be kept in the input stream. If reading from a pipe or a device, the side effect might be even more problematic. Alas, there is no portable way to test if a FILE stream is associated with an actual file.
I have a small program I'm writing to practice programming in C.
I want it to use the getchar(); function to get input from the user.
I use the following function to prompt for user input, then loop using getchar() to store input in an array:
The function is passed a pointer referencing a struct's member.
getInput(p->firstName); //The function is passed an argument like this one
void getInput(char * array)
{
int c;
while((c=getchar()) != '\n')
*array++ = c;
*array = '\0'; //Null terminate
}
This function is called multiple times, as it is a part of a function that creates a structure, and populates it's array members.
However when the program executes, The first two calls to it work fine, but any subsequent calls to this function will cause every-other call to getchar() to not wait for keyboard input.
After some debugging I traced the bug to be that getchar(); was for some reason reading in the '\n' character instead of waiting for input, the while loop test fails, and the function returns essentially an empty string.
I have done some research and keep finding to use
while(getchar() != '\n');
at the end of the function in order to properly flush stdin, however, this produces undesirable results, as the program will prompt again for more input after I type ENTER. Pressing ENTER again continues the program, but every-other subsequent calls continue to read in this mysterious '\n' character right off the bat, causing the test to fail, and resulting in empty strings whenever it comes time to print the contents of the the structure.
Could anyone explain to me what is going on here? Why does getchar() keep fetching a '\n' even though I supposedly cleared the input buffer? I have tried just placing a getchar(); statement at the beginning and end of the function, tried 'do while' loops, and taken other jabs at it, but I can't seem to figure this out.
The code you have written has several drawbacks. I'll try to explain them as it is unclear where your code is failing (probably outside the function you posted)
First of all, you don't check for EOF in getchar() result value. getchar(3) doesn't return a char precisely to allow to return al possible char values plus an extra one, EOF, to mark the end of file (this can be generated from a terminal by input of Ctrl-D in unix, or Ctrl-Z on windows machines) That case must be explicitly contempled in your code, as you'll convert the result to a char and will lose the extra information you received from the function. Read getchar(3) man page to solve this issue.
Second, you don't check for input of enough characters to fill all the array and overflow it. To the function you pass only a pointer to the beginning of the array, but nothing indicates how far it extends, so you can be overfilling past the end of its bounds, just overwritting memory that was not reserved for input purposes. This normally results in something called U.B. in the literature (Undefined Behaviour) and is something you must care of. This can be solved by passing a counter of valid positions to fill in the array and decrementing it for each valid position filled. And not allowing more input once the buffer has filled up.
On other side, you have a standar function that does exactly that, fgets(3) just reads one string array from an input file, and stores it on the pointer (and size) you pass to it:
char *fgets(char *buffer, size_t buffer_size, FILE *file_descriptor);
You can use it as in:
char buffer[80], *line;
...
while (line = fgets(buffer, sizeof buffer, stdin)) {
/* process one full line of input, with the final \n included */
....
}
/* on EOF, fgets(3) returns NULL, so we shall be here after reading the
* full input file */
Say I make an input :
"Hello world" // hit a new line
"Goodbye world" // second input
How could I scan through the two lines and input them separately in two different arrays. I believe I need to use getchar until it hits a '\n'. But how do I scan for the second input.
Thanks in advance. I am a beginner in C so please It'd be helpful to do it without pointers as I haven't covered that topic.
Try this code out :
#include<stdio.h>
int main(void)
{
int flx=0,fly=0;
char a,b[10][100];
while(1)
{
a=getchar();
if(a==EOF) exit(0);
else if(a=='\n')
{
flx++;
fly=0;
}
else
{
b[flx][fly++]=a;
}
}
}
Here I use a two dimensional array to store the strings.I read the input character by character.First i create an infinite loop which continues reading characters.If the user enters the end of File character the input stops. If there is a newline character then flx variable is incremented and the next characters are stored in the next array position.You can refer to the strings stored with b[n] where n is the index.
The function that you should probably look at is fgets. At least on my system, the definition is as follows:
char *fgets(char * restrict str, int size, FILE * restrict stream);
So a very simple program to read input from the keyboard would run something like this:
#include <stdio.h>
#include <stdlib.h>
#define MAXSTRINGSIZE 128
int main(void)
{
char array[2][MAXSTRINGSIZE];
int i;
void *result;
for (i = 0; i < 2; i++)
{
printf("Input String %d: ", i);
result = fgets(&array[i][0], MAXSTRINGSIZE, stdin);
if (result == NULL) exit(1);
}
printf("String 1: %s\nString 2: %s\n", &array[0][0], &array[1][0]);
exit(0);
}
That compiles and runs correctly on my system. The only issue with fgets though is that is retains the newline character \n in the string. So if you don't want that, you will need to remove it. As for the *FILE parameter, stdin is a predefined *FILE structure that indicates standard input, or file descriptor 0. There are also stdout for standard output (file descriptor 1) and a stderr for error messages and diagnostics (file descriptor 2). The file descriptor numbers correspond to the ones used in a shell like so:
$$$-> cat somefile > someotherfile 2>&1
What that does is take outfile of file descriptor 2 and redirect it to 1 with 1 in turn being redirected to a file. In addition, I am using the & operator because we are addressing parts of an array, and the functions in question (fgets, printf) require pointers. As for the result, the man page for gets and fgets states the following:
RETURN VALUES
Upon successful completion, fgets() and gets() return a pointer to the string. If end-of-file occurs before any characters are read,
they return NULL and the buffer contents remain unchanged. If an
error occurs, they return NULL and the buffer contents are
indeterminate. The fgets() and gets() functions do not distinguish
between end-of-file and error, and callers must use feof(3) and
ferror(3) to determine which occurred.
So to make your code more robust, if you get a NULL result, you need to check for errors using ferror or end of file using feof and respond approperiately. Furthermore, never EVER use gets. The only way that you can use it securely is that you have to have the ability to see into the future, which clearly nobody can do so it cannot be used securely. It will just open you up for a buffer overflow attack.
I am trying to read a file given in following format
hello
{
1--2
2--3
3--4
}
I only want to use integers given in the file and to do that i am using the following code
while(fscanf(fp, "%d--%d", &a, &b) != EOF)
{ // do something here}
The problem is that this is not working because it goes in to an infinite loop after reading first line and if i remove first line it goes to an infinite loop at the last line where it read } . So,how can do this in a proper way?
If all else fails, RTFM:
fscanf: "This function return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure."
Meanwhile, EOF=-1 although in some stdio.h header files on some platforms it could be equal to zero.
You could either check that fscanf returns 0 or use feof(fp) to check that the end of file has been reached.