I've been looking around for like 4hours and cannot find where the problem is.
I got this function over here which is supposed to open a file.
In the function I successfully get into the != NULL condition thus returning 1, then in the main the value of my pointer test_file_1 is null (and then segfault when fclose)
I do not understand why because I am assigning the return value of fopen to my pointer !!
Here is the prototype :
/*
* Open a file and save its file pointer into file_to_load
* If it worked, returns 1
* Else, 0
*
* Prints its own error message, so you only have to use the return
* value to set the program behavior as wished
*
* filename : name of the file (+ path if needed)
* file_to_load : the file to be loaded
*
*/
int load_file(char* filename, FILE* file_to_load);
And here is the function by itself :
int load_file(char* filename, FILE* file_to_load)
{
//r is for read-only mode, we do not want to let the program edit the file
//We will only save when told (using save_file)
if( (file_to_load = fopen(filename, "r")) != NULL )
{
return 1;
}
else
{
fprintf(stderr, THE_FILE);
fprintf(stderr, filename);
fprintf(stderr, CANT_BE_OPENED);
// Should include the error number for convenience
return 0;
}
}
And .. here is the use in the main :
FILE* test_file_1 = NULL;
//Closed only if exists or else .. segfault
if ( (load_file("../bin/test", test_file_1)) == 1)
{
fclose(test_file_1);
}
C is pass-by-value, not pass-by-reference.
That means a function always gets a copy of its arguments, and changing its copy has no effect on the expression used on calling.
Use additional indirection, here the modified lines (each has exactly one * or & more):
int load_file(char* filename, FILE** file_to_load);
int load_file(char* filename, FILE** file_to_load)
if( (*file_to_load = fopen(filename, "r")) != NULL )
if ( (load_file("../bin/test", &test_file_1)) == 1)
BTW: It would be better to return the file as the return-value, unless you need the return-value for something else or there are other reasons not shown in the example.
Here is a simple program which pretty much does what you want.
int load_file(char *filename, FILE *file_to_load){
file_to_load = fopen(filename, "r");
if(file_to_load !=0)
return 1;
else
return 0;
}
int main(int argc, char *argv[]){
FILE file_to_load;
if(load_file(argv[1],&file_to_load) == 1)
printf("File exists\n");
else
printf("Error loading the given file\n");
}
I have taken the file as a command line argument and changed the error messages but you can alter it according to your requirements.
Related
So I am writing a program in C that takes in a few command-line arguments and also reads a file and prints it to standard out. This is my code thus far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( int argc, char* argv[] ) {
char* file_path;
float a;
float b;
char filedata[200];
if (argc != 4) {
printf("Error: 4 arguments are required.\n");
return -1;
}
file_path = argv[1];
a = atof(argv[2]);
b = atof(argv[3]);
if( a == 0.0 ) {
printf("Error: bad float arg\n");
return -1;
}
if( b == 0.0 ) {
printf("Error: bad float arg\n");
return -1;
}
FILE* fp = fopen( file_path, "r");
if( fp == NULL ){
printf( "Error: bad file; %s\n", file_path);
return -1;
}
while( fgets( filedata, 200, fp ) ){
printf("%s", filedata);
}
fclose(fp);
}
At the very bottom I have began to read a file. What I am trying to do is find files that contain the characters "#A#" and "#B#" and then print an error message when files containing these characters are not present.
Unfortunately, a simple if statement will not work in this scenario as I am not checking for equality but rather whether or not something is present.
If anybody could tell me about any C functions that are able to read and check the contents of a file, along with a few more specifics, then I would highly appreciate it!
After taking each line (into 'filedata') simply use the strstr function to check if it contains that substring "#A#" etc.
if strstr finds the substring it will return a pointer to it, otherwise it will return a NULL pointer.
So you should write something like this:
if ( strstr(filedata, "#A#") == NULL )
printf("Error\n");
but since you are looking at the entire file for this substring, you need to check all the lines before you conclude that there is an error.
I have a program that should take the file's name from command line using argc and argv. Printing argv[1] and argv[2] show me the exactly names I passed, but passing argv[1] and argv[2] as parameters to open the files in another function just show the error line I put if can't open the file.
My main:
int main(int argc, char* argv[])
{
if (argc != 4)
{
puts("Incorrect number of parameters.");
return 1;
}
else
{
Image *a, *b;
a = OpenFile(argv[1]);
b = OenFile(argv[2]);
} /* else */
return 0;
} /* main */
The function OpenFile will return a struct filled with information from the file. Here's the first part of the function:
Image *OpenFile(char* name)
{
FILE* f = fopen(name, "r");
Image* imagem;
int temp, i, cont, data[MAX];
char aux[2];
if(f == NULL)
{
puts("Error opening file.");
return NULL;
} /* if */
...
}
I'm passing the correct names but I receive the "Error opening file." line for each file I try to open.
Edit: It's giving me "No such file or directory", but I copied the files to the directory where the .exe is placed. It's not the first time I use the file's name from command line, but it's the first time I pass as parameters to another function.
From fopen man page:
RETURN VALUE
Upon successful completion fopen(), fdopen() and freopen() return a FILE pointer. Otherwise, NULL is returned and
errno is set to indicate the error.
So You could change:
if(f == NULL)
{
puts("Error opening file.");
return NULL;
} /* if */
With:
if(f == NULL)
{
perror("fopen");
return NULL;
} /* if */
And you ll get a pretty descriptive message on the reason fopen failed.
You should include errno.h in order to use perror
I'm trying to (as the title says) read from a file into main, using argc and argv, taking the filename from the command line and passing it through main into a void function which opens, reads and writes it. However im getting Cannot open file... Segmentation fault.
void file_pass (char * argv[])
{
FILE *file_name;
if ((file_name = fopen(argv[1], "r")) == NULL)
{
printf("Cannot open file ...\n");
}
fclose(file_name);
}
Which leads me to think it isn't opening the file correctly but I'm not sure why.
In your function void file_pass (char * argv[]) -
if ((file_name = fopen(argv[1], "r")) == NULL)
Instead of this , you should try this -
if ((file_name = fopen(argv[0], "r")) == NULL) // file's name is in argv[0] in funciton
Because array indexing start with 0 and in function argv[1] may contain nothing .
I am trying to read proc file /proc/stat at periodic interval but I want to avoid having to open and close the proc file each time I want to access it.
I want to open the file in sort of init function, and then keep using it in some other function, then close it later on.
It seems file handles opened by a function gets closed when the function exits
How can I keep it open ?
Please let me know if I should be doing it in some other manner
Sample of what I am trying to do:
#include <stdio.h>
int printer(FILE* fin)
{
/* I am getting fin as NULL */
if(!fin)
return 1;
char buf[16*1024];
rewind(fin);
size_t sz = fread(buf, 1, sizeof(buf), fin);
if (sz) {
buf[sz]=0;
printf(buf);
}
return 0;
}
int opener(FILE *fin)
{
fin = fopen("/proc/stat", "r");
if (!fin) {
perror("fopen");
return 1;
}
return 0;
}
int main() {
FILE *fin;
/*
* I know it works if I open the file handle in here instead of
* in another function but I want to avoid this
*/
if(opener(fin))
{
printf("ERROR1\n");
return 0;
}
while(1) {
if(printer(fin))
{
printf("ERROR2\n");
break;
}
sleep(1);
}
return 0;
}
Functions in c are pass by value. So when you pass a file handle to a function, it receives a copy of that handle and will update it locally. If you want those updates to propagate to your caller, you need pass file handle pointers. So your open would look like:
int opener(FILE **fin)
{
*fin = fopen("/proc/stat", "r");
if (!(*fin)) {
perror("fopen");
return 1;
}
return 0;
}
And you would call it like:
int main() {
FILE *fin;
/*
* I know it works if I open the file handle in here instead of
* in another function but I want to avoid this
*/
if(opener(&fin))
{
printf("ERROR1\n");
return 0;
}
/...
}
You need to pass a reference to the pointer to fin in order to keep it in main.
if(opener(&fin)) {}
pass it as double pointer :
int opener(FILE **fin) {}
and use it with derefencing
*fin = fopen("/proc/stat", "r");
otherwise you initiate it everytime you call your subfonction.
The C language passes arguments by value, so the fin that opener has is a copy of the fin that main has. Changing fin in opener has no effect on main's copy.
One solution is to use a temporary file pointer in opener and then return that pointer. To indicate an error, return NULL.
FILE *opener( char *name )
{
FILE *temp = fopen( name, "r" );
if ( !temp )
{
perror( "fopen" );
return( NULL );
}
return( temp );
}
int main( void )
{
FILE *fin = opener( "/proc/stat" );
if ( !fin )
printf( "failed\n" );
else
printf( "fin=%p\n", fin );
}
I created a function to print the contents of a file:
void readFile(char* filename)
{
int c ;
file = fopen(filename, "r");
printf("The contents of the file are:\n");
while((c = fgetc(file)) != EOF)
{
printf("%c", c);
}
return;
}
where file is a global variable. GDB gives output as follows:
_IO_getc (fp=0x0) at getc.c:39
39 getc.c: No such file or directory.
(gdb) bt
#0 _IO_getc (fp=0x0) at getc.c:39
#1 0x000000000040075e in readFile ()
#2 0x00000000004006d4 in main ()
However, the file is present and I get the SEGFAULT after printing the contents of the file. It might be because the buffer here (c) is small but I am not sure. Also, I don't know how do I fix this even if that were the case. Can anyone suggest how do I proceed?
EDIT
I call the readFile function only once. Here is my calling function:
int main(int argc, char* argv[])
{
char * filename;
filename = argv[1];
readFile(filename);
printf("File Handler: %ld", (long)file);
fclose(file);
return 0;
}
You're passing in a filename that doesn't exist or for some other reason cannot be opened. Get rid of the segfault by checking for errors (you'll need to #include <errno.h> and <string.h> too for this:
void readFile(char* filename)
{
int c ;
file = fopen(filename, "r");
if (file == NULL) {
printf("Cannot open file '%s' : %s\n", filename, strerror(errno));
return;
}
printf("The contents of the file are:\n");
while((c = fgetc(file)) != EOF)
{
printf("%c", c);
}
return;
}
Most likely your file is NULL and you are still trying to read it.
I simulated this behaviour (SEG fault) when I deleted this file.
If file exists then your code works fine.
Check what path you are passing.. If you are using single \ try with \\ and see if this works. First \ will work as escape sequence and final path will be send as D:\temp\use.dat to fopen.
readFile("D:\\temp\\user.dat");
Before you do anything with a file, you must ensure that you opened it successfully. This is done by checking that the file pointer received by calling fopen is not NULL.
Once you do this, you read using whatever function you choose until it returns a value that indicates failure to read — a NULL pointer for fgets, 0 or EOF for fscanf, or EOF for fgetc.
In any case, you challenge these return values in two ways. The first way is to check for read errors using ferror. The other way is to check whether the end of the file was reached using feof.
A complete program that should work, based upon your code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
enum { OPEN_ERROR = 1, READ_ERROR };
enum { PARAM_EXIT = 1, OPEN_EXIT, READ_EXIT };
FILE *file = NULL;
int readFile(char* filename)
{
int c;
file = fopen(filename, "r");
if (file == NULL)
return OPEN_ERROR;
printf("The contents of file '%s' are:\n", filename);
while((c = fgetc(file)) != EOF)
printf("%c", c);
/*
* fgetc returns EOF on end of file and when an error occurs.
* feof is used to determine whether the end of the file was reached.
* Otherwise, we encountered a read error.
*/
if (feof(file))
c = 0;
else
c = READ_ERROR;
return c;
}
int main(int argc, char *argv[])
{
int status = 0;
if (argc == 1) {
fprintf(stderr, "usage: %s file\n", argv[0]);
return PARAM_ERROR;
}
/* Check that <program ""> wasn't used... */
if (argv[1][0] == '\0') {
fprintf(stderr, "error: empty filename detected, exiting. . .\n");
return PARAM_ERROR;
}
switch (readFile(argv[1])) {
case 0:
break;
case OPEN_ERROR:
fprintf(stderr, "error: file open failed - %s\n", strerror(errno));
status = OPEN_EXIT;
break;
case READ_ERROR:
fprintf(stderr, "error: file read failed - %s\n", strerror(errno));
status = READ_EXIT;
break;
default:
fprintf(stderr, "error: unknown error occurred, aborting...\n");
abort();
}
if (file != NULL)
fclose(file);
return status;
}
Of course, normally you would close the file in the same function in which it was opened (e.g. something like filep = openFile(...); readFile(filep); fclose(filep);, except error handling would be used of course).
I am completely changing my answer
Actually, the file that I was reading was open in gedit (which might explain why I was getting "NULL" even after printing the file contents. I closed the file and removed my NULL comparison code and it works perfectly fine.
Ok, from everybody's comments I got to know that you basically get a SEGFAULT when you read the contents of file that has NULL contents. I just made a simple fix in my while loop:
while((c != EOF))
{
printf("%c", c);
c = fgetc(file);
if(c == NULL)
break;
}
Problemo solved! (Although, the compiler gives me a warning of "comparison between pointer and integer".)