Строка динамического размера двоичного файла - PullRequest
0 голосов
/ 08 марта 2010

Я работал над этим заданием, где мне нужно прочитать «записи» и записать их в файл, а затем иметь возможность прочитать / найти их позже. При каждом запуске программы пользователь может решить записать новую запись или прочитать старую запись (по имени или #)

Файл является двоичным, вот его определение:

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

Как работает программа, она будет хранить структуру, затем имя, затем адрес. Имя и адрес распределяются динамически, поэтому сначала необходимо прочитать структуру, чтобы найти размер имени и адреса, выделить для них память, а затем прочитать их в этой памяти.

На данный момент у меня есть две программы для отладки. У меня есть программа для записи файлов и чтения файлов.

Моя настоящая проблема заключается в следующем: когда я читаю файл, который я написал, я читаю в структуре, распечатываю телефон #, чтобы убедиться, что он работает (работает нормально), а затем перечитываю имя (теперь могу используйте record.nameLength, который также сообщает правильное значение). Fread, однако, не возвращает пригодного имени, он возвращает пустое.

Я вижу две проблемы: либо я неправильно записал имя в файл, либо неправильно прочитал. Вот как я пишу в файл: где fp - указатель файла. record.name - правильное значение, как и record.nameLength. Также я пишу имя, включая нулевой терминатор. (например, «Джек \ 0»)

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

И тогда я закрываю файл. вот как я читаю файл:

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

Обратите внимание, что там есть некоторые отладочные материалы (длина и номер имени, оба из которых являются правильными). Итак, я знаю, что файл открыт правильно, и я могу использовать длину имени в порядке. Почему тогда мой вывод пуст, или перевод строки, или что-то в этом роде? (Вывод - просто Имя: после него ничего не происходит, и программа просто завершается)

Спасибо за помощь.

Ответы [ 3 ]

1 голос
/ 08 марта 2010

Я попробовал ваш код, и он работал нормально. По порядку вот вывод, hexdump файла и ваш исходный код, скомпилированный.

Обновление: обновлен код для чтения имени и адреса из аргументов стандартного ввода или командной строки.

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;
}
0 голосов
/ 09 марта 2010

Во-первых, придирка: вам никогда не нужен sizeof (char) - это всегда 1, по определению.

Что касается вывода пустого имени: вам, возможно, нужен символ новой строки после% s, чтобы очистить вывод? Я видел странное поведение, когда вы опускаете это, и вы не указываете, какую платформу вы используете. Если printf () платформы реализован достаточно странно, вы можете напечатать и очистить строку формата, но само имя застрянет в буферах библиотеки C при выходе из программы.

И я никогда не рад чтению или записи больших двоичных данных, таких как структура, в файлы и из файлов. Осознайте, что таким образом вы обещаете своей программе, что она будет когда-либо читать только то, что написала на той же платформе . Вы не можете записать файл, скажем, на 64-битном хосте и прочитать файл обратно на 16-битном контроллере микроволновой печи.

0 голосов
/ 08 марта 2010

Я хотел бы добавить свой ввод .... поскольку вы выгружаете структуру памяти на диск, адреса указателей, используемые для хранения данных, наверняка будут действительны до сброса, но при чтении из них адреса указателей может быть недействительным .... что объясняет, почему указатель символа не показывает имя ...

...