I'm writing a simple code on Linux that writes into a file. That file will be stored in specific path ( not the same path where the executable is located ).The problem is that when I execute the code , the program is terminating with segmentation fault (core dump)
Here is my code :
#include <stdio.h>
int main ()
{
FILE * pFile;
char buffer[] = { 'x' , 'y' , 'z' };
pFile = fopen ("/home/medwajih/Desktop/bufferfile/buffer.txt", "wb");
fwrite (buffer , sizeof(char), sizeof(buffer), pFile);
fclose (pFile);
return 0;
}
Note that the exe of the program is in "/home/medwajih/Desktop/" and the location where I want to create the buffer.txt file is "/home/medwajih/Desktop/bufferfile/"
Thank you.
If the fopen fails (such as if the /home/medwajih/Desktop/bufferfile directory does not exist, or the file exists but has permissions that disallow you replacing it), then pFile will be set to NULL.
Attempting to use it is then undefined behaviour.
You should generally check all calls that may fail to ensure they don't cause issues later on, such as with:
pFile = fopen ("/home/medwajih/Desktop/bufferfile/buffer.txt", "wb");
if (pFile == NULL) {
fprintf (stderr, "Could not create file\n");
return 1;
}
If the problem is actually that the directory does not exist, you can call mkdir beforehand. And, of course, check the return value of that as well :-)
If it's something else (there's not really enough information in the question to ascertain what it is), you need to find a different way to rectify the problem.
Related
I'm trying to read a binary file of 32 bytes in C, however I'm keep getting "segmentation fault (code dumped)" when I run my program,
it would be great if somebody can help me out by pointing where did I go wrong?.
my code is here below:
int main()
{
char *binary = "/path/to/myfiles/program1.ijvm";
FILE *fp;
char buffer[32];
// Open read-only
fp = fopen(binary, "rb");
// Read 128 bytes into buffer
fread (buffer, sizeof(char), 32, fp);
return 0;
}
It's because of the path. Make sure that "/path/to/myfiles/program1.ijvm" points to an existing file.
You should always check the return value of fopen.
\\Open read-only
fp = fopen(binary, "rb");
if(fp==NULL){
perror("problem opening the file");
exit(EXIT_FAILURE);
}
Notice also that you are reading 32 bytes in your buffer and not 128 as your comment says.
You must check the return result from fopen().
I'm assuming you are getting the segfault in the fread() call because your data file doesn't exist, or couldn't be opened, and you are trying to work on a NULL FILE structure.
See the following safe code:
#include <stdio.h>
#include <stdint.h>
#define SIZE_BUFFER 32
int main()
{
char *binary = "data.txt";
FILE *fp = NULL;
char buffer[SIZE_BUFFER];
// Open read-only
fp = fopen(binary, "rb");
// Read SIZE_BUFFER bytes into buffer
if( fp )
{
printf("Elements read %ld\n", fread (buffer, sizeof(char), SIZE_BUFFER, fp));
fclose(fp);
}
else
{
// Use perror() here to show a text description of what failed and why
perror("Unable to open file: ");
}
return 0;
}
When I execute this code it doesn't crash and will print the number of elements read if the file is opened or it will print "Unable to open file" if the file could not be opened.
As mentioned in the comments you should also close the file being exiting. Another thing you can do is the following:
FILE *fp = fopen(.....);
Instead of declaring and assigning in two separate steps.
There are two possible reasons
The fopen(3) function failed due to some reason, which means fp is NULL, and then you are trying to use the null-pointer in fread(3). This can crash. #OznOg has already given a subtle hint to look into this direction.
If the fopen call is a success (i.e. fp is non-NULL after calling fopen), the code can still crash because you are reading 32 chars into the variable binary, while binary has been initialized with only 30 chars.
The following is my code for a method that copies a file from a path to a file to a directory provided as the destination. The copy works perfectly fine, however my chmod call assigns the wrong permissions to the copied file in the destination. If the permission in the source is 644, the copied file has a permission of 170 or 120.
I have been attempting to debug this for hours and it's driving me slightly crazy so any help is greatly appreciated.
void copy_file(char* src, char* dest) {
char a;
//extract file name through a duplicate ptr
char* fname = strdup(src);
char* dname = basename(fname);
//open read and write streams
FILE* read;
FILE* write;
read = fopen(src, "r");
chdir(dest);
write = fopen(dname, "w");
//error checking
if (read == NULL) //|| (write == NULL))
{
perror("Read Error: ");
exit(0);
}
else if (write == NULL)
{
perror("Write Error: ");
exit(0);
}
//write from src to dest char by char
while (1){
a = fgetc(read);
if (a == EOF)
{
break;
}
fputc(a, write);
}
//close files
fclose(read);
fclose(write);
// this is where I attempt to assign source file permissions
//and it goes horribly wrong
struct stat src_st;
if(stat(src, &src_st)){
perror("stat: ");
}
chmod(dname, src_st.st_mode);
printf("%o\n", src_st.st_mode & 0777);
}
You fopen(src, "r"), then you chdir(dest). This means that when you later call stat(src, &src_st), there is no reason to think that stat will access the same file as fopen did, or indeed that stat will access any file at all.
If stat fails, you proceed to call chmod anyway, so you pass whatever random junk was in src_st.st_mode to chmod.
You should use fstat(fileno(read), &src_st) before calling fclose(src), instead of calling stat(src, &src_st).
The basic problem is you have to check your system calls like fopen, chdir, and stat immediately.
For example, first thing I tried was copy_file( "test.data", "test2.data" ) not realizing it expected a destination directory.
char* fname = strdup(src);
char* dname = basename(fname);
dname is now test.data, same as the source.
read = fopen(src, "r"); // succeeds
chdir(dest); // fails
write = fopen(dname, "w"); // blows away test.data, the source
You do eventually check read and write, but after the damage has been done.
Blowing away your source file is really bad. It's important that your code deals with failed system calls. If you don't, it will sail along causing confusion and destruction.
Most system calls in C return 0 for success. This is an anti-pattern where the return value is an error flag, so false is failure, and anything else indicates what kind of error (though stat doesn't use that, it uses errno).
When it fails, stat returns -1 which is true. So this is the wrong way around.
struct stat src_st;
if(stat(src, &src_st)){
perror("stat: ");
}
Instead, you have to check for non-zero.
struct stat src_st;
if(stat(src, &src_st) != 0 ){
// Note that I don't use perror, it doesn't provide enough information.
fprintf(stderr, "Could not stat %s: %s\n", src, strerror(errno));
exit(1);
}
As you can guess this gets tedious in the extreme, and you're going to forget, or do it slightly different each time. You'll want to write wrappers around those functions to do the error handling for you.
FILE *fopen_checked( const char *file, const char *mode ) {
FILE *fp = fopen(file, mode);
if( file == NULL ) {
fprintf(stderr, "Could not open '%s' for '%s': %s", file, mode, strerror(errno));
exit(1);
}
return fp;
}
It's not the best error handling, but it will at least ensure your code appropriately halts and catches fire.
A note about chdir: if you can avoid it don't use it. chdir affects the global state of the program, the current working directory, and globals add complexity to everything. It's very, very easy for a function to change directory and not change back, as yours does. Now your process is in a weird state.
For example, if one did copy_file( "somefile", "foo" ) this leaves the program in foo/. If they then did copy_file( "otherfile", "foo" ) they'd be trying to copy foo/otherfile to foo/foo/otherfile.
And, as #robmayoff pointed out, your stat fails because the process is now in a different directory. So even the function doing the chdir is confused by it.
Ensuring that your functions always chdir back to the original directory in a language like C is very difficult and greatly complicates error handling. Instead, stay in your original directory and use functions like basename to join paths together.
Finally, avoid mixing your file operations. Use filenames or use file descriptors, but try not to use both. That means if you're using fopen, use fstat and fchmod. You might have to use fileno to get a file descriptor out of the FILE pointer.
This avoids having to carry around and keep in sync two pieces of data, the file descriptor and the filename. It also avoids issues with chdir or the file being renamed or even deleted, the file descriptor will still work so long as it remains open.
This is also a problem:
char a;
...
while (1){
a = fgetc(read);
if (a == EOF)
{
break;
}
fputc(a, write);
}
fgetc() returns int, not char. Per the C Standard, 7.21.7.1 The fgetc function:
7.21.7.1 The fgetc function
Synopsis
#include <stdio.h>
int fgetc(FILE *stream);
Assuming sizeof( int ) > sizeof( char ), char values are signed, 2s-complement integers, and EOF is an int defined to be -1 (all very common values), reading a file with char a = fgetc( stream ); will fail upon reading a valid 0xFF character value. And if your implementation's default char value is unsigned char, char a = fgetc( stream ); will never produce a value that matches EOF.
This seems to be a really simple one, but I can't figure it out after not touching C programming in four years.
I was trying to open a file in main()
int main(int argc, const char * argv[])
{
FILE * fp = fopen("data.txt","r");
...
return(0)
}
The program compiled, but when I tried to run it in gdb, the following error occurs.
Program received signal SIGSEGV, Segmentation fault.
0x00000000004016c6 in main ()
when the program is trying to open the file "data.txt". What could cause the error? Thanks!
I suspect your error lies in this bit of code:
...
In other words, there's nothing in the other code shown that appears to be wrong.
The most likely case is that the file doesn't exist, or it doesn't exist in the directory where the program is running (which, if you're in an IDE, usually turns out to be somewhere other than you think it is).
And, in that case, you're getting NULL from the fopen, then later using it, something like:
FILE *fp = fopen ("no_such_file.txt", "r");
int ch = fgetc (fp);
You should generally check return values from all functions that use them to indicate success or failure:
#include <stdio.h>
int main (void) {
FILE *fp = fopen ("no_such_file.txt", "r");
if (fp == NULL) {
perror ("Opening no_such_file.txt");
return 1;
}
// You can use fp here.
puts ("It worked.");
fclose (fp);
return 0;
}
What could cause the error?
The most likely cause of the error is that the file data.txt could not be opened (e.g. because it doesn't exist, or it's not in the current directory, or your program doesn't have permission to read it). That will cause fopen() to return NULL. Then if your code (in the ... section) tries to call fread() or fgets() or whatever and passes in the NULL pointer, that will cause a crash. You need to check the value returned by fopen() to make sure it is non-NULL before trying to use it.
Okay so this is probably has an easy solution, but after a bit of searching and testing I remain confused.. :(
Here is a snippet of the code that I have written:
int main(int argc, char *argv[]){
int test;
test = copyTheFile("test.txt", "testdir");
if(test == 1)
printf("something went wrong");
if(test == 0)
printf("copydone");
return 0;
}
int copyTheFile(char *sourcePath, char *destinationPath){
FILE *fin = fopen(sourcePath, "r");
FILE *fout = fopen(destinationPath, "w");
if(fin != NULL && fout != NULL){
char buffer[10000];//change to real size using stat()
size_t read, write;
while((read = fread(buffer, 1, sizeof(buffer), fin)) > 0){
write = fwrite(buffer, 1, read, fout);
if(write != read)
return 1;
}//end of while
}// end of if
else{
printf("Something wrong getting the file\n");
return 0;}
if(fin != NULL)
fclose(fin);
if(fout != NULL)
fclose(fout);
return 0;
}
Some quick notes: I am very new to C, programming, and especially file I/O. I looked up the man pages of fopen, fread, and fwrite. After looking at some example code I came up with this. I was trying to just copy a simple text file, and then place it in the destination folder specified by destinationPath.
The folder I want to place the text file into is called testdir, and the file I want to copy is called test.txt.
The arguments I have attempted to use in the copyFile function are:
"test.txt" "testdir"
".../Desktop/project/test.txt" ".../Desktop/project/testdir"
"/Desktop/project/test.txt" "/Desktop/project/testdir"
I just get the print statement "Something wrong getting the file" with every attempt. I am thinking that it may be because 'testdir' is a folder not a file, but then how would I copy to a folder?
Sorry if this a really basic question, I am just having trouble so any advice would be awesome!
Also, if you wanted to be extra helpful, the "copyTheFile" function is supposed to copy the file regardless of format. So like if its a .jpg or something it should copy it. Let me know if any of you guys see a problem with it.
This is with ISO/POSIX/C89/C99 on Linux.
At the start, you'll want to include stdio.h to provide FILE and the I/O function declarations:
#include <stdio.h>
Aside from this, your program compiles and works properly for me. Unfortunately you can't copy to a directory without using stat() to detect if the destination is a directory, and if so, appending a file name before opening the file.
Some other minor suggestions:
A buffer with a power of two bytes such as 4096 is probably more efficient due to it lining up with filesystem and disk access patterns
Conventionally, C functions that return a status code use 0 for success and other values such as 1 for failure, so swapping your return values may be less confusing
When a standard library function such as fopen, fread or fwrite fails, it is a good idea to use perror(NULL); or perror("error prefix"); to report it, which may look something like:
$ ./a.out
...
error prefix: No such file or directory
if you are trying to write a new file in a directory, you should be giving the full path of the file to be written. in your case
"C:...\Desktop\project\testdir\testfile"
I'm working on a simple file splitter/merger program in the C programming language. The problem is, for some reason fopen returns NULL, and because of that, my program is crashing at the fwrite statement. How do I fix this?
Here is the C file:
int SplitFile(char* filename, char* output, size_t size)
{
char current_file_name[256];
int file_count = 0, i = 0;
FILE *file = fopen( filename, "rb" );
printf("split %s into chunks of %d named\n", filename, size);
if (!file)
return E_BAD_SOURCE;
else
{
output = (char *) malloc(size * sizeof(char));
if (output == NULL)
return E_NO_MEMORY;
else
{
int bytes_read = 0;
FILE *outFile;
do
{
bytes_read = fread(output, sizeof(char), size, file );
sprintf(current_file_name, "%s%04lu\n", "part", file_count++);
outFile = fopen (current_file_name, "wb" ); // THIS RETURNS NULL
fwrite(output, sizeof(char), bytes_read, outFile); //CRASHES ON THIS LINE
}
while ( bytes_read > 0 )
;
//fclose(outFile);
}
}
fclose(file);
printf("...\n");
return 0;
}
The proper thing to do is check errno when fopen returns NULL.
I'm going to guess that your problem is that you're trying to write to a filesystem that doesn't allow \n in filenames, but it could be a permissions issue as well.
There are many reasons fopen can return NULL including (but certainly not limited to):
The file doesn't exist
The file is opened in a mode that doesn't allow other accesses
The network is down
The file exists, but you don't have permissions
A file exists with the name you gave, but the current directory of the process is not what you expected so the relative pathname fails to find and open the file.
The way to find out which is responsible is to dig into the errno code.
However just because you resolve this particular error doesn't mean you can assume fopen will never return NULL. When dealing with I/O operations your code simply has to expect failure. It's not possible to predict the success of I/O operations, and they can always fail.
It means that the file might not exist or some permission error occurred while accessing a file such as "Read-Only" or "Write-Protected", so in those cases fopen will return 0 (a NULL pointer). On success it will return a file pointer as a handler.
fp=fopen("c:\\ABC.txt", "r"); cannot be the same as fp=fopen("c:\\abc.txt", "r");.
Use // instead of \\ in a Linux environment.
P.S.: In Linux and Unix-like operating systems file names are case-sensitive.
Is fopen for write return NULL in the first run?
I noticed that in the while you keep open files for write but not closing them.
Try to add fclose(outFile) after fwrite:
outFile = fopen ( current_file_name , "wb" );
fwrite(output, sizeof( char ), bytes_read, outFile);
fclose(outFile)
It is possible you open more files than your OS allows.
In Unix, for fopen(), there is no reason to prepend ./ to a filename passed to fopen().
In my case, i was reading the same file all over again in a while loop and forgot to close it.
I used a function for reading the file and finding a match and the function had a return; statement that terminated the function before doing fclose(fp) :D
The path given for the file is checked from wherever the executable is present.
In my case I was opening the text file in c file when both were present at the same place.
It was continuously giving the error of file not found.
Placed the file in the folder of executable and it started working.
In my case, it was because I was trying to create the file in a directory that does NOT exist.