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
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... ;-)
I'm trying to print lines which starts from given letter to second file but it prints only 1 line and then stops, even if there are more lines which starts with given letter. How to fix it ?
#include <stdio.h>
#include <string.h>
int main()
{
FILE* f = fopen("story.txt","r");
char usr;
printf("enter letter: ");
scanf(" %c",&usr);
FILE* f2=fopen("letter.txt","a+");
char buffer[255];
while(fscanf(f, "%[^\n]s", buffer)==1)
if (*buffer == usr)
fprintf(f2, "%s\n", buffer);
return 0;
}
The second time through the loop, fscanf(f, "%[^\n]s", buffer) fails to scan anything because the previous call left the \n character in the buffer. This can't get past that.
Use fgets() instead of fscanf() to read a whole line.
char buffer[255];
while(fgets(buffer, sizeof buffer, f))
if (buffer[0] == usr)
fprintf(f2, "%s", buffer);
I would not use fscanf to read line of text.
//fi - input file
//fo - output file
int copyLines(FILE *fi, FILE *fo, char c)
{
char line[256];
if(fi && fo)
{
while(fgets(line, sizeof(line), fi))
{
if(*line = c)
if(fputs(line, fo) == EOF) return EOF;
}
}
return 0;
}
For starters the format string in the call of fscanf is incorrect
while(fscanf(f, "%[^\n]s", buffer)==1)
^^^
At least you should remove the letter s.
Another problem is that after such a call of fscanf the new line character '\n' is not read. So the next call of fscanf reads an empty string.
It is better to use another C function fgtes. But you need to use it with a caution.
In general a string stored in the input file can be greater than the size of the array buffer.
That means that you need to read some strings in the input file using more than one call of fgets. Otherwise the output file will be formed incorrectly.
The loop can look the following way
int success = 1;
do
{
success = fgets( buffer, sizeof( buffer ), f ) != NULL;
if ( success )
{
int target = *buffer == usr;
if ( target ) fprintf( f2, "%s", buffer );
while ( success && !strchr( buffer, '\n' ) )
{
success = fgets( buffer, sizeof( buffer ), f ) != NULL;
if ( success && target ) fprintf( f2, "%s", buffer );
}
}
} while ( success );
For example, if a .txt has
Hello
There.
written in it, no matter how bigger N is in fgets(str, N, file), it will only store "Hello" in str, because it stops when it finds a '\n' character.
So, how could I read the whole file if, for example, I wanted to find a specific word in it?
So, how could I read the whole file
In order to read the whole file into a memory buffer, you could use the function fread. After turning the input into a string by appending a terminating null character, you could then use the function strstr to search the input for a certain word.
Here is a program which does this and searches the input for the word targetword:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( void )
{
FILE *fp;
char buffer[1000];
size_t read;
//open input file
fp = fopen( "input.txt", "rt" );
if ( fp == NULL )
{
fprintf( stderr, "ERROR: Unable to open input file!\n" );
exit( EXIT_FAILURE );
}
//read entire file into buffer
read = fread( buffer, 1, sizeof buffer, fp );
//verify that buffer was not too small
if ( read == sizeof buffer )
{
fprintf( stderr, "ERROR: Memory buffer is too small to contain entire input!\n" );
exit( EXIT_FAILURE );
}
//add terminating null character to make input a valid
//null-terminated string
buffer[read] = '\0';
//search input for target word
if ( strstr( buffer, "targetword" ) != NULL )
printf( "Found word!\n" );
else
printf( "Did not find word!\n" );
fclose( fp );
}
However, instead of reading the entire file at once (which could require a very large memory buffer), it is more common to read one line at a time in a loop, and in every loop iteration, you check whether the current line contains the word you are looking for. That way, the memory buffer only has to be large enough to store one line of input at once, instead of the entire input.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
int main( void )
{
FILE *fp;
char line[100];
bool found = false;
//open input file
fp = fopen( "input.txt", "rt" );
if ( fp == NULL )
{
fprintf( stderr, "ERROR: Unable to open input file!\n" );
exit( EXIT_FAILURE );
}
//read one line per loop iteration
while ( fgets( line, sizeof line, fp ) != NULL )
{
//verify that line was not too long to fit into buffer
if ( strchr( line, '\n' ) == NULL )
{
fprintf( stderr, "line too long to fit buffer!\n" );
exit( EXIT_FAILURE );
}
//search for target word
if ( strstr( line, "targetword" ) != NULL )
{
found = true;
break;
}
}
if ( found )
printf( "Found word!\n" );
else
printf( "Did not find word!\n" );
fclose( fp );
}
However, both solutions have several possible issues:
If the target word targetword is part of another word, for example thetargetword, then it will state that it found the target word. I'm not sure if this is what you want or if you want the target word to appear by itself.
If the target word is syllabified so that, for example, target-\n appears in one line and word in the next line, then the program won't be able to find the word.
The search is case-sensitive, so it will only find targetword, but not Targetword or TARGETWORD.
All of these issues can be solved, if necessary, but would require additional work.
I have a file .txt with values of some variable. I need to read them to declarate my variables in main. What is wrong?
#include <stdio.h>
#define INPUT "input.txt"
int main (void){
FILE *open_file = fopen(INPUT, "r");
if (open_file == NULL){
puts("ERROR.");
} else {
puts("SUCCESS.");
}
char *buffer;
int size = ftell(open_file);
int read_file = fread(buffer,size,*open_file);
int Integer1, Integer2;
while (size != EOF){
sscanf("%d%d",Integer1, Integer2);
}
int close_file = fclose(open_file);
if (close_file == -1){
puts("Error in closing file.");
} else {
puts("Closing file: SUCCESS.");
}
return 0;
}
Whats is wrong? I have to read every line of my file. For example if my file contains:
1
2
My scanf should set:
Integer1 = 1;
Integer2 = 2;
One problem is that after the line
char *buffer;
the variable buffer does not point to any valid memory location. It is a wild pointer.
You can either create a fixed size array like this:
char buffer[100];
or you can create a dynamically sized memory buffer, like this:
if ( fseek( open_file, 0, SEEK_END ) != 0 )
DoSomethingToHandleError();
long size = ftell(open_file);
if ( fseek( open_file, 0, SEEK_SET ) != 0 )
DoSomethingToHandleError();
char *buffer = malloc( size );
if ( buffer == NULL )
DoSomethingToHandleError();
Depending on whether you used a fixed-size array or a dynamically allocated buffer, you should change the call to fread to one of the following:
fread( buffer, sizeof(buffer), open_file ); //for fixed size array
fread( buffer, size, open_file ); //for dynamically allocated buffer
Instead of using the function fread, you would probably be better off using the function fgets, especially because sscanf requires a null-terminated string as input, not binary data. The function fread will give you binary data that is not null-terminated, whereas fgets will give you a null-terminated string.
Also, change the line
sscanf("%d%d",Integer1, Integer2);
to
sscanf( buffer, "%d%d", &Integer1, &Integer2);
Before using Integer1 and Integer2 afterwards, you should also check the return value of sscanf to make sure that both integers were found in the string.
However, if you don't want to handle the memory management and reading in of the file yourself, you can simply use fscanf, like this:
if ( fscanf( open_file, "%d%d", &Integer1, &Integer2 ) != 2 )
DoSomethingToHandleError();
But this has the disadvantage that fscanf will just give you the first two numbers that it finds in the file, and won't perform much input validation. For example, fscanf won't enforce that the two numbers are on separate lines. See the following link for more information on the disadvantages of using fscanf:
A beginners' guide away from scanf()
If you use the function fgets as I suggested, then you will need two calls to fgets to read both lines of the file. This means that sscanf will be unable to find both integers in the same string. Therefore, if you use fgets, then you will have to change your program logic a bit, for example like this:
#define MAX_INTEGERS 2
char buffer[100];
int integers[MAX_INTEGERS];
int num_found = 0;
while ( fgets( buffer, sizeof(buffer), open_file ) != NULL )
{
int i;
if ( strchr( buffer, '\n' ) == NULL && !feof( openfile ) )
{
printf( "Error: Line size too long! Aborting.\n" );
break;
}
if ( sscanf( buffer, "%d", &i ) == 1 )
{
if ( num_found == MAX_INTEGERS )
{
printf(
"Error: Found too many integers in file! This "
"program only has room for storing %d integers. "
"Aborting.\n",
MAX_INTEGERS
);
break;
}
//add found integer to array and increment num_found
integers[num_found++] = i;
}
else
{
printf(
"Warning: Line without number encountered. This could "
"simply be a harmless empty line at the end of the "
"file, but could also indicate an error.\n"
);
}
}
printf( "Found the following integers:\n" );
for ( int i = 0; i < num_found; i++ )
{
printf( "%d\n", integers[i] );
}
Instead of using sscanf, you may want to use strtol, as that function allows you to perform stricter input validation.
If you don't want to use the function fgets, which reads input line by line, but really want to read the whole file at once using fread, you can do that, but you would have to add the terminating null character manually.
EDIT: Since you stated in the comments that you didn't want a loop and wanted to store the individual lines each into their own named variable, then you could use the following code instead:
//This function will assume that one number is stored per line, and
//write it to the memory location that "output" points to. Note that
//the return value does not specify the number found, but rather
//whether an error occurred or not. A return value of 0 means no error,
//nonzero means an error occurred.
int get_number( FILE *fp, int *output )
{
char buffer[100];
int i;
//read the next line into buffer and check for error
if ( fgets( buffer, sizeof(buffer), fp ) == NULL )
return -1;
//make sure line was not too long to fit into buffer
if ( strchr( buffer, '\n' ) == NULL && !feof( fp ) )
return -1;
//parse line and make sure that a number was found
if ( sscanf( buffer, "%d", &i ) != 1 )
return -1;
*output = i
return 0;
}
Now, in your function main, you can simply use the following code:
int error_occurred = 0;
if ( get_number( &Integer1 ) != 0 )
{
printf( "Error occured when reading the first integer.\n" );
error_occurred = 1;
}
if ( get_number( &Integer2 ) != 0 )
{
printf( "Error occured when reading the second integer.\n" );
error_occurred = 1;
}
if ( !error_occurred )
{
printf( "The value of Integer1 is: %d\n", Integer1 );
printf( "The value of Integer2 is: %d\n", Integer2 );
}
There are couple of problems in your code
fread(buffer,size,*open_file);, buffer is not allocated
A) you have to allocate memory using malloc or calloc if you use pointers and also free after you are done with it.
If you want to avoid the headache of allocating and freeing, you better use an array sufficient enough to store the contents.
fread takes 4 arguments
A) 4th argument is not FILE , its FILE* , use only open_file not *open_file and you have not used nmemb(number of members) parameter
On success, fread() return the number of items read, so check the return value to avoid errors.
ftell() returns the current offset , Otherwise, -1 is returned
A) you really don't need it, check the return value of fread to find out you have reached the EOF.
check the syntax of sscanf and example
OP's code failed to seek the end of the array, allocate space for buffer and used fread() incorrectly.
Correct version shown with some error checking.
//char *buffer;
//int size = ftell(open_file);
//int read_file = fread(buffer,size,*open_file);
// Seek and report, hopefully, the end position
if (fseek(open_file, 0, SEEK_END)) { fprintf(stderr, "fseek() failed.\n"); return EXIT_FAILURE;
long size = ftell(open_file);
if (size == -1) { fprintf(stderr, "ftell() failed.\n"); return EXIT_FAILURE; }
// Allocate memory and read
if ((unsigned long) size > SIZE_MAX) { fprintf(stderr, "size too big.\n"); return EXIT_FAILURE; }
char *buffer = malloc((size_t) size);
if (buffer == NULL) { fprintf(stderr, "malloc() failed.\n"); return EXIT_FAILURE; }
size_t length = fread(buffer, sizeof *buffer, size, open_file);
// Use `length` as the number of char read
// ...
// when done
free(buffer);
Other problems too.
// while (size != EOF){
// sscanf("%d%d",Integer1, Integer2);
// }
Maybe later, GTG.
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 );
}