fgets returns null on non empty file - c

I am trying to read from a file a non specific number of integers in pairs. I also want to skip lines that start with #. My problem is that nothing gets printed. When I tried to printf the value returned by fgets, it printed null. I would really appreciate a little help since I am not very experienced with C and I would be very grateful if you did not focus on feof since I have already read why is feof bad.
The file looks like this:
#This must
#be
#skipped
1233 14432
4943928 944949
11233 345432
And the code is:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct{
int start;
int end;
}path;
int main()
{
path* array;
array=malloc(5*sizeof(path));
if(array==NULL){
printf("Error allocating memory\n");
abort();
}
FILE* fd=fopen("File.txt","r");
if(fd==NULL){
printf("Error opening file\n");
abort();
}
char buff[200];
int counter=0;
if(fopen==NULL){
printf("Error opening file\n");
abort();
}
char c;
while(!feof(fd)||counter==6){
fgets(buff,200,fd);
c=buff[0];
if(strcmp(buff[0],"#")){
continue;
}
sscanf(&buff,"%d %d",array[counter].start,array[counter].end);
printf("%d\t%d\n",array[counter].start,array[counter].end);
counter++;
}
fclose(fd);
free(array);
return 0;
}

First, answering the title of your question: fgets() returns NULL at end of file and not when a file is empty.
Anyway, your test in the while loop is incorrect:
feof() only gives a true result when you have already tried read and you have already hit the end of file with an unsuccessful read. As read tries to give you as many bytes as it can... or none at all if end of file, the only way to get end of file condition is after you failed to read something. It is far better to check for fgets() result, as it returns NULL on being unable to read anything now. (and not in the last read) so
while(fgets(buff, sizeof buff, fd) != NULL)
or just
while(fgets(buff, sizeof buff, fd))
would be far better. Also, see how I use the sizeof operator to use the size of the used buffer, instead of repeating (and being error prone) the actual number of bytes at two places. If you decide to change the size of the buffer, you'll need also to change the actual number of bytes to read in the fgets() call, making the possibility of forgetting one of them an opportunity to run into trouble.
you order to stay in the loop only while !feof() OR when counter == 6 (first, this will make the control to enter the loop when counter is equal to 6, despite you have reached EOF or not, this cannot be correct) Think that you only get out of the loop when both conditions are false (this means feof() returns true and also counter != 6), you had better to write:
while(fgets(buff, sizeof buff, fd) && counter < max_number_of_iterations)
The test
if(strcmp(buff[0],"#"))
is also incorrect, as buff[0] is a character (indeed, it is the first character read in the buffer, and "#" is a string literal (not a character) Probably you got at least a warning from the compiler, from which you say no word. You had better to test both characters for equality, as in
if (buff[0] == '#') /* this time '#' is a character literal, not a string literal */
in the line
if (fopen == NULL)
fopen by itself is a pointer to the library function fopen(3) which is not what you want (fopen is always != NULL) but
if (fd == NULL){
(which you do before, so you had better to eliminate al this code)
you define a char c;, then initialize it to the first char of buff, and then you don't use it at all. This has no impact in your code but it's bad style and confounds maintainers in the future.
in the line sscanf(&buff, "%d %d", .... you don't need to pass &buff, while buff is already a char pointer. It is better to pass it buff.n But instead, you need to pass pointers to the variables you are reading so you need it corrected into:
sscanf(buff, "%d%d", &array[counter].start, &array[counter].end);
not doing so will make an Undefined Behaviour that will be difficult to pursue, as the use of uninitialised variables (and more on, pointers to variables) will make the code probably work at first, but fail when it has got to production for a while... this is a very serious error.
Your code, with all these errors corrected, should look like:
pru.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N (5) /* I have defined this constant so you can
* change its value without having to go all
* the code for occurrences of it and
* changing those */
typedef struct{
int start;
int end;
} path;
int main()
{
path* array = malloc(N*sizeof(path)); /* better declare and init */
if(array==NULL){
printf("Error allocating memory\n");
abort(); /* have you tried exit(EXIT_FAILURE); ?? */
}
FILE* fd=fopen("File.txt","r");
if(fd==NULL){
printf("Error opening file\n");
abort();
}
char buff[200];
int counter=0;
while(fgets(buff, sizeof buff, fd) && counter < N){
if(buff[0] == '#'){
continue;
}
sscanf(buff, "%d %d", &array[counter].start, &array[counter].end);
printf("%d\t%d\n", array[counter].start, array[counter].end);
counter++;
}
fclose(fd);
free(array);
return 0;
}
Running the code shows:
$ pru
1233 14432
4943928 944949
11233 345432
with the File.txt you posted.
Finally, a hint:
Despite of your interest in knowing only the reasons of your loop falling, and not why feof() is of no use here (and many other things you just don't ask for and that are wrong in your code), if that is actually the case, you had better to post an example that only shows the failing behaviour as recommended by the page How to create a Minimal, Complete, and Verifiable example you should have read and which I recommend you to do.

You should not check feof() in the while condition. See Why is “while ( !feof (file) )” always wrong?.
The loop should be:
while (fcounter < 5 && fgets(buff, 200, fd))

Related

Initializing a null pointer before fscanf

So I gotta make this program that reads a huge .txt file into an AVL, and for that, I need to read all the formatted data in the text document and put it into an AVL. However, any time I try to initialize the AVL in my code (a NULL pointer) it breaks the code once it reaches the fscanf function I used to gather the strings out of the .txt file. I made this demo right here, and I think I'm pretty close to the source of the problem. I narrowed it down to being related to initializing a pointer with a NULL value before the fscanf function. But how do I fix this?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE * filePointer = fopen("_lexico_shuf.txt", "r");
if(!filePointer) {
printf("can't open the file");
exit(101);
}
char *lexiconWord;
float polarity;
int *a = NULL;
printf("before while");
while (!feof(filePointer)) {
fscanf(filePointer, "%[^;];%f\n", lexiconWord, &polarity);
printf("| (%s) (%.1f) |", lexiconWord, polarity);
}
printf("after while");
}
so the only thing that is printed on the screen is the "before while" printf, and not the "after while" one. and the program returns a random number.
lexiconWord hasn't been set to point anywhere, so fscanf is using an invalid pointer value to attempt to write to.
Change this variable to an array, and use a field width in fscanf do you don't overrun the buffer, and check the return value of fscanf.
char lexiconWord[100];
...
int rval = fscanf(filePointer, "%99[^;];%f\n", lexiconWord, &polarity);
if (rval != 2) {
printf("not all values read\n");
exit(1);
}
Also, see Why is “while ( !feof (file) )” always wrong?

Why am I getting a Segmentation Fault when reading in a text file and storing into an array? [duplicate]

This question already has answers here:
Getting a stack overflow exception when declaring a large array
(8 answers)
Closed 5 years ago.
I need to read in a line of text, store it into an array. When I compile the program, it works but then when I execute it, I receive a segmentation fault. I have read other questions and tried what they have suggested and nothing seems to be working.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main() {
FILE *file;
char text[10000000], *line[10000000];
int i=0;
file = fopen("/home/Documents/xxxxxx_HW01/text.txt", "r");
if(file == NULL) {
printf("cannot open file");
exit(1);
}
while (i< 10000 && fgets(text, sizeof(text), file)!= NULL){
line[i] = strdup(text);
i++;
}
for (i=0; text[i] != '\0'; i++)
printf("%c ", text[i]);
fclose(file);
}
Continuing from my comment,
text[i] = strdup (text);
Is wrong. It attempts to assign a pointer (the result of strdup) to text[i] a signed char value. You need to use a separate array of pointers (or declare a pointer to pointer to char, e.g. char **lines; and then allocate pointers and then for each line).
The most important thing you can do is Listen to what your compiler is telling you. To make sure you are getting the benefit of your compilers help, always compile with warnings enabled and do not accept code until it compiles without warning. For gcc that means adding at minimum -Wall -Wextra to your compile string. For clang, -Weverything will do. For cl.exe (VS) add /Wall. Then read and understand the warnings. The compiler will give you the exact line where any problem occurs.
If you are simply reading lines less than some number, you can avoid allocating pointer and just use an array of pointers, but you must keep track of the index (to avoid writing beyond the last element)
Based on what you are attempting, it looks like you are trying to do something similar to the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1000
int main (void) {
FILE *file;
char text[MAX] = "",
*lines[MAX] = {NULL};
int i=0, j;
file = fopen ("/home/Documents/xxxxxx_HW01/text.txt", "r");
if(file == NULL) {
printf("cannot open file");
exit(1);
}
while (i < MAX && fgets (text, sizeof(text), file)!= NULL){
size_t len = strlen (text); /* get length */
if (len && text[len-1] == '\n') /* check if last is '\n' */
text[--len] = 0; /* overwrite with '\0' */
else { /* line too long - character remain unread */
fprintf (stderr, "error: line exceeds %d chars.\n", MAX - 2);
exit (EXIT_FAILURE);
}
lines[i] = strdup(text);
i++;
}
for (j = 0; j < i; j++) {
printf ("line[%3d] %s\n", j, lines[j]);
free (lines[j]); /* don't forget to free memory */
}
fclose(file);
return 0; /* main() is type int and therefore returns a value */
}
note: you should also remove the trailing '\n' included at the end of text by fgets -- example given above.
Look things over and let me know if you have further questions.
From what I remember sizeof will give you the size of the object type, and the fgets expects the maximum amount of chars you want to read, so you probably don’t want to use sizeof there.
Also you are increasing the index of your array indefinitely which is most likely going to give you a out of bounds exception.
Summing up I think you should try passing directly the size you set on your array on the fgets, and if you dont need the file to be all stored at the same time, just don’t increase i and handle each chunk in one iteration of the loop. If you do need the file all stored at once, make sure you have an array as big as your file size and perhaps use fread like this

C program to read a text file line by line then print out those lines to the terminal

I want to have a c program read a text file line by line then print out those lines to the terminal.
My code
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char* line;
FILE *ifp;
ifp = fopen("BBE.txt", "r");
if (ifp == NULL)
{
printf("Error opening file!\n");
exit(1);
}
while (fscanf(ifp, "%s", line) == 1)
{
printf("%s\n", line);
}
fclose(ifp);
return 0;
}
The program when i try to run it does not print out anything to the terminal. This tells me that the while loop is not working but i am not to sure as to why.
Your loop is not working, because fscanf does not return just 1 on success.
According to the man page of fscanf, the return value has the following meaning:
RETURN VALUE
On success, these functions return the number of input items
successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early matching failure.
The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs, in which case the error indicator for the stream (see ferror(3)) is set, and errno is set to indicate the error.
Additionally as already stated in another answer: You write to memory that is NOT YOUR memory:
char* line;
is just a the declaration of a pointer to a char. What you need is a contiguous array of char to write to.
You either can allocate this on the stack by declaring it:
char line[1000]; // Allocate a char array of the size of 1000.
or on the heap;
char* line = malloc(1000*sizeof(char)); // Allocate 1000 chars on the heap
here you have to free the memory afterwards
free(line);
You used *line without initialising it -> undefined behavior.
To fix that, you can use a char array instead:
char line[1000] = "";

Using Fgets in two ways

I looked through some "FGETS" questions before posting, and what i gathered is it may be a new line character thats causing the issue for the manual input.
int main ( int argc, char *argv[] ){
char temp[1000];
FILE *user_file;
printf("Starting....\n"); //Used for user visual.
if(argc == 2){ //open file
user_file = fopen(argv[1],"r");
if( user_file == NULL ){
printf("No file was found.");
exit(2);
}else{
fgets(temp,strlen(temp),user_file);
}
}else if( argc > 2 ){ // Will exit if arguments are greater than 2.
printf("Maximum args 2.\n");
exit(1);
}else{
printf("File was not provided, please enter the text to convert.\n"); //If the user doesnt provide a file allow manual input.
fgets(temp,strlen(temp),stdin);
}
printf("%s\n",temp);
return 0;
}//End main
Questions:
Why is fgets not opening the txt file I provide it with on the cmd line, and storing it to the temp array?
Why is Fgets being skipped over in the "else" statment if the file is not provided?
Why is print being skipped over in both instances?
Hey and by the way thank you very much for the assistance.
If you know a similar question that has been asked, can you post it in the comments so I can read it.
Your code has multiple problems.
Here's the first problem:
char temp[1000];
Your buffer declaration does not initialize the buffer's contents - so the value of each char value will be whatever was in the raw memory previously. In C most strings are "null-terminated" so having a terminating NULL (0 - zero) is important otherwise you can run into buffer-overruns.
The "best" approach is to zero-out (zero-initialize) the array/buffer before you use it, like so (in C99):
char temp[1000] = {0};
...this way temp will contain all 0 values (NULL) so anything written to it (provided it's no longer than 999 bytes) will automatically have a null-terminator (though fgets will append a terminating 0 value, but not every function in C does this).
The second problem is related to the first: you're using the runtime string-length function strlen to get the size of the strlen buffer. This is incorrect as the buffer sized is fixed at compile-time to 1000. The strlen will return the index of the first 0 (NULL) char value, which is undefined behavior at this point because you haven't zero-initialized the buffer anyway (so it could return 0 immediately if the buffer's original raw data contained a zero, or it could overrun 1000 because there was never any zero value.
...thus you need to re-use the buffer-length, like so:
#define TEMP_LENGTH 1000
char temp[ TEMP_LENGTH ];
...
fgets( temp, TEMP_LENGTH, user_file );
Finally, you're making the same mistake when you call fgets( temp, ..., stdin ).
The array temp[] is uninitialized, and you attempt to find strlen(temp). You don't even know if there is a NUL stored in the array. Try doing:
#define MAXLINE 1000
and changing your calls to fgets():
fgets(temp, MAXLINE, user_file);
...
fgets(temp, MAXLINE, stdin);
Here problem is in your code, instead of passed numerical value in second argument you passed strlen(temp).
fgets(temp,strlen(temp),user_file);
right way is :-
fgets(temp,1000,user_file);

Multiple fscanf

I have written the following program that is intended to read a string from a file into variable "title":
#include <stdio.h>
#include <stdlib.h>
int main()
{
int m, b;
char *title;
FILE *fp;
fp = fopen("input2.txt", "r");
if (fp == NULL)
{
printf ("Error: file cannot be found\n");
return 1;
}
fscanf(fp, "<%d>\n<%d>", &m, &b);
printf("%d\n%d", m, b);
fscanf(fp, "<%s>", title);
fclose(fp);
return 0;
}
The above program crashes at the second call to fscanf. Why does this happen?
Your main problem is that you've not allocated space for the string to be read into. You can do this in multiple ways:
char title[256];
or:
char *title = malloc(256);
if (title == NULL)
{
fprintf(stderr, "Out of memory\n");
exit(1);
}
either of which should then be used with:
if (fscanf(fp, " <%255[^>]>", title) != 1)
{
fprintf(stderr, "Oops: format error\n");
exit(1);
}
or, if you have a system with an implementation of fscanf() that's compliant with POSIX 2008, you can use the m modifier to %s (or with %c, or, in this case, a scanset %[...] — more on that below):
char *title = 0;
if (fscanf(fp, " <%m[^>]>", &title) != 1) // Note the crucial &
{
fprintf(stderr, "Oops: format error\n");
exit(1);
}
This way, if the fscanf() succeeds in its entirety, the function will allocate the memory for the title. If it fails, the memory will have been released (or never assigned).
Note that I changed %s to %m[^>]. This is necessary because the original conversions will never match the >. If there is a > in the input, it will be incorporated into the result string because that reads up to white space, and > is not white space. Further, you won't be able to tell whether the trailing context was ever matched — that's the > in the original format, and it's still a problem (or not) in the revised code I'm suggesting.
I also added a space at the start of the string to match optional white space. Without that, the < at the start of the string must be on the same line as the > after the second number, assuming that the > is present at all. You should also check the return from the first fscanf():
if (fscanf(fp, "<%d>\n<%d>", &m, &b) != 2)
{
fprintf(stderr, "Oops: format error\n");
exit(1);
}
Note that the embedded newline simply looks for white space between the > and the < — that's zero or more blanks, tabs or newlines. Also note that you'll never know whether the second > was matched or not.
You could use exit(EXIT_FAILURE); in place of exit(1); — or, since this code is in main(), you could use either return 1; or return(EXIT_FAILURE); where the parentheses are optional in either case but their presence evokes unwarranted ire in some people.
You could also improve the error messages. And you should consider using fgets() or POSIX's getline() followed by sscanf() because it makes it easier (by far) to do good error reporting, plus you can rescan the data easily if the first attempt at converting it fails.
This:
char *title;
is just a pointer to a char. If fscanf writes more than one character to it, you will corrupt whatever happens to be in memory after
You need to do one of two things:
char title[50]; // Holds up to 49 characters, plus termination
Or:
#include <stdlib.h>
// ...
char *title = malloc(50 * sizeof(char)); // Same capacity as above
if (title == NULL) {
// handle out of mem error
}
// ...
free (title);
The first option is obviously much simpler, but requires you to know your array size at compile time.
If you are new to programming, and haven't encountered pointers and dynamic memory allocation yet, stick with the first option for now.

Resources