My code compiles just fine but when I run it I get bus error: 10
void backupf(char *namelist, char *dirname)
{
char *in_filename;
char *out_filename;
char line[MAXPATHLEN];
FILE *filenames = fopen(namelist, "r");
if(filenames == NULL)
{
fprintf(stderr, "Cannot Open File\n");
exit(EXIT_FAILURE);
}
while( fgets(line, sizeof line, filenames) != NULL )
{
sprintf(in_filename, "./%s\n", line);
sprintf(out_filename, "%s/%s\n", dirname, line);
}
backup(dirname, in_filename, out_filename);
fclose(filenames);
}
It's supposed to take a text file argument with a list of file names and then use that information to back it up to a backup directory using a backup function I've written.
You don't allocate space for the file names; you should. You're writing over indeterminate memory. This would probably work better:
void backupf(char *namelist, char *dirname)
{
char in_filename[MAXPATHLEN];
char out_filename[MAXPATHLEN];
char line[MAXPATHLEN];
FILE *filenames = fopen(namelist, "r");
if (filenames == NULL)
{
fprintf(stderr, "Cannot Open File\n");
exit(EXIT_FAILURE);
}
while (fgets(line, sizeof(line), filenames) != NULL)
{
snprintf(in_filename, sizeof(in_filename)"./%s\n", line);
snprintf(out_filename, sizeof(out_filename), "%s/%s\n", dirname, line);
backup(dirname, in_filename, out_filename);
}
fclose(filenames);
}
Related
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.
I have a function in the program that has to remove a given string from a file. To do this, rewrites the entire file into a temporary file and then overwrites the original file.
Saving a temporary file with the removed string works, but overwriting the original file does't work.
What's wrong here?
#define MAXCHAR 10000
void delPath(char stringToDelete[], char bashrcDir[]) {
FILE *bashrc = fopen(bashrcDir, "r+");
char str[MAXCHAR];
if (bashrc != NULL) {
FILE *tempfile = fopen("./tempFile.txt", "w+");
// Create tempFile and copy content without given string
while (fgets(str, MAXCHAR, bashrc) != NULL) {
if (!strstr(str, stringToDelete)) {
fprintf(tempfile, "%s", str);
}
}
// Read tempFile and overwrite original file - this doesn't work
while (fgets(str, MAXCHAR, tempfile) != NULL) {
fprintf(bashrc, "%s", str);
}
fclose(tempfile);
}
fclose(bashrc);
}
r+ allows you to read the file and overwrite it. I'm wrong?
Referring to #KamilCuk answer, here's the solution:
#define MAXCHAR 10000
void delPath(char stringToDelete[], char bashrcDir[]) {
FILE *bashrc = fopen(bashrcDir, "r");
char str[MAXCHAR];
if (bashrc != NULL) {
FILE *tempfile = fopen("./tempFile.txt", "w");
while (fgets(str, MAXCHAR, bashrc) != NULL) {
if (!strstr(str, stringToDelete)) {
fprintf(tempfile, "%s", str);
}
}
fclose(bashrc);
fclose(tempfile);
FILE *newTempfile = fopen("./tempFile.txt", "r");
FILE *newBashrc = fopen(bashrcDir, "w");
while (fgets(str, MAXCHAR, newTempfile) != NULL) {
fprintf(newBashrc, "%s", str);
}
fclose(newTempfile);
fclose(newBashrc);
remove("./tempFile.txt");
}
}
Thanks!
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);
}
}
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.
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;
}