Creating and returning file via C function - c

What I'm trying to do is to write a function that creates a file, fills it with data and returns the file to main(). The question is - what is the right way to "return file". Should I pass pointer / file descriptor or just disregard all this and use filename?
EDIT: doing the right way (I hope):
int mkrandfile(const char *name, int range, int qnt)
{
FILE *afile;
int i = 0;
if (afile = fopen(name, "w+"))
{
while((i <= qnt) && fprintf(afile, "%d ", rand() % range - range/2))
i++;
fclose(afile);
if (i != qnt + 1)
return -2;
}
else
return -1;
}

You are correct that returning afile from that function is wrong. Once the file is closed, that file handle is no longer valid. Use of it by the caller would result in undefined behavior.
While it is probably not the best idea from a modularity standpoint, you could leave the file open and then return the handle. But I think one of the following might be better:
Pass in an opened file handle to the function (let the caller open and close it).
Make the caller open the file again on its own.
The first option may be more efficient when file caching by the OS (if applicable here) is considered.

Related

How to use goto across multiple functions

I am trying to exit a program without using exit(). I have come up with a very convoluted and dirty solution (I am a Beginner).
I would like to use if statements and if it is true, then I would like to use goto to go the main function and then return 3; and end the program.
Here is a bit of code:
FILE *filepointer;
char * line = NULL;
size_t len = 0;
size_t read;
int linecount = 0;
filepointer = fopen(filename, "r");
if (filepointer == NULL)
{
printf("[ERR] Could not read file %s.\n",filename );
goto FILE_ERROR;
}
...
int main(){
...
FILE_ERROR: return 3;
}
This however does not work as I cannot get jump between functions because I get undeclared Label as an error. Is there any way I can exclude exit() from my program and still end it returning a certain value. If there is a better solution, please let me know
The only good answer to this question is: don't do it. gotos used in this way make your code very hard to reason about.
Refactor your code so that you have a clear structure and hierarchy of calls. Use return values to propagate success/failure throughout the call stack.
goto can't be used to jump across different functions; it can only be used within the same function. To jump between functions, you can look at setjmp() and longjmp() functions.
Having said, since you claim to be a beginner, I am not convinced you really need to use either of the above. You can simply modify your function to return an "error" value. And in main(), check its value and return from main() with the error value.
By design, a goto cannot jump from one function to another. It can only be used to jump within a given function.
There are ways to jump between functions, but doing so is not only very poor design but also dangerous as it is very easy to put your program in an invalid state.
The proper way to handle this is to have your function return a specific value (or set of values) to indicate an error. Then the calling function would check for one of those error values and act accordingly.
For example:
int readFile(char *filename)
{
FILE *filepointer;
char * line = NULL;
size_t len = 0;
size_t read;
int linecount = 0;
filepointer = fopen(filename, "r");
if (filepointer == NULL)
{
// add strerror(error) to the error message to know why fopen failed
printf("[ERR] Could not read file %s: %s.\n",filename, strerror(errno) );
// error completion
return 0;
}
...
// successful completion
return 1;
}
int main(){
...
if (readFile("myfile") == 0) {
return 3;
}
...
}
If you wanted to use a go-to , and insisted on doing that, you could I guess try to expand your 1st function so it includes / encapsulates the 2nd function, and get rid of the 2nd function conpletely, so your able to do go tos and subroutines within this much larger function.
Is that an option you could try ? (If you were dead cert on using Goto's, ) ?
I would give that a go.

C fopen/fwrite driving me to madness - fwrite not writing

Ok, here is the deal...i remember creating a program past week that required me to open a file in binary mode and write data to it. At first, i tried using the fopen function, checking if the result is ok, then try to write data. I remember that at first try, the fwrite operation wasn't working. Then, after moving declaration of variables from a place to another, i was finally able to make the fwrite to insert data to the file.
Now, i need to create another similar program to do some other stuff, so i wanted to use the same allocation code (actually, i wanted to create a specific function to do the same), and here is what i was able to come up with:
#include <stdio.h>
int openfile(FILE *main, char *name, int option);
int main(void)
{
FILE *main;
int header_init;
int result;
switch (openfile(main,"main_file.bin",1)) {
case 1:
header_init = -1;
//fseek(main,0,SEEK_SET); --> useless
fwrite(&header_init,sizeof(int),1,main);
printf("ftell = %d\n",ftell(main)); break;
case 2:
fread(&header_init,sizeof(int),1,main);
printf("%d\n",header_init); break;
default:
printf("Error trying to open file\n");
}
printf("header_init is %d\n",header_init);
fclose(main); exit(0);
}
int openfile(FILE *main, char *name, int option)
{
int result_alloc;
int F_OK;
if (result_alloc = access (name, F_OK) != 0) {
printf("File not found, allocating a new one\n");
if ((main= fopen(name,"w+b")) != NULL) return 1;
}
else {
printf("File exist, allocating as r+b\n");
if ((main= fopen(name,"r+b")) != NULL) return 2;
}
printf("Failure trying to open");
return 0;
}
For some unfortunate reason, the fwrite operation is not writing -1 to the allocated file. My intention with this program is so that it will always check for existence of that specific file: if there is one in place, simply open it with r+b to allow update functions without overwriting the actual file contents. Otherwise, allocate a new one with a header value of -1 (i will use this file as a record file with chained list structure).
Seriously, i cannot understand why this is not working. The idea is the same of my previous program. The only thing that changed is that i created a function, because this is going to happen me later (because of the 3rd parameter that will allow me to reduce my code and make it more "readable" - at least this is the intention!). I HAVE to admit that i have some attention to details problem, but i am working hard to get better at it, i am probably missing something stupid in this code, but after hours looking at it i really wanted to ask here for some help. Thanks
Edit: I am running it under z/Linux. What i am trying to understand is, why the code above doesn't write -1 to the file, but the one below writes ok?
#include <stdio.h>
int main(void)
{
FILE *main;
int result_alloc;
int header_init;
int F_OK;
if (result_alloc = access ("test.bin", F_OK) != 0) {
printf("File not found, allocating a new one\n");
if ((main = fopen("test.bin","w+b")) == NULL) {
printf("Failure trying to open file");
return 1;
}
else {
header_init = -1;
printf("current pos is: w+b %d\n",ftell(main));
fwrite(&header_init,sizeof(int),1,main);
printf("current pos is: write header_init %d\n",ftell(main));
}
}
else {
if ((main = fopen("test.bin","r+b")) == NULL) {
printf("Failure trying to open file");
return 2;
}
else {
printf("current pos is: r+b %d\n",ftell(main));
fread(&header_init,sizeof(int),1,main);
printf("current pos is: read header_init %d\n",ftell(main));
}
}
}
The main issue that the assignment to the main variable inside of the openfile function is not seen by the calling function. Because C is pass by value, you're only changing the value of the function parameter, not the value of the variable that was passed in. So when openfile returns, the main variable inside of the main function is unchanged.
What you need to do is pass the address of that variable to the function, then within the function you dereference the local variable (which is a pointer) and assign a value to the dereferenced variable.
Also, it's not a good idea to have a variable with the same name as a function as it hides the function in that scope and can cause confusion.
So you would define your function as follows:
int openfile(FILE **fp, char *name, int option);
You would then call it like this (changing the name of the main variable to fp):
FILE *fp;
...
openfile(&fp,"main_file.bin",1)
Then inside of openfile, you dereference fp to change the value in the calling function:
*fp = fopen(name,"w+b")
The reason why the second code sample is working is that you're assigning directly to a local variable and then using that same variable later on in the function.
Also, you're "lucky" that the second piece of code is working because you did this:
int F_OK;
F_OK is already defined in unistd.h, where access() is defined. So by doing this you're redeclaring it and not giving it a value, causing undefined behavior. Get rid of this definition, and #include <unistd.h>, and the call to access() is guaranteed to work as expected.

Preserving file pointer between function calls

I have a code where I'm accessing a binary file several times. Each time I call the function, it opens the file for reading and it reads out only the required number of bytes (say n bytes each time).
The binary file contains time series data, and what I'd like it to be able to do is run the function call through a loop, and every time I call the function to open the same file, it needs to read out the next chunk of data, i.e, I don't want the file pointer to be reset every time. Is there a way to do this?
The function looks like so:
int readBinary(float *binImage, int gelements) {
imageFile = fopen("tmpImageFile", "r");
if (imageFile == NULL) {
fprintf(stderr, "Error opening file\n");
return (1);
}
fread(binImage, sizeof(float), gelements, imageFile);
return 0;
}
And in my main code, I'd like to run it through a loop, giving it the array binImage of size gelements every time. I'd rather not give it an array of size gelements * nLoop if that's avoidable.
The quick rules of thumb are
"Life gets easier if you properly separate responsibilities between functions"
and
"Life gets complicated if you use static or global variables".
In this case, giving the readBinary function both the responsibility of managing the FILE and reading the data is too much.
Note that the function doesn't close the handle.
If the handle is a local static in the function then it will be impossible to close it.
It also means that the function will be forever locked into using only "tmpImageFile" (which is not immediately apparent from the function's signature or missing documentation)
If the handle is a global then it may be possible to close it prematurely.
Notice that if you remove the "open file" responsibility the readBinary function is just a call to fread.
The best way to handle this is to skip the readBinary function altogether.
You say you have a caller which reads data in a loop.
Make this caller responsible for opening the FILE, use fread directly in the loop and close the file when you are done.
Now, this might give the caller too much responsibility. Simply have the caller accept the FILE* as a parameter and give the file management responsibility to its caller.
Or the caller's caller's caller, depending on where it makes sense to manage the file's lifetime.
Use a static variable so you retain the file pointer:
int readBinary(float *binImage, int gelements) {
static FILE *imageFile = NULL;
if (imageFile == NULL) {
imageFile = fopen("tmpImageFile", "r");
if (imageFile == NULL) {
perror("Error opening file: ");
return (1);
}
}
fread(binImage, sizeof(float), gelements, imageFile);
return 0;
}
I would pass the FILE* as parameter to function:
int readBinary(float *binImage, int gelements, FILE *imageFile) {
int bytes = fread(binImage, sizeof(float), gelements, imageFile);
return bytes != -1 ? 0 : 1;
}
I also added simple check for fread return value and converting it to your return value convention. Though this function seems so simple, you could just call fread directly, unless you want to add stuff like error print to it.
You can make the file pointer static and initialize it to NULL. Then next time onwards if it is not NULL, then it contains the opened file. Also while closing the file, make sure you make it to NULL again. Same can be done with a global pointer also
int readBinary(float *binImage, int gelements) {
static imageFile = NULL;
if(imageFile == NULL ) imageFile = fopen("tmpImageFile", "r");
if (imageFile == NULL) {
fprintf(stderr, "Error opening file\n");
return (1);
}
fread(binImage, sizeof(float), gelements, imageFile);
return 0;
}

Reading in .txt file with different extension in C

At the moment my program has no problem reading in a .txt file, but my program needs to read in a text file with a different file extension (.emu is the requirement). When simply changing the same file's extension to .emu, the variable 'file' is NULL and therefore the file isn't opened, can anyone help?
Had a little look around and haven't been able to find a solution so any help is much appreciated
here's the source code:
void handleArgs (const char *filename, int trace, int before, int after) {
FILE *file = fopen(filename, "r");
char *address = malloc(MAX_ADD_LENGTH * sizeof(char));
char *instruction = malloc(MAX_INS_LENGTH * sizeof(char));
long int addressDecoded;
if (file == NULL || file == 0) {
fprintf(stderr, "Error: Could not open file");
}
else {
if (ferror(file) == 0) {
while (fscanf(file, "%s %s", address, instruction) != EOF) {
if (strlen(address) == 8 && strlen(instruction) == 8) {
addressDecoded = strtol(address, NULL, 16);
printf("%ld\n", addressDecoded);
//instruction = decodeInstruction(instruction);
}
else {
fprintf(stderr, "Error: particular line is of wrong length");
}
}
}
}
fclose(file);
}
argument 'filename' when executing is simply '/foopath/test.emu'
There's nothing special to C about the file extension. Reread your code for simple errors like changing the filename in one place, but not the other. If you're passing in the filename, pass the whole name, not just the part to the left of the period.
Files are data, and have names. What comes before the dot in a name, is just as much a part of it as what comes after -- the extensions were created just as hints as to what the file contains, but they are NOT required to be strictly related to the file's contents.
The file may not exist, or your priviledges may not be enough to open it. Or maybe there's some other kind of error. How can you diagnose this?
When you use a system call and it doesn't behave the way you want to, there's a variable called errno in errno.h (#include <errno.h>) that will contain a number representing the status of the last call. There's a huge list of symbolic constants to put names to these values, you can google it up.
For example, if you try to open a file and the returned pointer is useless, you might want to check errno to see if the file existed, or if you're exceding system restrictions for opened files, etc.

problem using fprintf

I'm trying to print to a text file numerous variables yet it doesn't work.
I checked and verified that i write it in the correct syntax.
I also checked the return value and it's positive therefore i know it did write to the file, however when i open the file it's empty.
I would be happy for some help.
This is the code:
I initiate DynsaleDayPtr in the main:
FILE* DynsaleDayPtr = CreateTextFiles("sale_day.txt");
Create function:
FILE* CreateTextFiles (char* fileName)
{
FILE* saleFilePtr=NULL;
if((saleFilePtr=fopen(fileName,"a+"))==NULL)
printf("File couldn't be opened\n");
return saleFilePtr;
}
The call to the function TextAddSale is done from a function that is called in the main:
TextAddSale(DynSaleDayPtr,dynNumOfRecords);
Bool TextAddSale (FILE* DynsaleDayPtr, int* dynNumOfRecords)
{
char id[6];
char name [50];
char priceChar[20];
char* tmp = NULL;
int price=-1;
DynamicRecord * newRec=NULL;
scanf("%s%s%s",id,name,priceChar);
newRec = (DynamicRecord *)malloc(sizeof(DynamicRecord));
if (newRec == NULL)
return False;
tmp = (char*)malloc(strlen(name)+1);
if (tmp == NULL)
{
free (newRec);
return False;
}
strcpy(tmp,name);
newRec->productName = tmp;
strcpy(newRec->productId, id);
newRec->productPrice=atoi (priceChar);
if (fprintf(DynsaleDayPtr,"%d %s %s %d", strlen(newRec->productName),
newRec->productId, newRec->productName, newRec->productPrice)>0)
{
*dynNumOfRecords=(*dynNumOfRecords)+1;
return True;
}
}
thanks!
You need to flush the stream.
fflush(FILE*);
Of course, you have to close the stream if you have done with it.
fclose(FILE*);
Agree with #pmg - try something like this:
FILE *pFile = fopen("foo.txt","w");
if (pFile==NULL)
bad();
fprintf(pfile,"Hello world\n");
fclose(pfile);
make that work first - then fix whatever's wrong in the big app -
A thought:
scanf("%s%s%s",id,name,priceChar);
the above statement is a bit dodgy since you haven't said how many bytes
should go in each string.
better to use fgets() then parse the string retrieving the individual values
or create a better format specifier.
If the above statement causes a memory overwrite the rest of your program
could malfunction causing things like what you describe.
fprintf() most likely uses buffered output. Therefore, you should either fflush() the DynSaleDayPtr stream or, better yet, print a newline to the file. The latter has the added benefit of making the file contents actually readable...
Also, don't forget to close() the stream when you're finished with writing. This will also render fflush() unnecessary.

Resources