Reading variables via fread and storing via sscanf - c

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.

Related

Detect if line is the last line of a file, using only one loop?

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... ;-)

Print whole line which starts from given letter

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 );

Using C, how to I read in specific information from a file and store in multiple locations

I'm given a text file containing information about a game world and it's collision data in this format.
Width 5
Height 5
10001
11000
11100
11111
11111
To store the data, I'm given
static int BINARY_MAP_WIDTH;
static int BINARY_MAP_HEIGHT;
and
static int **MapData; // Dynamic array of map data
My FileIO knowldege doesn't go much beyond reading in strings from a file line by line.
So far I have this very roundabout way of reading in just the first two lines.
FILE *Data;
int line = 1; // line number that we're on
Data = fopen(FileName, "rt");
if (!Data)
return 0;
if (Data)
{
while (!feof(Data))
{
if (line == 1)
fscanf(Data, "%*[^0-9]%d%n", &BINARY_MAP_WIDTH);
if (line == 2)
fscanf(Data, "%*[^0-9]%d%n", &BINARY_MAP_HEIGHT);
if (line > 2)
break;
line++;
}
}
And to be quite honest, I'm not entirely sure why it's working, but I am getting the correct values into the variables.
I know how to set up the dynamic array, at this point my issue is with reading in the correct values.
I'm not sure where to go from here.
Here's a couple things you need to know about fscanf
fscanf will consume as many bytes as necessary to perform the
requested conversions and will update the file pointer accordingly.
The next call to fscanf will start at the location in the file
where the previous fscanf ended.
fscanf returns the number of successful conversions, so you
should verify that the return value is equal to the number of
conversions requested.
So here's how I would rewrite the code you have so far
#include <stdio.h>
static int mapWidth;
static int mapHeight;
int readFromFile( char *name )
{
FILE *fp;
int good = 1;
if ( (fp = fopen(name, "r")) == NULL )
return 0;
if ( fscanf(fp, "%*[^0-9]%d", &mapWidth) != 1 )
good = 0;
if ( fscanf(fp, "%*[^0-9]%d", &mapHeight) != 1 )
good = 0;
if ( good )
{
// the code to read the rest of the file goes here
}
fclose( fp );
return good;
}
int main( void )
{
if ( readFromFile( "input.txt" ) )
printf( "%d %d\n", mapWidth, mapHeight );
else
printf( "readFromFile failed\n" );
}
The next step is to figure out
how to allocate memory for MapData based on the width and height
how to read the rest of the lines in a loop, e.g. using fgets or fscanf(..."%s"...)
how to parse those lines to fill in the MapData

How to read entire file in c into a numeric array

I'm writing a program in C, that is supposed to read arrays of doubles from files of arbitrary length. How to stop it at EOF? I've tried using feof, but then read the discussions:
Why is “while ( !feof (file) )” always wrong?
How does C handle EOF?
Then again they concern strings, not numbers. So when reading a file of the form "4 23.3 2 1.2", how to state the loop condition, so that my array A has all the numbers from the file and nothing more (also the iterator N = length of A)?
Here's the part of my code with feof, which produces one entry too many in A. The reallocation part is based on http://www.cplusplus.com/reference/cstdlib/realloc/ example.
int N = 0;
double *A = NULL;
double *more_space;
double buff = 0;
FILE *data;
data = fopen(data.dat,"r");
while(feof(data) == 0) {
fscanf(data, "%lg", &buff);
more_space = realloc(A, (N+1)*sizeof(double));
A = more_space;
A[N] = buff;
N++;
}
The return value of fscanf is -1 when you hit eof (or other problems) so try while(fscanf(…) >= 0) for your outer loop. (Whether you accept a zero return value or not depends on how you want to handle bad data -- as other posters have pointed out, you will get 0 if no numbers are converted.
I like using the 'greater than or equals' test (instead of testing for ==1) because it doesn't break if you change the scanf format to, say, read two items from the input line. On the other hand, you could argue that it's better to verify that you always read exactly the correct number of arguments, and it's better to have your program 'fail fast' as soon as you change the number of scant arguments, than to have some mysterious failure later on, if you get bad input. It's a matter of style, and whether this is throwaway code for an assignment, or production code..
During the scan, save the results of fscanf()
int cnt;
double d;
while ((cnt = fscanf("%f", &d)) == 1) {
more_space = realloc(A, (N+1)*sizeof(double));
if (more_space == NULL) Handle_MemoryError();
A = more_space;
A[N] = buff;
N++;
}
if (cnt == 0) Handle_BadDataError();
Just stop when fscanf tells you there is no more data to be read. Its return value indicates the number of items it read or you get EOF if you reach end of file or there is a read error. Therefore, since you are reading only one item in each call, you will get 1 so long as reading is successful.
while (fscanf(data, "%lg", &buff) == 1) {
...
}
You may want to store the return value in a variable to verify whether reading stopped due to end-of-file or because the double parsing failed.
You should do:
while (fscanf(data, "%lg", &buff) == 1)
That way if you hit a "non number" then it'll stop instead of loop infinitely!! ... And fscanf will check for EOF and it'll break the loop for you.
Alternatively to other answers, read the entire file:
int32_t readFile ( char* filename, uint8_t** contentPtr, int32_t* sizePtr)
{
int32_t ret = 0;
struct stat st;
FILE *file = NULL;
uint8_t* content = NULL;
memset ( &st, 0, sizeof ( struct stat ) );
ret = stat( filename, &st );
if( ret < 0 ) {
return -1;
}
file = fopen64(filename, "rb");
if ( file == NULL ) {
return -1;
}
content = calloc ( st.st_size+10, sizeof ( uint8_t ) );
ret = fread ( content, 1, st.st_size, file );
fclose( file );
if( ret != st.st_size ) {
free(content);
return -1;
}
*contentPtr = content;
if (sizePtr != NULL) {
*sizePtr = st.st_size;
}
return 0;
}
And then process the contents of the buffer with sscanf().

Replace string with another

I am just not sure why my replaceWord isn't going in to the file at all i have used all the commented out and so on and so forth. I am just trying to replace with with the text received from the command line argument. I know i might be far off I was just looking for a relatively easy way to do it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( int argc, char *argv[] )
{
if ( argc != 4 ) /* argc should be 2 for correct execution */
{
/* We print argv[0] assuming it is the program name */
printf( "usage: %s filename\n", argv[0] );
}
else
{
// We assume argv[1] is a filename to open
char* wordReplace = argv[1];
char* replaceWord = argv[2];
FILE *file = fopen( argv[3], "r" );
/* fopen returns 0, the NULL pointer, on failure */
if ( file == 0 )
{
printf( "Could not open file\n" );
}
else
{
char string[100];
int len = 0;
/* read one character at a time from file, stopping at EOF, which
indicates the end of the file. Note that the idiom of "assign
to a variable, check the value" used below works because
the assignment statement evaluates to the value assigned. */
while ( (fscanf( file, "%s", string ) ) != EOF )
{
len = strlen(string);
printf( "%s\n", string );
if(strcmp(string, wordReplace) == 0){
//fseek (file, (-strlen(string) + 1), 1);
//fputc(*replaceWord,file);
//replaceWord++;
//strcpy(string, replaceWord);
fprintf(file,"%s",replaceWord);
fputs(replaceWord, file);
printf("\n%d\n", len);
}
}
fclose( file );
}
}
printf("\n");
return 0;
}
You've opened the file in r ie read mode and trying to write to it.
Also after correcting that, note that, the replaced word and word to be replaced have to be of the same size, if you want to replace the file in place. Else you will end up overwriting other data. And you need to use functions like fseek to reposition the internal file pointer as fp would have moved ahead after fscanf

Resources