Question

I've been working on this assignment, where I need to read in "records" and write them to a file, and then have the ability to read/find them later. On each run of the program, the user can decide to write a new record, or read an old record (either by Name or #)

The file is binary, here is its definition:

typedef struct{
        char * name;
        char * address;
        short addressLength, nameLength;
        int phoneNumber;
    }employeeRecord;
    employeeRecord record;

The way the program works, it will store the structure, then the name, then the address. Name and address are dynamically allocated, which is why it is necessary to read the structure first to find the size of the name and address, allocate memory for them, then read them into that memory.

For debugging purposes I have two programs at the moment. I have my file writing program, and file reading.

My actual problem is this, when I read a file I have written, i read in the structure, print out the phone # to make sure it works (which works fine), and then fread the name (now being able to use record.nameLength which reports the proper value too). Fread however, does not return a usable name, it returns blank.

I see two problems, either I haven't written the name to the file correctly, or I haven't read it in correctly. Here is how i write to the file: where fp is the file pointer. record.name is a proper value, so is record.nameLength. Also i am writing the name including the null terminator. (e.g. 'Jack\0')

fwrite(&record,sizeof record,1,fp);
fwrite(record.name,sizeof(char),record.nameLength,fp);
fwrite(record.address,sizeof(char),record.addressLength,fp);

And i then close the file. here is how i read the file:

fp = fopen("employeeRecord","r");


fread(&record,sizeof record,1,fp);
printf("Number: %d\n",record.phoneNumber);


char *nameString = malloc(sizeof(char)*record.nameLength);

printf("\nName Length: %d",record.nameLength);
fread(nameString,sizeof(char),record.nameLength,fp);
printf("\nName: %s",nameString);

Notice there is some debug stuff in there (name length and number, both of which are correct). So i know the file opened properly, and I can use the name length fine. Why then is my output blank, or a newline, or something like that? (The output is just Name: with nothing after it, and program finishes just fine)

Thanks for the help.

Was it helpful?

Solution

I tried your code and it worked fine. In order, here is the output, a hexdump of the file, and your source made to compile.

Update: Updated code to read name and address from stdin or command-line arguments.

prompt$ g++ -g -Wall -o test_records test_records.cpp
prompt$ echo -e "Test User\nSomeplace, Somewhere" | ./test_records
sizeof(employeeRecord) = 24
Number: 5551212

Name Length: 9
Name: Test User

prompt$ hexdump -C employeeRecord 
00000000  90 f7 bf 5f ff 7f 00 00  70 f7 bf 5f ff 7f 00 00  |..._....p.._....|
00000010  14 00 09 00 6c b4 54 00  54 65 73 74 20 55 73 65  |....l.T.Test Use|
00000020  72 53 6f 6d 65 70 6c 61  63 65 2c 20 53 6f 6d 65  |rSomeplace, Some|
00000030  77 68 65 72 65                                    |where|
00000035

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct{
        char * name;
        char * address;
        short addressLength, nameLength;
        int phoneNumber;
    }employeeRecord;

int main(int argc, char *argv[])
{
  employeeRecord record;

#if 0
  // Commmand line arguments
  if (argc < 3)
    return 1;

  record.nameLength = strlen(argv[1]);
  record.name = (char *)malloc(sizeof(char)*(record.nameLength + 1));
  strncpy(record.name, argv[1], record.nameLength + 1);

  record.addressLength = strlen(argv[2]);
  record.address = (char *)malloc(sizeof(char)*(record.addressLength + 1));
  strncpy(record.address, argv[2], record.addressLength + 1);
#else
  // stdin
  char input[1024];

  fgets(input, sizeof(input), stdin);
  record.nameLength = strlen(input);
  record.name = (char *)malloc(sizeof(char)*(record.nameLength + 1));
  strncpy(record.name, input, record.nameLength + 1);

  fgets(input, sizeof(input), stdin);
  record.addressLength = strlen(input);
  record.address = (char *)malloc(sizeof(char)*(record.addressLength + 1));
  strncpy(record.address, input, record.addressLength + 1);
#endif

  record.phoneNumber = 5551212;

  FILE *fp = NULL;

  printf("sizeof(employeeRecord) = %lu\n", sizeof(employeeRecord));

  // Write
  fp = fopen("employeeRecord","w");
  fwrite(&record,sizeof(employeeRecord),1,fp);
  // Note: we're not including terminating NULLs.
  fwrite(record.name,sizeof(char),record.nameLength,fp);
  fwrite(record.address,sizeof(char),record.addressLength,fp);
  fclose(fp);

  // Read
  fp = fopen("employeeRecord","r");
  fread(&record,sizeof(employeeRecord),1,fp);
  printf("Number: %d\n",record.phoneNumber);

  char *nameString = (char *)malloc(sizeof(char)*(record.nameLength + 1));
  printf("\nName Length: %d",record.nameLength);
  fread(nameString,sizeof(char),record.nameLength,fp);
  nameString[record.nameLength] = '\0';
  printf("\nName: %s",nameString);
  printf("\n");

  fclose(fp);

  return 0;
}

OTHER TIPS

I would like to add my input....since you are dumping the memory structure to disk, the pointer addresses used to hold the data would most certainly be valid prior to dumping, but when reading from them, the pointer addresses could be invalid....which would explain why the character pointer is not showing the name...

Firstly, a nitpick: you never need sizeof (char) - it's 1, always, by definition.

As for the blank name output: do you perhaps need a newline after the %s to flush the output? I've seen weird behaviour when you leave this out, and you don't state which platform you are using. If the platform's printf() is implemented bizarrely enough, you could have the format string printed and flushed, but the name itself stuck in the C library's buffers when your program exits.

And I'm never happy about reading or writing blobs of binary data like a struct to and from files. Realise that by doing so you're promising your program that it will only ever read what it wrote on the same platform. You couldn't write a file on, say, a 64-bit host and read the file back in on a 16-bit microwave oven controller.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top