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?
Related
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))
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
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] = "";
I am currently working on the C code below. I need to access the array outside the while loop, after fclose. It appears that the blackfin ADSP kernel crashes every time I run it. I will need it further to perform FFT. Please help!
#include <stdlib.h>
#include <stdio.h>
#include <flt2fr.h>
#include <fract_math.h>
#include <math_bf.h>
#include <complex.h>
#include <filter.h>
int main()
{
int n = 1024;
long int dat1[n];
FILE *file1;
fract16 *m;
int i;
// file1 open and read the values
file1 = fopen("0.dat", "r");
if (file1 == NULL) {
printf("I couldn't open 0.dat for reading.\n");
exit(0);
}
while (!feof(file1)) {
fgets(dat1, n, file1);
m = malloc(sizeof(fract16) * n);
for (i = 0; i < n; i++) {
sscanf(dat1, "%f", &m[i]); //getting error here
}
}
fclose(file1);
printf("%lf\n", m);
return 0;
}
Alright, thank you all for correcting my mistakes, but the problem is still unresolved. I am able to print all of the values inside, but outside the loop it prints just the last value of the data set, is there any precise solution for this? I googled for hours but no success yet.
The code is as follows >
#include <stdlib.h>
#include <stdio.h>
#include <flt2fr.h>
#include<fract_math.h>
#include <math_bf.h>
#include <complex.h>
#include <filter.h>
int main()
{
int n = 1024;
long int dat1[n];
FILE *file1;
fract16 *m;
file1 = fopen("0.dat", "r");
if (file1 == NULL) {
printf("I couldn't open 0.dat for reading.\n");
exit(0);
}
while( !feof(file1))
{
fgets(dat1,n,file1);
sscanf(dat1, "%f", &m);
printf("%f\n",m); //Prints all elements in the 1st column of the array, 0.dat is a nx2 matrix
}
fclose(file1);
}
You can allocate memory for the buffer before reading the file, outside the while loop. Then every time before reading into the buffer, simply use memset and set the buffer to all null characters.
Also, try using fread to read directly into the buffer rather than fgets
the variable m is defined as a pointer to and array of fract16
to fix the problem suggest:
if( 1 != sscanf(dat1, "%f", m+(sizeof(fract16)*i) )
{
perror( "sscanf failed" );
exit( EXIT_FAILURE );
}
The error is being cause because m is already a pointer and you want it to continue to be a pointer
As an aside. the code is not checking how much data was actually read in the call to fgets() so the for() may very well be reading behond the end of the actual data. And each trip through the while() loop is destroying/overlaying the pointer obtained from the prior call to malloc()
then later in the code is the statement:
printf("%lf\n", m);
But m is a pointer to an array of `fract16 objects.
and those fract16 objects might be double values, but that detail is not clear. In any case, this call to printf() will, at best, only output a single double value from the beginning of the last line in the input file. Is that what you really want to do?
Note: dat1[] is declared as an array of long int, but the call to sscanf() seems to be trying to extract float values.
I.E. the code is not consistent about the data types, nor the extraction of individual values, nor the printing.
One thing to note: with the current code there is a massive memory leak due to the pointer m being repeatedly overwritten by the calls to malloc() And due to the use of feof(), the last call to fgets() will fail, so the cotents of dat1[] will be starting with a NUL byte
Suggest allocating an array of pointers to fractl16 objects
Then for each line read, use malloc() to set the next pointer in the array of pointers, ...
I am trying to open and then write to a .dat file. The file is just a simple series of numbers, but i would like to add to it. Right now the fputs isn't working for me.
I was wondering if I am using the right function to do the job. Right now it says i can't use the integer enter_this in the function fputs because it is not a constant character.
I want to ask the user to add a integer to the file. My next step after i understand this is to add strings, floats, characters and more. But just getting something that is working is good.
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
#include
//functions called
//why is it void?
int main(void)
{
FILE *pFile;
int choice = 0;
char buf[40];
int i = 0;
int num[40];
int enter_this;
printf("WELCOME. \n\n");
pFile = fopen("test.dat", "r");
if (pFile != NULL)
for (i = 0; i < 8; i++)
{
//get num
fgets(buf, sizeof(buf), pFile);
num[i] = atoi(buf);
printf("#%i = %i\n", i, num[i]);
}
printf("Enter number to be added: ");
gets_s(buf);
enter_this = atoi(buf);
fputs(enter_this, pFile);
fclose(pFile);
system("pause");
}//end main
int main(void)
The 'void' in this case implies that the function 'main' accepts no arguments. If you just leave empty parens in C, it implies that the function accepts a variable number of arguments, not 0 as you might expect.
If you want to add a number to the end of the file, you must open it in "append mode":
FILE *pFile = fopen("test.dat", "a");
The second argument "a" is a mode string. It tells fopen to open the file for appending, ie, data will be written at the end of the file. If the file does not exist, it is created. You're currently opening the file in "read only" mode & will not be able to write to it at all. Read about the different mode strings fopen takes here.
Your check to see if the file pointer is NULL is also redundant. You have passed no block to the 'if' to run when the pointer is not NULL. It should be something like:
if (!pFile) {
puts("Something went wrong");
exit(1);
}
Finally, fputs takes a STRING value, ie, a character constant. It will refuse to work with enter_this because it is an integer. One way to write the integer to your file is to use fprintf. For example:
/* Write the integer enter_this & a newline to pFile */
fprintf(pFile, "%d\n", enter_this);