Having an issue with my fwrite() and fread() dealing with a binary file here is my source code, and towards the bottem are my read and write. Right now it is returning 'jake' when I run it, and nothing else. I was told to write a dump buffer function to deal with the binary characters. In addition here is the text file as well, I am writing to a blank file called info.bin. PS I know that it is bad practice to save the zip as an int but this is what my professor is asking for.
File:
mike|203-376-5555|7 Melba Ave|Milford|CT|06461
jake|203-555-5555|8 Melba Ave|Hartford|CT|65484
snake|203-555-5555|9 Melba Ave|Stamford|CT|06465
liquid|203-777-5555|2 Melba Ave|Barftown|CT|32154
Code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LINE 80
#define RECORDS 10
struct info{
char name[100];
char number[100];
char address[100];
char city[100];
char state[100];
int zip;
};
void dump_buffer(void *buffer, int buffer_size)
{
int x;
for(x = 0; x < buffer_size; x++)
{
printf("%c",((char *)buffer)[x]);
}
}
int i, j, seeker;
int main(int argc, char* argv[])
{
char *buffer;
struct info input_records[RECORDS];
int nrecs = 0;
unsigned long fileLen;
char line[LINE];
FILE *fp = NULL;
FILE *fpbin = NULL;
FILE *fpread = NULL;
if (argc != 2)
{
printf ("ERROR: you must specify file name!\n");
return 1;
}
/* Open file */
fp = fopen(argv[1], "r");
if (!fp)
{
perror ("File open error!\n");
return 1;
}
while (!feof (fp)) {
fgets(line, sizeof(line),fp);
char* tok = strtok(line, "|");
while(tok != NULL)
{
strcpy(input_records[nrecs].name, tok);
tok = strtok(NULL, "|");
strcpy(input_records[nrecs].number, tok);
tok = strtok(NULL, "|");
strcpy(input_records[nrecs].address, tok);
tok = strtok(NULL, "|");
strcpy(input_records[nrecs].city, tok);
tok = strtok(NULL, "|");
strcpy(input_records[nrecs].state, tok);
tok = strtok(NULL, "|");
input_records[nrecs].zip = atoi(tok);
tok = strtok(NULL, "|");
}
nrecs++;
}
fpbin = fopen("info2.bin", "wb");
if (!fp)
{
perror ("File open error!\n");
return 1;
}
for(i = 0; i < 4; i++)
{
fwrite(&input_records[i], sizeof(struct info), 200000, fpbin);
}
fclose(fpbin);
fpread = fopen("info2.bin", "rb");
fseek(fpread, 0, SEEK_END);
fileLen = ftell(fpread);
fseek(fpread, 0, SEEK_SET);
buffer = (char *)malloc(sizeof(struct info));
fread(buffer, fileLen, 1, fpread);
dump_buffer(buffer, sizeof(buffer));
fclose(fpread);
fclose(fp);
free(buffer);
return 0;
}
fwrite(&input_records[i], sizeof(struct info), 200000, fpbin);
You just told fwrite
to write 200000 * sizeof(struct info)
bytes to the file, starting at the address of input_records[i]
. That accesses memory far beyond what has been allocated for input_records
, the behaviour is undefined, but a segmentation fault is not unlikely. I'm actually surprised that apparently it didn't crash for you.
buffer = (char *)malloc(sizeof(struct info));
fread(buffer, fileLen, 1, fpread);
You're trying to read fileLen
bytes into a buffer of size sizeof(struct info)
. If fileLen > sizeof(struct info)
, that is again undefined behaviour, and if fileLen
is sufficiently larger, likely to crash.
You should let fwrite
one object of size sizeof(struct info)
each time, and you should allocate fileLen
bytes for the buffer you read in (or read in chunks of size sizeof(struct info)
). And you should check the return values of fwrite
and fread
to know whether they succeeded in writing/reading the desired data and handle failures appropriately.
fpbin = fopen("info2.bin", "wb");
if (!fp)
{
You check the wrong FILE*
here, and you don't check fpread
at all.
Further, you pass the wrong count to dump_buffer
,
dump_buffer(buffer, sizeof(buffer));
buffer
is a char*
, so sizeof buffer
is the size of a char*
, typically four or eight bytes. You should pass the allocated size of the buffer there.
And, when reading the original file,
while (!feof (fp)) {
fgets(line, sizeof(line),fp);
feof(fp)
only becomes true after an attempt to read was made when the end of the file has been reached, you should change your loop condition to
while(fgets(line, sizeof line, fp) != NULL) {
Finally, your tokenizing code will fail badly if the input file contains malformed data, or too long lines. You should also add checks there, so that you don't pass a NULL
to strcpy
or atoi
.