Function for loading data from binary files to array of structs - c

This is my code for loading data from binary file to array of structs but I get error that file is not found. File is there and it works with other functions.
void ispis2(void) {
float data_num = brojanje();
int N = data_num / 3;
ARTIKL artikl[120];
FILE *fp = NULL;
fp = fopen("artikli.bin", "rb");
if (fp == NULL) {
fprintf(stderr, "Pogreska: %s\n", strerror(errno));
}
else {
for (int i = 0; i < N; i++) {
fread(&artikl[i].ime, sizeof(artikl), 1, fp);
fread(&artikl[i].cijena, sizeof(artikl), 1, fp);
fread(&artikl[i].ID, sizeof(artikl), 1, fp);
}
for (int i = 0; i < N; i++) {
printf("Ime: %s", artikl[i].ime);
printf("Cijena: %f", artikl[i].cijena);
printf("ID: %d", artikl[i].ID);
}
}
}

You probably are not running your program in the environment (notably check the current working directory) you want.
Of course your fread-s smell bad. Read again the documentation of standard C input/output functions, in particular of fread. The sizeof(artikl) argument is surely wrong (but since your question don't explain what an ARTIKL really is, we cannot help more).
The notion of directory is unknown by the C11 standard n1570. See also this. But if you are on a POSIX system, you could query it with getcwd(3). Other operating systems have different ways of querying it (e.g. GetCurrentDirectory on Windows). Read Operating Systems: Three Easy Pieces to understand more about operating systems, and read also a good C programming book.
So you could perhaps improve the error handling:
if (fp == NULL) {
fprintf(stderr, "Pogreska: %s\n", strerror(errno));
char wdbuf[128];
memset(wdbuf, 0, sizeof(cwdbuf));
fprintf(stderr, "working directory: %s\n",
getcwd(wdbuf, sizeof(wdbuf));
}
(the above code don't handle failure of getcwd; a robust program should handle that)
BTW, I am not sure that handling binary files like you do is worthwhile (a binary format is very brittle, and you need to document its format very precisely; remember that most of the time, data is more valuable than the application processing it). You might consider instead storing the data in some textual format (like JSON, YAML, ....) or in some sqlite database. Consider using appropriate libraries (e.g. jansson for JSON, libsqlite for sqlite)
Don't forget to compile your code with all warnings and debug info (so gcc -Wall -Wextra -g with GCC). Read the documentation of your compiler (e.g. how to invoke it) and of your debugger. Use the debugger to understand the behavior of your program.

Related

Segmentation fault found but message before that is being optimized out

I wrote the following code in GDB online debugger :
#include <stdio.h>
int main()
{
printf("jkjkkjkj");
int p , n;
FILE *fp;
printf("jkjkkjkj2");
fp = fopen("abc.txt","r");
while ( (n = getc(fp))!= EOF)
{
printf( "the chareacter here is %d \n", n);
}
n = fclose(fp);
return 0;
}
While executing the code I am getting a segmentation fault at the line where I am trying to fetch the characters from the file. I know that as the file does not exist the segmentation fault error is coming.
However, what intrigues me is the absence of the messages that I am trying to print on the screen. I tried checking on debugger and once I found:
optimized out written near the line no
However, I tried putting getchar() here and there, the messages got printed on the screen even if the segmentation fault persists.
How to explain this? Why is this happening? Why are the messages printed when I am putting getchar() at different places?
I had tried writing this code on a Solaris server and compiling using GCC. The code got compiled but I did not get any output message even when a file with the name provided in the directory existed.
As answered by Yunnosch, you probably forgot to check against failure of fopen(3). A better habit is to always check that, at least by coding:
fp = fopen("abc.txt","r");
if (fp == NULL) { perror("fopen abc.txt"); exit(EXIT_FAILURE); };
and take the habit of doing at least that everywhere. Using perror(3) (or strerror(3) with errno(3)) is a useful habit to get, since you want some reason related to the failure (given by errno perhaps thru perror).
More generally, always read the documentation of functions that you are using (for standard functions, at least on some reference website, and possibly in the C11 standard n1570), and take care of handling their failure (at the very least, by checking against failure and exiting with a useful message to stderr); for Unix functions, see their man pages (on Linux, start on intro(2) and intro(3); for Solaris, start with intro(2) & intro(3)..). In your Unix terminal, try also man fopen ... For POSIX standard, start here.
what intrigues me is the absence of the messages that I am trying to print on the screen.
That is simple. stdout is buffered (see also setvbuf(3)), and often line-buffered. So a printf which does not end with a \n has its output still inside the buffer, and not yet on the screen. The habit to get is to almost always end your printf(3) control format string with a newline, or else to flush the buffer explicitly using fflush(3).
For a newbie, there are few reasons to avoid ending your printf with an explicit \n. So use instead
printf("jkjkkjkj\n");
Otherwise, call fflush(NULL); quite often in your program. BTW, for these buffering reasons, fflush(NULL) should be done before calls to system(3), fork(2), execve(2) and other important program-wide functions.
optimized out written near the line no
That probably happens in the C standard library itself (e.g. in getc from some libc.so), which is usually not compiled with debug information. In practice, trust your C standard library: you are much more likely to have bugs in your code that in libc.
Your own source code should be compiled with gcc -Wall -Wextra -g (asking the GCC compiler to give all warnings and debug info in DWARF format, usable by the gdb debugger) and you need to improve your code to get no warnings at all before using the gdb debugger.
Be aware of undefined behavior, spend several hours reading about UB, and be scared of UB.
Try guarding against NULL in fp and for good measure make sure the debug output gets printed (as in comment by Some Programmer Dude).
#include <stdio.h>
int main(void)
{
int p , n;
FILE *fp;
printf("jkjkkjkj2\n");
fp = fopen("abc.txt","r");
if (NULL != fp)
{
while ( (n = getc(fp))!= EOF)
{
printf( "the chareacter here is %d \n", n);
}
n = fclose(fp);
} else
{
printf("File opening failed somehow!\n");
}
return 0;
}
Note the nice touch (by Basile Starynkevitch) to only close what was successfully opened.

Opening all the files from a local directory/folder [duplicate]

This question already has answers here:
Using a variable file name in C to read from multiple files with similar names?
(2 answers)
Closed 7 years ago.
Using Visual Studio 2015 how would i open and read all the file in a directory.
The Input Parameters for the program are
Number of Sensors (N): Determines the number of input files
File Location: A local directory/folder where the files are located. Each file will be named: sensor_0.txt, sensor_1.txt, ... sensor_(n - 1).txt
I can open and read individual files in the directory by hard coding them using fopen, but since the number of input files is not constant I don't know how I would read all of the files in the directory regardless of how many input files there are.
I was thinking that i would need to create the file names since the only thing changing in the file names is the sensor number but that doesn't seem to work since fopen requires a const char * file name.
I have searched for solutions and i found a DIR variable type in dirent.h header file, but that doesn't work with the the Visual Studio Compiler and a package needs to be installed in order to use that header file.
I am in an intro to programming class so i feel like installing outside programs would be the wrong approach to solving this issue, but I could be wrong. I have also looked into functions like FindFirstFile, and FindNextFile but those also seem too advanced for me.
Any help would be really would be appreciated. Thank you in advance.
If you're writing a Windows-specific application (rather than something that needs to be portable to other operating systems) then look into the FindFirstFile, FindNextFile, and FindClose APIs.
Here's a sample of how to use these APIs (based somewhat on the samples from the above links):
#include <windows.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
if (argc != 2) {
printf("Usage: %s [target_file]\n", argv[0]);
return 1;
}
printf("Target file is %s\n", argv[1]);
hFind = FindFirstFile(argv[1], &FindFileData);
if (hFind == INVALID_HANDLE_VALUE) {
printf("FindFirstFile failed, error %d\n", GetLastError());
return 1;
}
do {
printf("File name = %s\n", FileFindData.cFileName);
} while (FindNextFile(hFind, &FindFileData));
FindClose(hFind);
return 0;
}
Disclaimer: I haven't had a Windows dev environment years, so I have no way to compile & verify this sample. It should get you pointed in the right direction, though.
You can just do it by hardcoding the base name and iterating with an index to generate the specific name, something like this
for (size_t i = 0 ; ; ++i)
{
char filepath[MAX_PATH];
FILE *file;
// In principle, you should check the return value to ensure
// it didn't truncate the name
snprintf(filepath, sizeof(filepath), "sensor_%d.txt", i);
// Try to open the file, if it fails it's probably because
// the file did not exist, but it's not the only possible
// reason.
file = fopen(filepath, "r"); // Or "rb", depends ...
if ((done = (file == NULL)) != 0)
break; // Cannot open this, probably there are no more files.
// Process the file here
}
A better way would be to pass the name to another function, so you can later change the name generation method by looking at the directory instead of assuming it.
NOTE 1: Secure c Runtime, in MSVC compiler will probably complain about fopen() and snprintf() since snprintf() uses the POSIX name style or something like that (perhaps using the safe version snprintf_s()) I don't remember. But this is standard c (as per C11) so it should compile with any c compiler.
NOTE 2: You should also, use the full path unless the files are in the CWD. Something like (assuming the files are in drive "C:")
snprintf(filepath, sizeof(filepath), "C:\\full\\path\\sensor_%d.txt", i);

Why gcc does not give a warning or error when invalid mode is used in fopen()?

I am practicing some practice questions in FILE IO in C. Below is one of the programs.
#include<stdio.h>
#include<stdlib.h>
int main()
{
char fname[]="poem.txt";
FILE *fp;
char ch;
fp = fopen ( fname, "tr");
if (fp == NULL)
{
printf("Unable to open file...\n");
exit(1);
}
while((ch =fgetc(fp)) != EOF)
{
printf("%c",ch);
}
printf("\n");
return 0;
}
As you can see in the statement
fp = fopen ( fname, "tr");
The mode "tr" is not a valid mode (as I understand). I was expecting gcc to give an error (or a warning) while compiling the above program. However, gcc does not give any error (or warning) while compiling it.
However, as expected, when i run the program it exits printing "Unable to open file..." which means fopen() returned NULL , because there was error while opening file.
-bash-4.1$ ./a.out
Unable to open file...
-bash-4.1$
(The file poem.txt exists so this is because of the invalid mode given to fopen(). I checked by changing the mode to "r" and it works fine displaying the content of "poem.txt")
-bash-4.1$ ./a.out
THis is a poem.
-bash-4.1$
I was expecting gcc to give an error (or warning) message for the invalid mode.
Why gcc does not give any error (or warning) for this ?
the compiler doesn't check what you do, it only checks the syntax.
However, at run time, if the code is written like so:
#include<stdio.h>
#include<stdlib.h>
int main()
{
char fname[]="poem.txt";
FILE *fp;
char ch;
fp = fopen ( fname, "tr");
if (fp == NULL)
{
perror( "fopen for poem.txt failed");
exit( EXIT_FAILURE );
}
while((ch =fgetc(fp)) != EOF)
{
printf("%c",ch);
}
printf("\n");
return 0;
}
then a proper error message is output:
...$ ./untitled
fopen for poem.txt failed: Invalid argument
This is Undefined Behavior:
Per Annex J.2 "Undefined Behavior", it is UDB if:
—The string pointed to by the mode argument in a call to the fopen function does not exactly match one of the specified character sequences (7.19.5.3).
Although Annex J is informative, looking at §7.19.5.3:
/3 The argument mode points to a string. If the string is one of the following, the file is open in the indicated mode. Otherwise, the behavior is undefined.
Basically, the compiler can blow you off here - a standard library function name (and behavior) can be used outside of the inclusion of a standard header (for example, non-standard extensions, completely user-defined behavior, etc.). The Standard specifies what a conforming library implementation shall include and how it shall behave, but does not require you to use that standard library (or define behavior for a specific implementation explicitly specified as UDB territory: at this point, if your parameter types match it's a legal function call).
A really good lint utility might help you here.
How is the compiler supposed to know what the valid arguments for a function are?
To do it you'd be building too much knowledge in the compiler - it would have to recognize functions and their parameters by name. What if you want to override the function? What if different modes are valid on different platforms?
In Windows programming, "tr" is a valid mode is not a valid mode, although "rt" is. The t means text and the r means read. (If you are using gcc and linking to MS's C runtime then you will be able to use this).
However you still don't see t very often because it is the default and therefore redundant; the other option for this setting is b meaning binary. But MS do seem to explicitly use t in their examples to make it clear that translation is intended.
The behaviour of text mode and binary mode for a stream is implementation-defined, although the intent is that binary mode reads the characters exactly as they appear on disk, and text mode may perform translations relevant to text processing; most famously, converting \r\n in MS text files to \n in your program.

updating text files in C(is it possible?)

Do any of you guys know if it's possible to update a text file(e.g something.txt) in C?
I was expecting to find a function with similar syntax as update_txt(something.txt), but I haven't found anything while browsing the internet for the last 2 hours.....
The thing is that I would like some data to be stored and displayed in real time in an already opened text file. I can store the data but I am unable to find a way to display it without manually closing the text file and then open it again...
Do someone know how to solve this issue? Or do you have another way to solve it? I have read something about transferring data to a new text document and then renaming it, but I am quite sure that this wouldn't solve my problem. I have also read something about macros that could detect changes in the document and then somehow refresh it. I have never worked with macros and I have absolutely no idea of how they are implemented....
But please tell me if it is a fact that it is impossible to update an already opened text document?
I am thankful for any suggestions or tutorials that you guys may provide! :)
That's outside the scope of C; it will require some system-specific filesystem monitoring mechanism. For example, inotify offers this functionality
First off, you can use the rewind(), fseek(), ftell() or fgetpos() and fsetpos() functions to locate the read pointer in a file. If you record the start position where the updated record was written (the start offset) using ftell() or fgetpos(), you could jump back to that position later with fseek() or fsetpos() and read in the changed data.
The other gotcha lurking here is that in general, you can't simply 'update' a text file. Specifically, if the replacement text is not the same length as the original text, you have problems. You either need to expand or contract the file. This is normally done by making a copy with the desired edit in the correct location, and then copying or moving the modified copy of the file over the original file.
Detecting when some other process modifies the file is harder still. There are different mechanisms in different operating systems. For Linux, it is the inotify system, for example.
Based upon your statement that you 'can't display it without manually closing the text file and open it again', it may be a buffer issue. When using the C standard library calls (fopen, fread, fwrite, fclose, etc ...) the data you write may be buffered in user-space until the buffer is full or the file is closed.
To force the C library to flush the buffer, use the fflush(fp) call where fp is your file pointer.
Regarding: But please tell me if it is a fact that it is impossible to update an already opened text document? Yes, it is not possible, unless you own the handle to the file (i.e. FILE *fp = fopen("someFilePath", "w+");)
Regarding: if it's possible to update a text file(e.g something.txt) in C?
Yes. If you know the location of the file, (someFileLocation, eg. "c:\dev\somefile.txt"), then open it and write to it.
A simple function that uses FILE *fp = fopen(someFileLocation, "w+"); (open existing file for append) and fclose(fp); will do that: Here is an example that I use for logging:
(Note, you will have to comment out, or create the other functions this one refers to, but the general concept is shown)
int WriteToLog(char* str)
{
FILE* log;
char *tmStr;
ssize_t size;
char pn[MAX_PATHNAME_LEN];
char path[MAX_PATHNAME_LEN], base[50], ext[5];
char LocationKeep[MAX_PATHNAME_LEN];
static unsigned long long index = 0;
if(str)
{
if(FileExists(LOGFILE, &size))
{
strcpy(pn,LOGFILE);
ManageLogs(pn, LOGSIZE);
tmStr = calloc(25, sizeof(char));
log = fopen(LOGFILE, "a+");
if (log == NULL)
{
free(tmStr);
return -1;
}
//fprintf(log, "%10llu %s: %s - %d\n", index++, GetTimeString(tmStr), str, GetClockCycles());
fprintf(log, "%s: %s - %d\n", GetTimeString(tmStr), str, GetClockCycles());
//fprintf(log, "%s: %s\n", GetTimeString(tmStr), str);
fclose(log);
free(tmStr);
}
else
{
strcpy(LocationKeep, LOGFILE);
GetFileParts(LocationKeep, path, base, ext);
CheckAndOrCreateDirectories(path);
tmStr = calloc(25, sizeof(char));
log = fopen(LOGFILE, "a+");
if (log == NULL)
{
free(tmStr);
return -1;
}
fprintf(log, "%s: %s - %d\n", GetTimeString(tmStr), str, GetClockCycles());
//fprintf(log, "%s: %s\n", GetTimeString(tmStr), str);
fclose(log);
free(tmStr);
}
}
return 0;
}
Regarding: browsing the internet for the last 2 hours. Next time try
"tutorial on writing to a file in C" in Google, it lists lots of links, including:
This one... More On The Topic.

How do you write to a buffer then to a file

I'm trying to write some STL data out of matlab and I'm trying to do this by writing a MEX File (a matlab DLL written in C) At the moment I have a loop just going through my data writing out the stl syntax with the floats.
...
for(m=0;m<colLen;m++)
{
res = m % 3;
if(res == 0)
{
fprintf(fp, "\tfacet normal %f %f %f \n",
normalValues[(x*nvcolLen)+0], normalValues[(x*nvcolLen)+1], normalValues[(x*nvcolLen)+2]);
fprintf(fp,"\t\touter loop\n" );
flag = 0;
x++;
}
fprintf(fp, "\t\t\tvertex ");
for(n=0;n<rowLen;n++)
{
fprintf(fp, "%f ", xValues[m*rowLen+n]);
}
fprintf(fp,"\n");
flag++;
if (flag == 3)
{
fprintf(fp, "\t\tendloop\n\tendfacet\n");
flag = 0;
}
}
...
The main reason why I want to do this in a MEX file is because things are way quicker since its compiled. I was reading a C++ book, "Sams Teach Yourself C++ in One our a day" and in page 645 they talk about using a buffers to speed up writing to the disk. Once the buffer fills up, write the data, flush it, and do it again. They don't really show any code on how to do that and this is with C++'s streams.
How would I approach this in C? Would I just make a char* buffer with a fixed size, and then somehow check when its full and write it to a file with fwrite(), flush it, start over??
Basically, of you want to do it yourself, you'd do it almost exactly as you wrote: Make a char* buffer, track the number of chars in it (by counting the chars you put in it) and if it is full (or nearly-full), flush it to the file.
However, this should really not be an issue with C streams, as they usually do buffering. You can even control this buffering with the function setbuf et al.
fprintf does buffered output automatically for you. If there is a problem, show us the code that opens the file (fp).

Resources