Reading a file using fgets and printing its content on screen - c

I still consider myself as a new webby in C.I am trying to read a file in, file is not binary but its size varies from small size of feb kbs to big size files of feb Mbs.I am using fgets function, i had taken reference from this link but after compilation, i am getting segmentation fault.i tried to debug it with gdb and found that i am able to open file but unable to read.Here is my code.
#include<stdio.h>
#define MAX_LENGTH 1048576
int main()
{
FILE *fp;
char *result;
char line[MAX_LENGTH];
fp =fopen("/home/shailendra/sampleprograms/C/shail1.txt","r");
if(result=fgets(line,MAX_LENGTH,fp) != NULL)
printf("The string is %s \n",result);
else
printf("Error opening the file");
if(fclose(fp))
printf("fclose error");
}
This Segmentation fault really sucks your blood.I understand that it is due to insufficient memory allocation but i had used MAX_LENGTH 1048576, so i don't think that it must create any problem.I had tried it with both small files with only one line and a big file with multiple lines but i am unable to figure out why i am getting segmentation fault.
I also looked at this and this but got no help.

Try some parentheses:
if((result=fgets(line,MAX_LENGTH,fp)) != NULL)
^ ^
Without those you'll store the result of the comparison instead of a pointer to the string.
Side note: you don't need result at all. When it succeeds, fgets returns the pointer you passed in; in other words you can just printf line:
if(fgets(line, MAX_LENGTH, fp))
printf("The string is %s \n", line);
Second side note: before trying to fgets from the file, you should check whether fopen succeeded:
if (!fp)
perror("fopen");

Couple of things in addition to cnicutar's answer:
#include <stdio.h>
^ Please make sure you have a space between your includes and the headers
fgets will read until it's encountered a new line or EOF (whichever comes first), so to read the whole file you'd have to do it in a loop.
I would recommend doing it like this (no need for the pointer assignment as pointed out):
while(fgets(line, MAX_LENGTH, fp))
printf("%s", line);

Related

Segmentation fault strcpy/strcat

I am writing a program to open a file (say "input_file"), manipulate its contents and then output it to another file ("manipulated-input_file")
I have done this with strcpy and strcat in the following way:
char t-filename[]="Manipulated-", filename[50], td-filename[50];
memset ( filename, '\0', FILE_NAME);
printf("Please enter the filename - \n");
scanf( "%30s", filename );
strcpy(td-filename,filename);
strcat(t-filename,td-filename);
printf("%s\n", t-filename);
Now printf functions prints the t-filename as "Manipulated-input_file"
After this part, I have a section where I open "input_file" and
do something.
fptr = fopen(filename, "r");
while ( fgets (line, sizeof line, fptr) != NULL)
{
...do something...
}
fclose(fptr);
Later I wanted to open a file with name 't-filename' at the end of the code:
tptr = fopen(t-filename, "w");
fprintf(tptr,"something");
fclose(tpr);
When I compile this code I am getting "Segmentation fault (core dumped)".
I do not know what went wrong. Can somebody help?
transfilename doesn't have enough space to hold additional items added there by strcat(transfilename,translatedfilename);. It's already full with "Translated-" since [] gives you the exact amount of characters in the initializing string, plus a null terminator.
You need to either change it to char transfilename [LARGE_ENOUGH] or use dynamic memory allocation to change the size in run-time.
strcat(t-filename,td-filename);
t-filename is not large enough to accommodate the result and it is an Undefined Behaviour.
same here
strcat(transfilename,translatedfilename);
transfilename is not large enough to accommodate the result and it is an Undefined Behaviour.

fgets returns null on non empty file

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

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] = "";

Reading from file into array, line by line

I am trying to read from a file in C. My code is the following. It seems to read everything fine into the array, but when I try to print it, I get the error Segmentation fault (core dumped)
FILE *fp;
char * text[7][100];
int i=0;
fp = fopen("userList.txt", "r");
//Read over file contents until either EOF is reached or maximum characters is read and store in character array
while(fgets((*text)[i++],100,fp) != NULL) ;
printf("%s", &text[0]);
fclose(fp);
Can someone point me in the right direction?
I have tried reading and copying solutions from other similar cases, but they are extremely specific to the user.
So part one, you don't need a pointer to a char[][]:
char text[7][100];
Part 2, just deference your array of strings like a normal person, nothing fancy here:
while(fgets((text)[i++],100,fp) != NULL) ;
Live example: http://ideone.com/MADAAs
Some things to watch out for:
If your input file has more than 7 lines you are going to have problems.
Why is “while ( !feof (file) )” always wrong?
char * text[7][100]; //wrong - this is 2 diminutions array of char pointers, replace it with
char text[7][100];
while(fgets((*text)[i++],100,fp) != NULL) ; // replace this with
while(fgets(&text[i++][0],100,fp) != NULL) ;
NOTE: this code will work in the current scope of the function (on the stack) if you need to use it outside the scope of current scope , allocate some memory on the heap and use the pointers of the heap.

Reading a specific line from a file in C

Okay, so after reading both: How to read a specific line in a text file in C (integers) and What is the easiest way to count the newlines in an ASCII file? I figured that I could use the points mentioned in both to both efficiently and quickly read a single line from a file.
Here's the code I have:
char buf[BUFSIZ];
intmax_t lines = 2; // when set to zero, reads two extra lines.
FILE *fp = fopen(filename, "r");
while ((fscanf(fp, "%*[^\n]"), fscanf(fp, "%*c")) != EOF)
{
/* globals.lines_to_feed__queue is the line that we _do_ want to print,
that is we want to ignore all lines up to that point:
feeding them into "nothingness" */
if (lines == globals.lines_to_feed__queue)
{
fgets(buf, sizeof buf, fp);
}
++lines;
}
fprintf(stdout, "%s", buf);
fclose(fp);
Now the above code works wonderfully, and I'm extrememly pleased with myself for figuring out that you can fscanf a file up to a certain point, and then use fgets to read whatever data is at said point into a buffer, instead of having to fgets every single line and then fprintf the buf, when all I care about is the line that I'm printing: I don't want to be storing strings that I could care less about in a buffer that I'm only going to use once for a single line.
However, the only issue I've run into, as noted by the // when set to zero, reads two extra lines comment: when lines is initialized with a value of 0, and the line I want is like 200, the line I'll get will actually be line 202. Could someone please explain what I'm doing wrong here/why this is happening and whether my quick fix lines = 2; is fine or if it is insufficient (as in, is something really wrong going on here, and it just happens to work?)
There are two reasons why you have to set the lines to 2, and both can be derived from the special case where you want the first line.
On one hand, in the while loop the first thing you do is use fscanf to consume a line, then you check if the lines counter matches the line you want. The thing is that if the line you want is the one you just consumed you are out of luck. On the other hand you are basically moving through lines by finding the next \n and incrementing lines after you check if the current line is the one you're after.
These two factors combined cause the offset in the lines count, so the following is a version of the same function taking them into account. Additionally it also contains a break; statement once you get to the line you are looking for, so that the while loop stops looking further into the file.
void read_and_print_line(char * filename, int line) {
char buf[BUFFERSIZE];
int lines = 0;
FILE *fp = fopen(filename, "r");
do
{
if (++lines == line) {
fgets(buf, sizeof buf, fp);
break;
}
}while((fscanf(fp, "%*[^\n]"), fscanf(fp, "%*c")) != EOF);
if(lines == line)
printf("%s", buf);
fclose(fp);
}
Just as another way of looking at the problem… Assuming that your global specifies 1 when the first line is to be printed, 2 for the second, etc, then:
char buf[BUFSIZ];
FILE *fp = fopen(filename, "r");
if (fp == 0)
return; // Error exit — report error.
for (int lineno = 1; lineno < globals.lines_to_feed_queue; lineno++)
{
fscanf(fp, "%*[^\n]");
if (fscanf(fp, "%*c") == EOF)
break;
}
if (fgets(buf, sizeof(buf), fp) != 0)
fprintf(stdout, "%s", buf);
else
…requested line not present in file…
fclose(fp);
You could replace the break with fclose(fp); and return; if that's appropriate (but do make sure you close the file before exiting; otherwise, you leak resources).
If your line numbers are counted from 0, then change the lower limit of the for loop to 0.
First, about what is wrong here: this code is unable to read the very first line in the file (what happens if globals.lines_to_feed__queue is 0?). It would also miscount lines shall the file contain successive newlines.
Second, you must realize that there is no magic. Since you don't know at which offset the string in question lives, you have to patiently read file character by character, counting end-of-strings along the way. It doesn't matter if you delegate the reading/counting to fgets/fscanf, or fgetc each character for manual inspection - either way an uninteresting piece of file will make its way from the disk into the OS buffers, and then into the userspace for interpretation.
Your gut feeling is absolutely correct: the code is broken.

Resources