从二进制文件C中编写和读取结构

时间:2017-06-25 04:15:55

标签: c file-io struct

我只是想获取用户输入,将其存储在结构中,将其写入二进制文件,然后再次读取。这是一个联系簿类型计划的开始。 当我尝试检索单个结构的数据时,它不会读入我的readStruct,并且我在代码中的标记注释中出现了seg错误。

另外,请注意动态字符串和用户输入的混乱使用。我只是在玩耍并从中学习。

感谢。

下面是代码:

int main(void) {

  struct contactStruct {
    int phoneNumber;
    char * firstName;
    char * lastName;
    char * companyName;
  };
  struct contactStruct contact;
  struct contactStruct read;

  //Variable Declaration
  int j = 1;
  char tempInput[100] = "-";
  char * menuInput;
  char * searchInput;
  bool menuLoop = false;
  FILE * filePointer;

  filePointer = fopen("contactList.db", "r+");
  if (filePointer == NULL) {
    filePointer = fopen("contactList.db", "w+");
  }

  printf("Welcome to the Contact Book Program\n");
  printf("This program will let you store and access all of your contacts!\n");
  do {
    menuLoop = false;
    printf("Would you like to: 'ADD', 'EDIT', 'VIEW', or 'REMOVE' a contact? - ");
    fgets(tempInput, sizeof(tempInput), stdin);
    for (int i = 0; i < strlen(tempInput); i++) {
      tempInput[i] = tolower(tempInput[i]);
    }
    menuInput = malloc(sizeof(char) * strlen(tempInput) + 1);
    strcpy(menuInput, tempInput);

    if (strcmp(menuInput, "add\n") == 0) {
      printf("Phone Number: ");
      fgets(tempInput, sizeof(tempInput), stdin);
      contact.phoneNumber = atoi(tempInput);

      printf("First Name: ");
      fgets(tempInput, sizeof(tempInput), stdin);
      contact.firstName = malloc(sizeof(char) * strlen(tempInput) + 1);
      strcpy(contact.firstName, tempInput);

      printf("Last Name: ");
      fgets(tempInput, sizeof(tempInput), stdin);
      contact.lastName = malloc(sizeof(char) * strlen(tempInput) + 1);
      strcpy(contact.lastName, tempInput);

      printf("Company Name: ");
      fgets(tempInput, sizeof(tempInput), stdin);
      contact.companyName = malloc(sizeof(char) * strlen(tempInput) + 1);
      strcpy(contact.companyName, tempInput);

      fwrite( & contact, sizeof(struct contactStruct), 1, filePointer);

    } else if (strcmp(menuInput, "view\n") == 0) {
      printf("Who are you searching for? (First Name): ");
      scanf("%s", tempInput);
      searchInput = malloc(sizeof(char) * strlen(tempInput) + 1);
      strcpy(searchInput, tempInput); // Get name being searched for

      fread( & read, sizeof(struct contactStruct), 1, filePointer);

      printf("DEBUG - File Pos: %ld Size of Struct: %lu\n", ftell(filePointer), sizeof(struct contactStruct));
      printf("Input: %s Searching: %s\n", searchInput, read.firstName); //Seg Fault Happens Here

      if (strcmp(searchInput, read.firstName) == 0) {
        printf("Here is the contact information given:\n\n");
        printf("%d %s %s %s \n", read.phoneNumber, read.firstName, read.lastName, read.companyName);
      } else {
        printf("Did not find\n");
      }
    } else {
      printf("Invalid Option, Try Again.\n");
      menuLoop = true;
    }
  }
  while (menuLoop == true);
  free(menuInput);
  free(searchInput);
  fclose(filePointer);

  return 0;
}

1 个答案:

答案 0 :(得分:0)

问题在于您的结构:

struct contactStruct 
{
    int phoneNumber;
    char * firstName;  // <--  you have pointers, not data
    char * lastName;
    char * companyName;
};

将contactStruct保存到文件时,使用fwrite( & contact, sizeof(struct contactStruct), 1, filePointer);保存指向文件的指针值,而不是它们指向的字符串的内容。这意味着实际数据永远不会被保存,当您读取文件时,您的指针无处可寻。

如果你想要做的只是在你的文件中有固定长度的记录 - 我建议你这样做,现在,你应该改变你的结构来保存数据。长度。您必须根据需要决定字符串的长度。

#define CS_PHONE_LEN  11     // remember that your strings will need a zero termination.
#define CS_FIRSTNAME_LEN 24  // I've chosen arbitrary lengths for the demonstration.
#define CS_LASTNAME_LEN 24     
#define CS_COMPANY_LEN 24

struct contactStruct 
{
    char phoneNumber[CS_PHONE_LEN];    // phone numbers are usually stored as text. 
    char firstName[CS_FIRSTNAME_LEN];
    char lastName[CS_LASTNAME_LEN];
    char companyName[CS_COMPANY_LEN];
};

您必须注意程序中不要存储超过结构中定义的字符串的字符串,否则数据将会损坏。您可能希望使用strncpy_s()在数据成员中存储字符串,这里是函数http://en.cppreference.com/w/c/string/byte/strncpy的文档。

strncpy_s(cs.phoneNumber, CS_PHONE_LEN, userEntryString, CS_PHONE_LEN - 1);

如果您使用较旧的strncpy,请注意,如果源字符串太长,它将不会终止您的目标字符串。

strncpy(cs.phoneNumber, userEntryString, CS_PHONE_LEN - 1);
cs.phoneNumber[CS_PHONE_LEN - 1] = 0;  // make sure it's null-terminated.

一种更安全,另类的写作方式(上面是更经常使用的'经典'符号。

strncpy_s(cs.phoneNumber, sizeof(cs.phoneNumber), userEntryString, sizeof(cs.phoneNumber) - 1);

// or...

strncpy(cs.phoneNumber, userEntryString, sizeof(cs.phoneNumber) - 1);
cs.phoneNumber[sizeof(cs.phoneNumber) - 1] = 0;  // make sure it's null-terminated.

这样,您的写入与常量的名称无关,而长度总是正确的。