读取字符串时出现C程序段错误

C program segmentation fault when reading string

我的背景是 c#,我现在正在努力学习 C。 为此,我正在研究这个示例程序。 我想要做的是读取每个 属性 成员的用户输入,并在循环中为每个成员分配策略。我设法做到了这一点,但是当我试图将 Policy_Type 读入时,我 运行 变成了 Segmentation Fault 错误。我很难理解为什么。

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

enum PolicyType
{
    Car = 1,
    Health = 2,
    Travel = 3,
    Pet = 4
};

// Member structure
struct Member
{
    int Member_ID;
    char Name[20];
    int Policy_Count; 
 
    // Policy structure
    struct Policy
    {
        char Policy_ID[20];
        int Member_ID;
        char Policy_Type[20];
        int Premium;
    } policies[]; // each member could maintain 0 or many policies - nested structure
};

void mainMenu(){
    printf("1. Add new member\n");
    printf("2. Display all members\n");
    printf("3. Search member by name\n");
    printf("4. Calculate total premium\n");
    printf("5. Exit\n");

    printf("Enter your choice--- ");
};

struct Member collectNewMemberDetails(){
    struct Member member;

    printf("a. Enter the member details:\n");
    
    printf("b. Member Name:\n");
    scanf("%s", member.Name); // saves the member name in structure

    printf("c. Member ID:\n");
    scanf("%d", &member.Member_ID);

    printf("d. How many policies for the member:\n"); 
    scanf("%d", &member.Policy_Count);
  
    for (int i = 0; i < member.Policy_Count; i++)
    {
        char policyId[20];
        char policyType[20];
        int policyPremium;

        printf("a. Enter Policy ID: \n");
        scanf("%s", policyId);

        printf("b. Enter Policy Type: \n");  
        scanf("%s", policyType);
          
        printf("c. Enter Policy Premium: \n");
        scanf("%d", &policyPremium);

        strcpy(member.policies[i].Policy_ID, policyId );
        strcpy(member.policies[i].Policy_Type, policyType );
        member.policies[i].Premium = policyPremium;
        member.policies[i].Member_ID = member.Member_ID;
    }
     
    return member;
} 

int main(int argc, char const *argv[])
{
    mainMenu();

    int choice;
    scanf("%d", &choice);
    
    struct Member newMember;
    switch (choice)
    {
    case 1:
        newMember = collectNewMemberDetails();
        break;
    
    default:
        break;
    }

   
     printf("Member name: %s\n", newMember.Name);
     printf("Member Policy Type: %s\n", newMember.policies[0].Policy_Type);
    return 0;
}

在与 dbg 的调试会话期间,在我输入 premium 后,我收到此错误:

-- omitted for brevity 
c. Enter Policy Premium: 
22

Thread 1 received signal SIGSEGV, Segmentation fault.
0x0000002b in ?? ()

我快要疯了,想知道为什么。 你能给我指明正确的方向吗?

非常感谢。

当一个结构体成员是一个没有指定大小的数组时,它被称为灵活的数组成员。为了使用该成员,您必须分配一些与您需要的数组大小相匹配的内存。因此,您需要使用指向 struct Member 而不是 struct Member 对象的指针。

当你做的时候

struct Member member;

没有为数组分配内存,即访问member.policies是非法的。

而是使用指针和动态内存分配来为数组获取内存——例如:

struct Member* member;
size_t array_size = INPUT_THE_NUMBER_OF_POLICIES();
member = malloc(sizeof *member + array_size * sizeof(struct Policy));
                \------------/   \--------------------------------/
                 Memory for         Memory  for the policies-array
                 first three
                 struct members

作为替代方案,您可以放弃使用灵活的数组并简单地使用指针 - 如:

struct Member
{
    int Member_ID;
    char Name[20];
    int Policy_Count; 
    struct Policy * policies;
};

并喜欢:

struct Member collectNewMemberDetails(){
    struct Member member;

    ...

    printf("d. How many policies for the member:\n"); 
    if (scanf("%d", &member.Policy_Count) != 1) exit(1);
    assert(Policy_Count > 0);

    member.policies = malloc(member.Policy_Count * sizeof *member.policies);

    ...

在C语言中,静态定义结构时必须指定结构的个数。如果你不知道一个用户有多少条策略,你必须指定策略结构的数量,最多你认为是最大的,或者你可以采用链表(在这种情况下,你必须在需要时分配使用策略结构)。

对于任何感兴趣的人,这就是我如何让它工作的:

// Policy structure
struct Policy
{
    char Policy_ID[20]; // the policy id
    int Member_ID; // owner member id of this policy
    char Policy_Type[20]; // array to hold policy type. 
    int Premium; // premium amount
};

// Member structure
struct Member
{
    int Member_ID; // member id
    char Name[20]; // member name
    int Policy_Count; // how many number of policies this member own
 
    struct Policy * policies; // each member could maintain 0 or many policies - nested structure
};

我没有使用嵌套策略,而是将其移出。

并像这样构建成员:

struct Member collectNewMemberDetails(){
    struct Member member;
 
    printf("b. Member Name:\n");
    scanf("%s", member.Name); // saves the member name in structure
 
    printf("d. How many policies for the member:\n"); 
    scanf("%d", &member.Policy_Count);
   
    // without doing this gave me error Segmentation Fault. 
    // after googling I found out i need to allocate memory for my array
    member.policies = malloc(member.Policy_Count * sizeof *member.policies);

    for (int i = 0; i < member.Policy_Count; i++)
    {
        // create a new policy
        struct Policy membePolicy;
        membePolicy.Member_ID = member.Member_ID; // attach the member id to this policy

        printf("a. Enter Policy ID: \n");
        scanf("%s", &membePolicy.Policy_ID); // set the policy id

        printf("b. Enter Policy Type: \n");  
        scanf("%s", &membePolicy.Policy_Type); // set the policy type
          
        printf("c. Enter Policy Premium: \n");
        scanf("%d", &membePolicy.Premium); // set the premium of this policy
  
        member.policies[i] = membePolicy; // set the policy to member
    }
     
    return member;
} 

然后成功了。

> .\policy.exe
1. Add new member
2. Display all members
3. Search member by name
4. Calculate total premium
5. Exit
Enter your choice--- 1
a. Enter the member details:
b. Member Name:
romesh
c. Member ID:
111
d. How many policies for the member:
1
a. Enter Policy ID: 
1 
b. Enter Policy Type: 
Car
c. Enter Policy Premium: 
233
Member name: romesh
Member Policy Type: Car