【问题标题】:Understanding references to members in a struct within a struct, as well as how to dynamically allocate memory for struct members了解结构内结构中成员的引用,以及如何为结构成员动态分配内存
【发布时间】:2022-11-07 13:21:26
【问题描述】:

关于我面临的问题,我已经查看了几个不同的问题,虽然我觉得我已经获得了一些见解,但我肯定有可以使用帮助的问题,所以我想解决一个问题并获得一些帮助我在解决它时面临的问题。

我有一个员工注册表,我想创建一个结构“员工”,其中包含每个员工所需的数据字段。在这些字段中,我希望他们的“出生日期”有另一个结构,该结构在结构中有 3 个整数 - 指的是出生月份/日期/年份。 (见下文)

typedef struct DOB {
    int month;
    int day;
    int year;
} Birthdate;

typedef struct EmployeeInfo {
    int empID;
    char *firstName;
    char *lastName;
    Birthdate date;
    double salary;
} Employee;

现在我希望我的程序输出一个选项菜单并提示用户输入可能导致以下几个选项的输入:

  • 插入新员工
  • 更新/更改有关员工的信息
  • 搜索特定员工
  • 显示所有员工的所有信息
int main() {
  //create the array of Items
  Employee * employeeRecord = (Employee * ) malloc(N * sizeof(Employee));
  Birthdate * birthRecord = (Birthdate * ) malloc(N * sizeof(Birthdate));
  int empID;
  double salary;
  Employee Employee;
  Birthdate Birthdate;
  char opt;
  while (1) {
    dispayMenu();
    printf("Enter your Choice: ");
    scanf(" %c",&opt);
    switch(opt) {
        case 'i':
            printf("\nEnter empID: ");
            scanf("%d", & Employee.empID);
            printf("Enter firstName: ");
            scanf("%s", Employee.firstName);
            printf("Enter lastName: ");
            scanf("%s", & Employee.lastName);
            printf("Enter Date of Birth (month/day/year format): ");
            scanf("%d-%d-%d", &Employee.date.month,&Employee.date.day,&Employee.date.year);
            printf("Enter Employee salary: ");
            scanf("%lf", & Employee.salary);
            insertItem(employeeRecord, Employee);
            break;
        case 'u':
            printf("\nEnter empID to update: ");
            scanf("%d", & empID);
            updateItem(employeeRecord, empID);
            break;
        case 's':
            printf("\nEnter empID to search: ");
            scanf("%d", &empID);
            searchItem(employeeRecord, empID);
            break;
        case 'd':
            printData(employeeRecord);
            break;
        case 'q':
            quit(employeeRecord);
            break;
        default:
            printf("%c is not a valid choice", opt);
    }
  }
}

我的第一个问题是 - 如何动态更新包含所有员工的数组的大小?我目前遇到分段错误;我不想全局创建数组的大小;但我知道我只需要在必须将 Employee 添加到注册表时更新它 - 所以当我调用 insert 函数时 - 但我不知道如何在 main 中保留一个变量的计数,该变量在调用 insert 时更新.

第二个问题是关于更改出生日期 - 我知道我必须在某处使用 -> 运算符,以便我可以访问第二个结构中的字段,但是当我目前使用它时,它告诉我类型不匹配 -它是一个 int 但需要 char* 类型。那么如何访问结构中的数据以从 update() 函数进行更改。

void updateItem(Employee * employeeRecord, int empID) {
  int i;
  char chng;
  for (i = 0; i < current_size; i++)
  {
      if (employeeRecord[i].empID == empID)
      {
          printf("What data do you wish to update?: ");
          scanf(" %c", &chng);
          switch (chng)
          {
          case '1':
              printf("\nEnter new First Name: ");
              scanf("%s", &Employee.firstName);
              break;
          case '2':
              printf("\nEnter new Last Name: ");
              scanf("%s", &Employee.lastName);
              break;
          case '3':
              printf("\nEnter new Date of Birth: ");
              // scanf("%d", &empID);
              // searchItem(employeeRecord, empID);
              break;
          case '4':
              printf("\nEnter new salary: ") break;
          case '5':
              printf("\nReturning to main menu.");
              break;
          default:
              printf("%c is not valid, try it again.", opt);
          }
      }
    break;
  }
  else{
  printf("Employee Not Found");
}
}

我已经在上面描述过,但基本上似乎无法正确引用结构中的项目,并且无法从 main 正确调用函数 - 表示隐式声明与函数的类型不匹配,但这可能必须处理这些函数本身的错误。

【问题讨论】:

  • 请分享minimal reproducible example 而不是部分sn-ps。例如什么是N?您已经在 Employee 中嵌入了 Birthdate,那么为什么要单独分配 Birthdate?你这样做的方式很好,另一个选择是让日期成为一个指针。
  • 函数应该在被调用之前声明。因此,要么将函数定义移到 main 之前,要么为函数编写一个前向声明 AKA 原型并将其放在第一次调用之前。我个人不喜欢不必要的重复,所以我建议在调用之前将函数放在源文件中(所以main 始终是源文件中的最后一个函数)
  • @hyde op 它为我们提供了 sn-ps,因此他们可能已经在这样做而没有向我们展示。
  • @AllanWind 阅读了最后一段
  • @hyde 错过了第三个未编号的问题。我会相应地更新答案。

标签: c struct reference dynamic-memory-allocation


【解决方案1】:
  1. 您将员工存储在动态分配的数组中,然后使用realloc() 调整数组的大小:
    void insertItem(Enployee **employees, size_t *n, Employee e) {
       Employee *tmp = realloc((n+1) * sizeof(Employee));
       if (!tmp) {
          // fail
       }
       *employees = tmp;
       memcpy(*employees + *n, e, sizeof(Employee));
       (*n)++;
    }
    
    int main(void) {
    // ...
       Employee *employees = NULL;
       size_t n = 0;
    // ...
       case 'i': {
          Employee *e = malloc(sizeof(Employee));
          scanf("%d", e->empID);
    // ...
          insertItem(&employees, &n, e);
       }
    // ...
    }
    

    由于employeesn 属于一起,因此创建一个结构来保存它们是有意义的。

    1. Employee 结构内Birthdate date 也是一个结构。您可以使用 . 通过值访问结构的成员,并且 -> 如果您有指针。在updateItem() 中,您传入Employee *employeeRecord 并将其用作数组,因此您可以:
    employeeRecord[i].date.month = ...
    // or
    (employeeRecord + i)->date.month = ...
    
    1. 您只能引用已声明的函数,因此您需要最后一个 main()。另一个不错的选择是在顶部为您的函数添加声明。

【讨论】:

  • 使用realloc 进行单项插入是非常效率低下。更好地使用指数缓冲区分配策略。
  • @hyde 是的。 Op 显然正在学习,所以我认为现在引入这种复杂性不是一个好主意。这是一个玩具问题,所以性能并不重要。使用 sn-ps 我并没有写出所有缺失的代码来测试它,所以我也希望尽可能简单地说明解决方案,即使它并不理想。指数缓冲区分配也有问题;当您拥有大量数据时,您可能不想要 2 倍因子。对于小数据,您可能需要 10 倍。
猜你喜欢
  • 1970-01-01
  • 2012-08-27
  • 1970-01-01
  • 2021-06-04
  • 1970-01-01
  • 2021-08-25
  • 1970-01-01
  • 2012-12-26
  • 1970-01-01
相关资源
最近更新 更多