c - 从二进制文件 C 中写入和读取结构

标签 c file-io struct

我只是想获取用户输入,将其存储在结构中,将其写入二进制文件,然后再次读取。它用于启动通讯录类型的程序。 当我尝试检索单个结构的数据时,它不会读入我的 readStruct,并且我在代码中标记的注释处出现段错误。

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

谢谢。

代码如下:

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

最佳答案

问题出在你的结构上:

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,请注意,如果源字符串太长,它不会以 null 终止您的目标字符串。

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.

这样,您的写入就独立于常量的名称,而长度始终是正确的。

关于c - 从二进制文件 C 中写入和读取结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44743145/

相关文章:

c - C语言读取内存

ruby - 如何在文件夹及其所有子文件夹中搜索某种类型的文件

python - 如何在目录中找到带有 .MP3 扩展名的最新文件?

c - C 结构体中的 Sizeof 指针

c++ - "Does not name a type"类错误

c - 如何使用线程更改函数中的结构变量?

c - 如何通过按 'Enter' 键而不是任何字母键来结束 while 循环?

c - Linux 上 POSIX 函数 "stat"的定义在哪里?

c - 从文件创建 1 和 0 的矩阵 NxN 的 C 程序中的段错误

c - 记住最后执行的命令的简单历史记录