Adding a file close statement causes a seg fault - c

When trying to close the file after reading it, I get a seg fault on running the program.
int inputDirectory()
{
char fileName[64];char directoryBuffer[256];FILE *fp;
printf("\n> Please type the filename containing the list of directories. >");
inputFix(fileName, sizeof(fileName));
fp = fopen(fileName,"r");
if(access(fileName, F_OK) == 0)
{
if (fp == 0)
{
printf("> Error opening file.");
return 1;
}
else
{
if (access(fileName, R_OK) == 0)
{
while (fgets(directoryBuffer, sizeof(directoryBuffer), (FILE*)fp))
{
readCheck(directoryBuffer);
printf("%s \n", directoryBuffer);
getInode(directoryBuffer);
}
}
else
{
printf("\n> File can't be read.");
}
}
}
else
{
printf("\n> File %s does not exist ", fileName);
}
fclose(fp);
return 0;
}
void inputFix(char string[],int length)
{
int ch, len = 0;
fgets(string, length, stdin);
string[strcspn(string, "\r\n")] = '\0';
len = strlen(string);
if (len == length - 1)
{
while((ch = getchar()) != '\n' && ch != EOF);
}
}
void readCheck(char string[])
{
string[strcspn(string, "\r\n")] = '\0';
}
Ive been reading into race conditions, but from my understanding there isn't one? Is there a need to check to see if the file exists before trying to open it? Is there a need to include some of the checks that I'm using?

Looking at these lines.
if (fp == 0)
{
printf("> Error opening file.");
fclose(fp); // NOT NEEDED. REMOVE THE LINE
}
It seems you don't need to call fclose when you were not able to open the file.
Remove the line.

If fp is null (equal to 0), you do not need to close it, the file was never opened to begin with. You should close fp after you are done successfully reading from it.

You are closing the file at the end regardless of whether the file ever opened or not. Calling fclose on an unopened file can cause a crash. Try this instead. I have moved the fclose statement to be called only when fp is not NULL.
int inputDirectory()
{
char fileName[64];char directoryBuffer[256];FILE *fp;
printf("\n> Please type the filename containing the list of directories. >");
inputFix(fileName, sizeof(fileName));
if(access(fileName, F_OK) == 0)
{
fp = fopen(fileName,"r");
if (fp == NULL)
{
printf("> Error opening file.");
return 1;
}
else
{
if (access(fileName, R_OK) == 0)
{
while (fgets(directoryBuffer, sizeof(directoryBuffer), (FILE*)fp))
{
readCheck(directoryBuffer);
printf("%s \n", directoryBuffer);
getInode(directoryBuffer);
}
}
else
{
printf("\n> File can't be read.");
}
fclose(fp);
}
}
else
{
printf("\n> File %s does not exist ", fileName);
}
return 0;
}

Only call fclose() on a FILE* which had been returned by a successful call to fopen().
To test wether fopen() had been successful compare its result against NULL. If this test succeeds the call had not been successful:
#include <stdio.h>
int main(void)
{
char filename[] = "myfile";
FILE * fp = fopen(filename, "r");
if (NULL == fp)
{
fprintf(stderr, "fopen(\"%s\", ...) failed.\n", filename);
}
else
{
fprintf(stderr, "fopen(\"%s\", ...) succeeded.\n", filename);
/* Perform operation on fp here. */
fclose(fp);
}
return 0;
}

Related

Running is fine but rename() does not work

Simple function code to delete a line from a text file by making a temporary text file that will store the new content once the line has been deleted and replacing the old Storage.txt file with the temporary file.
The delete() function works but my only problem seems to be the rename() function that seemingly won't do as intended.
THE CODE
void delete() {
struct task task;
FILE *fp;
char str[100];
char ch;
int delete_line = 0;
fp = fopen("Storage.txt", "r");
if (fp == NULL) {
printf("Error opening file");
fopen("Storage.txt", "w");
exit (1);
}
printf("\n\n\nAll Tasks\n");
printf("----------\n\n");
do {
ch = fgetc(fp);
printf("%c", ch);
} while (ch != EOF);
fclose(fp);
int line_no,ret;
char filename[] = "Storage.txt";
char newname[] = "temp.txt";
FILE *file, *temp;
file = fopen("Storage.txt", "r");
temp = fopen("temp.txt", "w");
printf("Select Line to delete: ");
scanf("d", &delete_line);
getchar();
temp = fopen("temp.txt", "w");
while (fgets(str, 99, fp) != NULL) {
line_no++;
if (line_no != delete_line) {
fputs(str, temp);
}
}
fclose(file);
fclose(temp);
remove(filename);
ret = rename(newname, filename);
if (ret == 0) {
printf("File renamed successfully");
} else {
printf("Error: unable to rename the file");
}
}
There are some problems in the code:
ch must be defined with type int to detect EOF reliably.
the do/while loop to read the file contents outputs the EOF indicator before testing it. You should use while ((ch = fgetc(fp)) != EOF) putchar(ch);
the identifier delete should be avoided to avoid confusing C++ programmers, use delete_line instead.
you should test for failure of fopen and remove and display the cause of the error.
if opening the file for reading fails, why do you create the file with fopen("Storage.txt", "w") ?
file temp.txt is open twice, which may prevent the rename operation on legacy systems.
line_no is not initialized. It should be initialized to 1 if lines are numbered starting at 1.
reading lines into an array is not reliable for this task as lines longer than 99 bytes will be counted more than once.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void delete_line() {
const char *filename = "Storage.txt";
const char *tempname = "temp.txt";
int ch;
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "Cannot open file %s: %s\n", filename, strerror(errno));
exit(1);
}
printf("\n\n\nAll Tasks\n");
printf("----------\n\n");
while ((ch = getc(fp)) != EOF) {
putchar(ch);
}
fclose(fp);
int delete_line = 0;
printf("Select Line to delete: ");
if (scanf("d", &delete_line) != 1) {
fprintf(stderr, "invalid or missing input\n");
exit(1);
}
// read and discard the rest of the user input line
while ((ch = getchar()) != EOF && c != '\n')
continue;
FILE *file = fopen(filename, "r");
if (file == NULL) {
fprintf(stderr, "Cannot open file %s: %s\n", filename, strerror(errno));
exit(1);
}
FILE *temp = fopen(tempname, "w");
if (temp == NULL) {
fprintf(stderr, "Cannot open file %s: %s\n", tempname, strerror(errno));
fclose(file);
exit(1);
}
int line_no = 1;
while ((ch = getc(file)) != EOF) {
if (line_no != delete_line)
putc(ch, temp);
if (ch == '\n')
line_no++;
}
fclose(file);
fclose(temp);
if (remove(filename)) {
fprintf(stderr, "Cannot remove %s: %s\n", filename, strerror(errno));
} else {
if (rename(tempname, filename)) {
fprintf(stderr, "Cannot rename %s as %s: %s\n",
tempname, filename, strerror(errno));
}
}
}
Your code opens the "temp.txt" file twice:
temp = fopen("temp.txt", "w");
...
temp = fopen("temp.txt", "w");
And closes it once. That will leave one open file descriptor to the file, untill the program exits.
remove() uses unlink() for deleting files. The man page of unlink() says:
If the name was the last link to a file but any processes still have
the file open the file will remain in existence until the last file
descriptor referring to it is closed.
Ensure that all file descriptors are closed when not needed anymore.
The rename may fail, if file of oldpath or newpath is still open.
temp = fopen("temp.txt", "w"); Call it twice
The two main bugs here are:
1.
scanf("d", ...) instead of
scanf("%d", ...)
scanf() needs a format string to know how to parse the input, just like printf() (the f is for format) needs it to know how to construct the output; and their format string syntax is almost the same.
2.
Unintialized line_no, meaning that it's not guaranteed to start at 0/1, thus it might not ever be equal to delete_line, and will not delete the line.

Fopen Fails to read from Command line

Fopen return NULL based on
'fopen' return a NULL
now I have one file to read and I want to output on console but it throws an error as fp return NULL here a snippet
#include<stdio.h>
int main(char argc,char **argv)
{
if(argc < 2)
{
printf("Usage:\t");
printf("Hash File path");
}
printf("Hash File : %s\n", argv[1]);
FILE *fp = fopen("argv[1]","r");
if(fp == NULL)
{
fprintf(stderr,"Can't open %s\n", argv[1]);
}
else
{
char buff[100];
while(!feof(fp))
{
if(fgets(buff,100,fp) == NULL) break;
fputs(buff,stdout);
}
fclose(fp);
}
return 0;
}
whenever I pass file Path E:\design\test.txt from the command line it always shows error report "Can't open...." like this
so the confusion is
why Fopen Failed to read from Command line?
There are few issues in code. Firstly, this
FILE *fp = fopen("argv[1]","r");
is wrong. First parameter of fopen() should be just argv[1] instead of "argv[1]". For e.g
FILE *fp = fopen(argv[1],"r");
if(fp == NULL) {
fprintf(stderr,"Can't open %s\n", argv[1]);
return 0; /* this you forgot, if fopen fails,then no need to proceed further */
}
Also if argc<2 is true then just wrinting printf() is not enough, you have to ask user to give correct command line input & don't let user proceed further. It should be
if(argc < 2) {
printf("Usage:\t");
printf("Hash File path");
return 0; /* return from here or use exit(0) */
}
Secondly, Read here why feof() is wrong. You can use it like
while(fgets(buff,100,fp) != NULL) { /* no need to use break */
fputs(buff,stdout);
}
instead of
while(!feof(fp))
{
if(fgets(buff,100,fp) == NULL) break;
fputs(buff,stdout);
}

Copying Only Part of a File to a New One in C

I have a practice question in C that asks me to create a function that only copies part of a file to another one. The restrictions are that lines with greater than maxlen characters are not copied to the new file, and the newline character does not count, so it should not be copied. Part of my function says that if a file does not exist, it should explicitly say so, and I am getting those error messages when I run that code; however, I can see that the files are created are inside my folder. Whenever I open the file I'm trying to read after running the code, I get this:
./Debug/main.c.o ./Debug/dot.c.o ./Debug/dataBase.c.o ./Debug/intPrompt.c.o ./Debug/numWords.c.o ./Debug/LinkedList.c.o
Below is my code :
void shortLines(char* f1, char* f2, int maxlen) {
FILE* fp = fopen(f1, "r");
FILE* fp2 = fopen(f2, "w");
if (fp == NULL) {
perror("File does not exist");
}
if (fp2 == NULL) {
perror("File does not exist");
}
char singleLine[maxlen];
char check;
size_t len;
do {
fgets(singleLine, maxlen, fp);
len = strlen(singleLine);
if (singleLine[len-1] == '\n') {
singleLine[len-1] = '\0';
}
fprintf(fp2, "%s", singleLine);
} while ((check=getc(fp) != EOF));
}
int main(int argc, char **argv) {
shortLines("Andrew.txt", "Andrew2.txt", 25);
return 0;
}
I just made new files called Andrew.txt and Andrew2.txt and these ones seem to be working for some strange reason. Regardless, there were a few problems in the code. First of all, after fgets is called, I needed to make sure to flush out the remaining characters in the line. I do this with a while loop and fgetc. If I reach an EOF, then I continue, and then fgets also returns an EOF, thus breaking the outer loop.
void shortLines(char* f1, char* f2, int maxlen) {
FILE* fp = fopen(f1, "r");
FILE* fp2 = fopen(f2, "w");
if (fp == NULL) {
perror(f1);
}
if (fp2 == NULL) {
perror(f2);
}
char line[maxlen+1];
size_t len;
char c;
while (fgets(line, maxlen+1, fp) != NULL) {
len = strlen(line);
if (len == maxlen) {
while ((c=fgetc(fp)) != '\n') {
if (feof(fp)) {
break;
}
}
continue;
}
if (line[len-1] == '\n') {
line[len-1] = '\0';
}
fprintf(fp2, "%s\n", line);
}
}

C Why can't my fgets() read line properly when writing with \n after words

This is a bit difficult to articulate but what I would like is for my commented out fprintf function to be commented in and my other two print functions commented out (In my add_to_white_list function).
However, when I write to the file in that way (with the \n after the word) something goes wrong with my fgets line reader in the remove_from_white_list function. In debugging my fgets reads the first line and then seems to be blank after.
This if very confusing to me because everything mostly works as is and there are still newline characters after all my words except for the last word in the file.
void add_to_white_list(char* ip) {
FILE *fp;
fp = fopen("../app/whitelist.txt", "r+");
if (!(getc(fp) < 0)) {
fseek(fp, 1, SEEK_END);
fputs("\n", fp);
}
fprintf(fp, "%s", ip);
//fprintf(fp, "%s\n", ip);
fclose(fp);
}
void remove_from_white_list(char* ip) {
FILE *fp;
FILE *fp_temp;
fp = fopen("../app/whitelist.txt", "r");
fp_temp = fopen("../app/temp.txt", "w+");
char buff[255];
int matched = 0;
while (fgets(buff, 255, fp) != NULL) {
strip(buff);
if (!(strcmp(buff, ip) == 0)) {
fprintf(fp_temp, "%s\n", buff);
} else {
matched = 1;
}
}
fclose(fp);
fclose(fp_temp);
if (matched == 0) {
printf("Please supply an ip address that is currently listed on the whitelist\n");
} else {
rename("../app/temp.txt", "../app/whitelist.txt");
}
}
*I didn't include my strip function but it removes \n
This may not fix your problem but you can simplify add_to_white_list to:
void add_to_white_list(char* ip) {
FILE *fp = fopen("../app/whitelist.txt", "a");
if ( fp != NULL )
{
fprintf(fp, "%s\n", ip);
fclose(fp);
}
}

Read the next line of a file every time a function is called

I have a text file with numbers on each line. I want to write a function in C that reads in the file and returns the next number in the file every time the function is called.
For example if I have these numbers:
100
200
300
400
and a function called get_number(), if I call get_number() it will return 100, if I call it again, it will return 200, etc.
This is what I've written so far but every time the function is called, it always goes back to the first number in the text file.
int * get_number()
{
FILE* file = fopen("random_numbers.txt", "r");
char line[256];
if (file==NULL)
{
perror ("Error reading file");
}
else
{
fgets(line, sizeof(line), file);
printf("%s", line);
}
return 0;
}
here's a version that does exactly that :
int * get_number(long* pos)
{
FILE* file = fopen("random_numbers.txt", "r");
char line[256];
if (file==NULL)
{
perror ("Error reading file");
}
else
{
fseek(file , *pos , SEEK_CUR);
fgets(line, sizeof(line), file);
printf("%s", line);
}
*pos = ftell(file);
return 0;
}
and you call it from main like this
long pos = 0;
get_number(&pos);
or better yet use a static variable
int * get_number()
{
static long pos = 0;
FILE* file = fopen("random_numbers.txt", "r");
char line[256];
if (file==NULL)
{
perror ("Error reading file");
}
else
{
fseek(file , pos , SEEK_CUR);
fgets(line, sizeof(line), file);
printf("%s", line);
}
pos = ftell(file);
return 0;
}
It's a good idea to avoid opening a file repeatedly. Instead of opening the file every time you call the function, open it once, then pass a file pointer to the function each time you call it.
int * get_number(FILE *file)
{
char line[256];
fgets(line, sizeof(line), file);
printf("%s", line);
return 0;
}
int main()
{
FILE *file = fopen("random_numbers.txt", "r");
if (file == NULL)
{
perror("Error opening file");
return 1;
}
while (!feof(file))
{
get_number(file);
}
fclose(file);
}
Open the file in the calling function.
Pass the FILE* to get_number.
Return an int from get_number, not an int*.
Here's a modified get_number.
int get_number(FILE* file)
{
// This is the core functionality.
// You should add error handling code
int number;
int n = fscanf(file, "%d", &number);
if ( n != 1 )
{
// Add error handling code.
}
return number;
}
This is normal, because you open your file each time you call get_number(); (this is even worse because no fclose are called.
What you want maybe is giving a file descriptor at get_number(); in this way :
void get_number(FILE* file)
{
char line[256];
if (file==NULL)
perror ("Bad descriptor given");
else
{
if (fgets(line, sizeof(line), file) == NULL)
perror("Fgets failed");
else
printf("%s", line);
}
}
And what you want, outside your function, is to do the following :
FILE * file = fopen("random_numbers.txt", "r");
get_number(file); // 100
get_number(file); // 200
fclose(file);
I made your function void, because the return here is pointless. You could change that and use atoi and the return fonction.

Resources