how to keep file handle open in c after exiting function - c

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 );
}

Related

Error: Control may reach end of non-void function - cat function

char *wcat(char *str, size_t n, FILE *fp){
if (fp == NULL) {
printf("wcat cannot open file\n");
fclose(fp);
perror("File cannot be opened");
return NULL;
exit(1);
}else{
if ((str = fgets(str,n,fp)) != NULL){
printf("%s",str);
return str;
exit(0);
}
}
}
Terminal:
gcc -o wcat wcat.c
Error: wcat.c:36:1: warning: control may reach end of non-void function [-Wreturn-type]
The fp already equals fopen(...).
I am not sure why this is happening. I wanted to create this wcat file to work like:
./wcat file1.c file2.c
Your else clause also needs an else, or at least a default return. Your ifs don't cover every possible case. The warning says exactly what the problem is.
char *wcat(char *str, size_t n, FILE *fp){
if (fp == NULL) {
printf("wcat cannot open file\n");
fclose(fp);
perror("File cannot be opened");
return NULL;
//exit(1);
}
else if (fgets(str,n,fp))
{
printf("%s",str);
return str;
// exit(0);
}
return NULL; /// or whatever it is that you expect to happen here.
}
Neither of the calls to exit makes sense. They'll never be executed. It looks like you're trying to use those to return some sort of success/failure flag, but:
they never execute because they follow a return
exit terminates the program.
The parameter is passed back to the calling process. In my experience, this is basically never used unless you're writing a console utility.
Do you really understand what exit does? And return?
There's a lot wrong with this one. I suggest stepping through in your debugger.
the following changes, with comments, is the correct way to handle this function:
char *wcat(char *str, size_t n, FILE *fp){
// note: this check should have been handled
// where/when 'fopen()' was called
if (fp == NULL) {
// this changes the value in 'errno'
// so 'perror() will not display the right message
//printf("wcat cannot open file\n");
//fclose(fp); // <-- never open'd so cannot close
perror("File cannot be opened");
return NULL;
//exit(1); // <-- will never be executed
}else{
if (fgets(str,n,fp)){
printf("%s",str);
return str;
//exit(0); // <-- will never be executed
}
return NULL; // <-- need to handle when 'fgets()' fails
}
}
after applying the corrections AND moving the check for a failure of 'fopen()', the code would look like the following:
char *wcat(char *str, size_t n, FILE *fp)
{
if ( fgets( str, n, fp ) )
{
printf("%s",str);
return str;
}
return NULL;
}

Print the contents of the file

I am trying to print the contents of my file byte by byte. However, I do get the compiler error "invalid type argument of unary *(have int)
my code is :
void print_the_file ()
{
void *file_hndl;
UINT32 file_size = 2048;
UINT8 *hndl;
file_hndl = fopen("my_bin_file.bin", "r") ;
if ( file_hndl == NULL )
{
printf("file open failed");
}
hndl = (UINT8*)file_hndl;
/* print the contents */
for ( UINT32 i = 0; i< 2048; i++ )
{
printf ("%02x", *hndl[i] );
}
}
Please advise me where i am going wrong and right way to print the contents of the file.
fopen returns a FILE * so your file_hndl should be of that type. Whilst you're checking the return value from fopen to print out an error message, you then ignore it and continue on trying to read from the file.
You're not actually reading from the file though - you need to call other functions such as fgetc to do that. But using fopen/fgetc is probably not want you want anyway as you're trying to read in a binary file. For that you want to use open and read.
The code below does what you're actually trying to do.
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
void print_the_file(void)
{
int file_desc;
char a_byte;
size_t err;
file_desc=open("my_bin_file.bin",O_RDONLY,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if(file_desc==-1)
{
printf("file open failed\n");
return;
}
do
{
err=read(file_desc,&a_byte,1);
if(err>0)
{
printf("%02x",a_byte);
}
}
while(err>0);
}
the error was fired because of * in front of the variable hndl
for ( UINT32 i = 0; i< 2048; i++ )
{
// printf ("%02x", *hndl[i] );
printf ("%02x", fgetc(hndl) );
// remove * if you are using [] or write like this *(hndl+i)
}
make sure that you are compiling it with C99 or higher standard. for this
for ( UINT32 i = 0; i< 2048; i++ )
Try something like this:
void print_the_file()
{
FILE* file_hndl = fopen("my_bin_file.bin", "rb");
if (file_hndl == NULL)
{
printf("file open failed");
}
else
{
while (!feof(file_hndl) && !ferror(file_hndl))
{
int c = fgetc(file_hndl);
if (c != EOF) /* should be redundant */
{
printf("%02x", c);
}
}
fclose(file_hndl);
}
}
Note the file mode to fopen is "rb" to open the file for read as binary.
Also, the routine processes the entire file character by character until EOF or error occurs.

Weird bug using fopen() inside a function

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.

Reading a file into a C program

The program I have reads the file, displays it accordingly, but then when trying to view the contents again, they are gone.
Structure:
typedef struct friends_contact {
char *First_Name;
char *Last_Name;
char *home;
char *cell;
} fr;
Main:
int main() {
fr friends[5];
char buffer[BUFFSIZE];
int counter = 0;
int i = 0;
menu(friends, &counter, i, buffer);
getch();
return 0;
}
If statement in the menu function used to open up the file:
if (user_entry1 == 1) {
printf("Please enter a file name");
scanf("%s", user_entry3);
read = fopen(user_entry3, "r");
}
If statement that allows the user to choose to look at the contacts of the address book.
if (user_entry == 4 ) {
print_contact(friends, counter, i, user_entry3);
if (user_entry1 == 1) {
file2(friends, counter, i, buffer, read);
}
}
Read function:
char file2(fr *friends, int *counter, int i, char buffer[], FILE *read) {
while (fscanf(read, "%s", buffer) != EOF) {
friends[i].First_Name = malloc(BUFFSIZE * strlen(buffer));
strcpy(friends[i].First_Name, buffer);
return printf("\n""%s ", friends[i].First_Name);
}
fclose(read);
}
If you need me to provide any more code. I'm trying to get it to read the content from the file into the contacts list so I can view, search, or delete them.
P.S. I understand some of the other code may not be perfect, but right now I'm just concerned about figuring this out :).
The file2 function reads each line of the file into friends[i] but never increments i. So each new record would overwrite the previous one ... except that the function returns during the first iteration of the loop. Better to use if than while in this case.
Other suggestions:
Instead of using }else; you can just close the if block with }. An if needn't be followed by else.
Instead of the idiom
if (foo == 1) {
// do stuff
} else if (foo == 2) {
// do other stuff
} else {
// do default stuff
}
you can use
switch (foo) {
case 1:
// do stuff
break;
case 2:
// do other stuff
break;
default:
// do default stuff
}
Instead of
printf("\n""%s ",friends[i].First_Name);
it's more common to use a single string, with the newline at the end:
printf("%s\n", friends[i].First_Name);
You have to reset your file pointer using fseek to the beginning of the file again. Your read function should start like:
fseek(read, 0, SEEK_SET); // set file pointer to the beginning of the file
You shouldn't forget to test if the file could be opened or not:
if ( user_entry1==1 ){
printf( "Please enter a file name" );
scanf( "%s", user_entry3 );
if ( ( read = fopen( user_entry3, "r" ) ) != NULL ){
printf( "The file couldn't be opened" );
}
else{
.
.
.
}
}

How do I use pointers in combination with getc?

I have a function getNum(), which gets a number from file and returns it. When I go back into getNum() I have lost the pointer and it starts at the begging of the file again. I'm wondering How do I get the location of where getc is and then go back to that place. I couldn't find how to do this in the manual or in forums. Thank you.
#include <stdio.h>
#include <stdlib.h>
int getNum();
int getLine();
int getMatrix();
main() {
int num;
int two;
num = getNum();
printf("%d\n", num);
two = getNum();
printf("%d\n", two);
}
int getNum() {
FILE *infile;
infile = fopen("matrix.txt","r");
int c;
double value = 0;
while ((c=getc(infile)) != '\n') {
if(c==32){
if(value != 0){
return(value);
}
//otherwise keep getting characters
}
else if ((c<=47)||(c>=58)){
printf("incorrect number input %d\n", c);
exit(1);
}
else {
value = (10*value) + c - '0';
}
}
return(value);
}
The reason is that you reopen the file each time you execute getNum. When you open a file for reading, it starts at the start of the file. Instead open it just once.
int main(int argc, char *argv[])
{
...
FILE *infile;
...
infile = fopen("matrix.txt","r");
...
getNum(infile)
...
fclose(infile);
return 0;
}
int getNum(File *infile)
{
// Same as before, just no file opening.
}
You re-open the File each time you Call getNum, so naturally you are back at the start.
Instead open the file in your main and pass the FILE * to getNum().
You're opening the file anew with each function call. The newly opened file begins scanning from the beginning.
An alternative would be to open the file once, outside getNum(). You could pass the FILE* to getNum() as an argument.
Also, you're not closing the file. Use fclose() to close the file after all the calls to getNum().
Something like:
int getNum( FILE* fp );
...
int n;
FILE* file = fopen( "file.txt" );
assert( file );
do {
n = getNum( file );
/* ... */
}
while ( n != -1 ); /* or something */
fclose( file );

Resources