0

My background is in c# and i'm trying to learn C now. For this purpose, I am working on this sample program. What I want to do is read user inputs for each property of the Member and also assign Policies to each member in a loop. I managed to get this far but while im trying to read the Policy_Type I run into a Segmentation Fault error. I am struggling to understand why.

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

during a debug session with dbg, right after I enter the premium, I receive this error:

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

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

I am going crazy to figure out why. Could you please point me in the right direction?

Thanks a lot in advance.

3
  • newMember.policies is uninitialized. Commented Aug 7, 2021 at 8:55
  • You don't seem to allocate memory for the variable number of policies? Commented Aug 7, 2021 at 9:23
  • 1
    Also both scanf("%s", ...) and strcpy() are unsafe; prefer variants that won't overrun the end of the buffer? Commented Aug 7, 2021 at 9:27

3 Answers 3

3

When a struct member is an array without a specified size, it's called a flexible array member. In order to use that member, you must allocate some memory that matches the array size you need. Consequently you need to use pointers to struct Member instead of struct Member objects.

When you do

struct Member member;

there is no memory allocated for the array, i.e. accessing member.policies is illegal.

Instead use a pointer and dynamic memory allocation to get memory for the array - like:

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

As an alternative you can drop the use of a flexible array and simply use a pointer - like:

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

and do like:

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

    ...
Sign up to request clarification or add additional context in comments.

1 Comment

Mate, you're amazing. Thank you very much for this detailed explanation. I'll try it out.
1

In C, you must specify the number of structs when you define the struct statically. If you don't know how many policies a user has, you must specify the number of policy struct up to what you think is the biggest, or you can adopt a linked-list (in this case, you must allocate whenever you need to use a policy struct).

Comments

0

For anyone interested, this is how I got it to work:

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

rather than having a nested policy, i moved it out.

and built the member like this:

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

and then it worked.

> .\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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.