The output is correct when fgets() in included in the while loop, but taking it outside makes it an infinite loop. Can anyone explain why?
main()
{
FILE *fp=fopen("myfile.txt","r");
char s[100];
fgets(s,50,fp);
while(s!=NULL) //infinte loop
puts(s);
/* while((fgets(s,100,fp))!=NULL)
puts(s);
This runs fine */
fclose(fp);
}
s!=NULL compares the address of the array s against NULL, which will never match.
while(fgets(s,100,fp))!=NULL) compares the return of fgets() with NULL, which is NULL on EOF or error.
Search for:
man page fgets
Code 1
main()
{
FILE *fp = NULL;
FILE *fp=fopen("myfile.txt","r");
if(!fp)
{
/*error occured during fopen()! abort*/
printf("Error while openning the file!\n");
return 1;
}
char s[100];
fgets(s,50,fp); /*1*/
while(s != NULL) /*2*/
{
puts(s); /*3*/
}
fclose(fp);
}
Code 2
main()
{
FILE *fp=fopen("myfile.txt","r");
char s[100];
while((fgets(s,100,fp)) != NULL) /*1*/
{
puts(s); /*2*/
}
fclose(fp);
}
In Code 1, when you reach point /*1*/ your buffer s in not empty and contain some string (its not null). so you are entering the while loop with s!=null then in /*3*/ you are printing this in the stdoutput and return to point /*2*/ to ask if s != null and getting again the same answer that s is not null. hence you are stuck in this infinite loop forever.
In Code 2, In point /*1*/ you are redaing a line from the input stream and ask if its not null. fgets() Upon successful completion, fgets() shall return s. If the stream is at end-of-file, the end-of-file indicator for the stream shall be set and fgets() shall return a null pointer. If a read error occurs, the error indicator for the stream shall be set, fgets() shall return a null pointer, and shall set errno to indicate the error. In some point you will reach the eof and fgets() will return null and then you will exit the loop. for further reading please refer to man pages in the link
the following proposed code:
cleanly compiles
performs the desired functionality
properly checks for (and handles) errors from fopen() and from fgets()
Eliminates the use of 'magic' numbers
includes the needed header files
contains a valid signature for main()
passes the proper parameters to fgets()
includes a final call to puts() to assure the output stream buffer is flushed to the terminal
incorporates my comments to the OPs question
and now, the proposed code:
#include <stdio.h>
#include <stdlib.h>
#define BUF_LEN 100
int main( void )
{
FILE *fp = fopen( "myfile.txt", "r" );
if( ! fp )
{
perror( "fopen to read file: myfile.txt failed" );
exit( EXIT_FAILURE );
}
char s[ BUF_LEN ];
while( fgets( s, sizeof(s), fp ) )
{
puts( s );
}
puts( "" );
fclose( fp );
}
Related
I am writing a text file parser in C.
I would like to read each line of a text file using fgets, except for the very last line, which I would like to skip.
Also, there is no telling how many characters will be in the file or in the last line, but assume my parser only cares about the first LINEMAXLEN characters in each line.
Currently, the only way I can think to do this is by running two loops, something like the following:
char line[ LINEMAXLEN+1u ];
unsigned int nlines;
unsigned int i;
nlines = 0u;
while ( fgets (line, LINEMAXLEN, file) != NULL )
nlines += 1u;
i = 0u;
while ( fgets (line, LINEMAXLEN, file) != NULL ) {
if ( i >= nlines - 1u )
break;
//...parse the line
i += 1u;
}
But surely, there's got to be a smarter way to do it in only one loop, no?
Instead of using two loops, it would be more efficient to always read two lines in advance and to only process a line once the next line has been sucessfully read. That way, the last line will not be processed.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define LINEMAXLEN 30
//forward function declarations
void process_line( const char *line );
bool read_start_of_line_and_discard_rest( char buffer[], int buffer_size, FILE *fp );
int main( void )
{
FILE *fp;
char lines[2][LINEMAXLEN];
//This index specifies which index in the array "lines"
//represents the newest line. The other index is the
//index of the previous line.
int newest_index = 0;
//attempt to open file
fp = fopen( "input.txt", "r" );
if ( fp == NULL )
{
fprintf( stderr, "Error opening file!\n" );
exit( EXIT_FAILURE );
}
//read first line
if ( !read_start_of_line_and_discard_rest( lines[newest_index], LINEMAXLEN, fp ) )
{
fprintf( stderr, "Error reading first line!\n" );
exit( EXIT_FAILURE );
}
//process one line per loop iteration
for (;;)
{
//swap the index, so that the newest line is now the
//previous line
newest_index = !newest_index;
//read the new line
if ( !read_start_of_line_and_discard_rest( lines[newest_index], LINEMAXLEN, fp ) )
{
//we have reached end-of-file, so we don't process the
//previous line, because that line is the last line
break;
}
//since reading in a new line succeeded, we can be sure that
//the previous line is not the last line, so we can process
//the previous line
//process the previous line
process_line( lines[!newest_index] );
}
//cleanup
fclose( fp );
}
//This function will process a line after it has been read
//from the input file. For now, it will only print it.
void process_line( const char *line )
{
printf( "Processing line: %s\n", line );
}
//This function will read exactly one line of input and remove the
//newline character, if it exists. On success, it will return true.
//If this function is unable to read any further lines due to
//end-of-file, it returns false. If it fails for any other reason, it
//will not return, but will print an error message and call "exit"
//instead.
//If the line is too long to fit in the buffer, it will discard
//the rest of the line and report success.
bool read_start_of_line_and_discard_rest( char buffer[], int buffer_size, FILE *fp )
{
char *p;
//attempt to read one line from the stream
if ( fgets( buffer, buffer_size, fp ) == NULL )
{
if ( ferror( fp ) )
{
fprintf( stderr, "Input error!\n" );
exit( EXIT_FAILURE );
}
return false;
}
//determine whether line was too long for input buffer
p = strchr( buffer, '\n' );
if ( p == NULL )
{
int c;
//discard remainder of line
do
{
c = getchar();
} while ( c != EOF && c != '\n' );
}
else
{
//remove newline character by overwriting it with a null
//character
*p = '\0';
}
return true;
}
For the input
This is line1.
This is line2 which has an additional length longer than 30 characters.
This is line3.
This is line4.
this program has the following output:
Processing line: This is line1.
Processing line: This is line2 which has an ad
Processing line: This is line3.
As you can see, all lines except the last line are being processed, and only the first LINEMAXLEN-1 (30-1 in my example) characters of each line are being processed/stored. The remaining characters are being discarded.
Only LINEMAXLEN-1 instead of LINEMAXLEN characters from each line are being processed/stored because one character is required to store the terminating null character.
This is quite simple to do in a single loop if we use alternating buffers [as others have mentioned].
In the loop below we read a line into the "current" buffer. If not the first line, we process the previous line in the "other" buffer.
By alternating the index into a buffer pool of two buffers, we avoid unnecessary copying.
This introduces a delay in the processing of the buffer. On the last iteration, the last line will be in the current buffer, but it will not be processed.
#define LINEMAXLEN 1000 // line length of buffer
#define NBUF 2 // number of buffers
char lines[NBUF][LINEMAXLEN]; // buffer pool
int previdx = -1; // index of bufs for _previous_ line
int curidx = 0; // index of bufs for _current_ line
char *buf; // pointer to line buffer to process
// read all lines into alternating line buffers
for (; fgets(lines[curidx],LINEMAXLEN,stdin) != NULL;
previdx = curidx, curidx = (curidx + 1) % NBUF) {
// process _previous_ line ...
if (previdx >= 0) {
buf = lines[previdx];
// process line ...
}
}
fgets() will not modify the buffer at all when it reaches EOF, so just read lines until fgets() returns NULL. The last line read will be retained:
#include <stdio.h>
int main( int argc, char **argv )
{
char line[ 1024 ];
FILE *f = fopen( argv[ 1 ], "r" );
if ( NULL == f )
{
return( 1 );
}
for ( ;; )
{
char *p = fgets( line, sizeof( line ), f );
if ( NULL == p )
{
break;
}
}
printf( "last line: %s\n", line );
return( 0 );
}
This relies on the required behavior of fgets():
The fgets function returns s if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned.
Robust code should check for errors with ferror().
Working that into your text processing is left as an exercise... ;-)
there is very long "dict.txt" file.
the size of this file is about 2400273(calculated by fseek, SEEK_END)
this file has lots of char like this 'apple = 사과'(simillar to dictionary)
Main problem is that reading file takes very long time
I couldn't find any solution to solve this problem in GOOGLE
The reason i guessed is associated with using fgets() but i don't know exactly.
please help me
here is my code written by C
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int line = 0;
char txt_str[50];
FILE* pFile;
pFile = fopen("dict_test.txt", "r");
if (pFile == NULL) {
printf("file doesn't exist or there is problem to open your file\n");
}
else {
do{
fgets(txt_str, 50, pFile);;
line++;
} while (txt_str != EOF);
}
printf("%d", line);
}
Output
couldn't see result because program was continuosly running
Expected
the number of lines of this txt file
Major
OP's code fail to test the return value of fgets(). Code needs to check the return value of fgets() to know when to stop. #A4L
do{
fgets(txt_str, 50, pFile);; // fgets() return value not used.
Other
Line count should not get incremented when fgets() returns NULL.
Line count should not get incremented when fgets() read a partial line. (I. e.) the line was 50 or longer. Reasonable to use a wider than 50 buffer.
Line count may exceed INT_MAX. There is always some upper bound, yet trivial to use a wider type.
Good practice to close the stream.
Another approach to count lines would use fread() to read chunks of memory and then look for start of lines. (Not shown)
Recommend to print a '\n' after the line count.
int main(void) {
FILE* pFile = fopen("dict_test.txt", "r");
if (pFile == NULL) {
printf("File doesn't exist or there is problem to open your file.\n");
return EXIT_FAILURE;
}
unsigned long long line = 0;
char txt_str[4096];
while (fgets(txt_str, sizeof txt_str, pFile)) {
if (strlen(txt_str) == sizeof txt_str - 1) { // Buffer full?
if (txt_str[sizeof txt_str - 1] != '\n') { // Last not \n?
continue;
}
}
line++;
}
fclose(pFile);
printf("%llu\n", line);
}
fgets returns NULL on EOF.
You are never assigning the result of
fgets(txt_str, 50, pFile);
to txt_str, your program never sees the end of the file and thus enters an endless loop.
try something like this:
char* p_str;
do{
p_str = fgets(txt_str, 50, pFile);
} while (p_str != NULL);
I'm having some problems with this little function that can read a file:
void ReadFile(char *name) {
FILE *fr;
int lenght, i;
fr = fopen(name, "r"); //Open the file reader
fseek(fr, 0, 2); //Set the pointer at the EOF
lenght = ftell(fr); //Read the ending position
printf("\nDEBUG lenght:%d\n", lenght);
fseek(fr, 0, 0); //Return at the beginning of the file
printf("File read:\n\n");
for (i = 1; i <= lenght; i++) {
printf("%c", getc(fr));
fseek(fr, i, 0);
}
fclose(fr);
}
This is the file that it reads:
qwerty
asdfgh
zxcvbn
But this is the output of the program:
DEBUG lenght:24
File read:
qwerty
asdfgh
zxcvbn
It is basically reading an extra "\n" when there is one before.
Any ideas of why the code doesn't work?
Thanks
If you open a file in text mode (as you do), then a call to fseek may only contain offset values that have been previously retrieved by an ftell function (cf, for example, cppreference/fseek):
If the stream is open in text mode, the only supported values for
offset are zero (which works with any origin) and a value returned by
an earlier call to ftell on a stream associated with the same file
(which only works with origin of SEEK_SET).
In your for-loop, however, you are passing the value of i, which is not retrieved by ftell.
Besides that, your fseek in the loop is superflous, as fgetc moves the read pointer forward anyway. So for (i = 1; i <= lenght; i++) { printf("%c", getc(fr)); } should do the job.
the following proposed code:
cleanly compiles
performs the desired functionality
properly checks for errors
and now, the proposed code:
#include <stdio.h> // EOF, fopen(), getc(), putc() fclose() puts() perror()
#include <stdlib.h> // exit(), EXIT_FAILURE
// prototype
void ReadFile(char *filename);
void ReadFile(char *filename)
{
FILE *fp = fopen( filename, "r" );
if( !fp )
{
perror( "fopen failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
puts("File read:\n");
int ch;
while( (ch = getc( fp )) != EOF )
{
putchar( ch );
}
fclose(fp);
}
I am writing a program that takes strings from two files and combines them to make a third file with the combined string.
#define BUF 255
int main( void)
{
FILE *usernames; FILE *passwords; FILE *final_file;
char *user_str, *pass_str;
int ct, ck;
usernames = fopen( ".\\info_files\\usernames.txt", "r" );
passwords = fopen( ".\\info_files\\passwords.txt", "r" );
final_file = fopen( ".\\info_files\\usernamesPasswords.txt", "w" );
if ( (usernames == NULL) || (passwords == NULL) || (final_file == NULL)
)
{
printf( "failed to open one of the files" );
}
while ( (fgets( user_str, BUF, usernames) != EOF ) && ( fgets( pass_str, BUF, passwords) != EOF))
{
fprintf( final_file, "%-25s %s\n", user_str, pass_str );
}
fclose( usernames );
fclose( passwords );
fclose( final_file );
return 0;
}
This is what's giving me trouble. I have no idea what is causing this to crash.
This is edited from what was first posted.
#BLUEPIXY has given you the correct code - Here's the explanation of where you went wrong in your code:-
char *fgets(char *str, int n, FILE *stream)
reads a line from the specified stream and stores it into the string pointed to by str. It stops when either (n-1) characters are read, the newline character is read, or the end-of-file is reached, whichever comes first.
Retun value of fgets
On success: the function returns the same str parameter
If the End-of-File is encountered and no characters have been read,
the contents of str remain unchanged and a null pointer is returned
If an error occurs, a null pointer is returned.
Source:- C Tutorial Point
So I have the txt file from which I need to read the number of students written in that file, and because every student is in separate line, it means that I need to read the number of lines in that document. So I need to:
Print all lines from that document
Write the number of lines from that document.
So, I write this:
#include "stdafx.h"
#include <stdio.h>
int _tmain(int argc, _TCHAR* Argo[]){
FILE *student;
char brst[255];
student = fopen("student.txt", "r");
while(what kind of condition to put here?)
{
fgetc(brst, 255, (FILE*)student);
printf("%s\n", brst);
}
return 0;
}
Ok, I understand that I can use the same loop for printing and calculating the number of lines, but I can't find any working rule to end the loop. Every rule I tried caused an endless loop. I tried brst != EOF, brst != \0. So, it works fine and print all elements of the document fine, and then it start printing the last line of document without end. So any suggestions? I need to do this homework in C language, and I am using VS 2012 C++ compiler.
OP's code is close but needs to use fgets() rather than fgetc() and use the return value of fgets() to detect when to quit, it will be NULL #Weather Vane. Also add a line counter.
#include <stdio.h>
int main(void) {
FILE *student = fopen("student.txt", "r");
unsigned line_count = 0;
if (student) {
char brst[255];
// fgetc(brst, 255, (FILE*)student);
while (fgets(brst, sizeof brst, student)) {
line_count++;
printf("%u %s", line_count, brst);
}
fclose(student);
}
printf("Line Count %u\n", line_count);
return 0;
}
Try this:
#include "stdafx.h"
#include <stdio.h>
int _tmain(int argc, _TCHAR* Argo[]){
FILE *student;
char brst[255];
char* result = NULL;
//Ensure file open works, if it doesn't quit
if ((student = fopen("student.txt", "r")) == NULL)
{
printf("Failed to load file\n");
return 1;
}
//Read in the file
for ( (result = fgets( brst, sizeof(brst), student));
!feof(student);
(result = fgets( brst, sizeof(brst), student)) )
{
if ( result == NULL ) break; //I've worked on embedded systems where this actually ment waiting on data, not EOF, so a 'continue' would go here instead of break in that case
printf("%s\n", brst);
}
fclose( student );
return 0;
}
feof() is only true after you've read past the end of the file. Using a for with two identical reads, and feof() on the conditional is a simple way to ensure you read the file as expected.
Use feof() to check for an eof condition.
You are correctly reading the file line-by-line, but use fgets(), not fgetc() - and the cast is not needed.
Then use sscanf() to assign the line data to variables (or some "safe" form of it).