Home > Mobile >  Why am I getting a segmentation fault for CS50 Lab?
Why am I getting a segmentation fault for CS50 Lab?

Time:06-14

I am getting a segmentation fault on line 56.

    // Simulate genetic inheritance of blood type

    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>

    // Each person has two parents and two alleles
    typedef struct person
    {
        struct person *parents[2];
        char alleles[2];
    }
    person;

    const int GENERATIONS = 3;
    const int INDENT_LENGTH = 4;

    person *create_family(int generations);
    void print_family(person *p, int generation);
    void free_family(person *p);
    char random_allele();

    int main(void)
    {
        // Seed random number generator
        srand(time(0));

        // Create a new family with three generations
        person *p = create_family(GENERATIONS);

        // Print family tree of blood types
        print_family(p, 0);

        // Free memory
        free_family(p);
    }

    // Create a new individual with `generations`
    person *create_family(int generations)
    {
        // TODO: Allocate memory for new person

        person *p = malloc(sizeof(person));

        if (p == NULL) {
            printf("Memory not allocated.\n");
            exit(0);
        }

        // If there are still generations left to create
        if (generations > 1)
        {
            // Create two new parents for current person by recursively calling create_family
            // TODO: Recursively create blood type histories for parents
            person *person0 = create_family(generations - 1);
            person *person1 = create_family(generations - 1);


            // TODO: Randomly assign current person's alleles based on the alleles of their parents
            p->alleles[0] = p->parents[0]->alleles[rand() % 2];
            p->alleles[1] = p->parents[1]->alleles[rand() % 2];

        }

       // If there are no generations left to create
        else
        {
            // TODO: Set parent pointers to NULL
            p->parents[0] = NULL;
            p->parents[1] = NULL;

            // TODO: Randomly assign alleles
            p->alleles[0] = random_allele();
            p->alleles[1] = random_allele();


        }

        // TODO: Return newly created person
        return NULL;
    }

    // Free `p` and all ancestors of `p`.
    void free_family(person *p)
    {
        // TODO: Handle base case
        if (p == NULL)
        {
            return;
        }

        // TODO: Free parents recursively
        if (p->parents[0] != NULL)
        {
            free_family(p->parents[0]);
            free_family(p->parents[1]);
        }


        // TODO: Free child
        free(p);

    }

    // Print each family member and their alleles.
    void print_family(person *p, int generation)
    {
        // Handle base case
        if (p == NULL)
        {
            return;
        }

        // Print indentation
        for (int i = 0; i < generation * INDENT_LENGTH; i  )
        {
            printf(" ");
        }

        // Print person
        if (generation == 0)
        {
            printf("Child (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
        }
        else if (generation == 1)
        {
            printf("Parent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
        }
        else
        {
            for (int i = 0; i < generation - 2; i  )
            {
                printf("Great-");
            }
            printf("Grandparent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]);
        }

        // Print parents of current generation
        print_family(p->parents[0], generation   1);
        print_family(p->parents[1], generation   1);
    }

    // Randomly chooses a blood type allele.
    char random_allele()
    {
        int r = rand() % 3;
        if (r == 0)
        {
            return 'A';
        }
        else if (r == 1)
        {
            return 'B';
        }
        else
        {
            return 'O';
        }
    }

===========

    Use of uninitialised value of size 8
    ==3017==    at 0x40126A: create_family (inheritance.c:61)
    ==3017==    by 0x401235: create_family (inheritance.c:56)
    ==3017==    by 0x4011B1: main (inheritance.c:30)
    ==3017==  Uninitialised value was created by a heap allocation
    ==3017==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==3017==    by 0x4011F4: create_family (inheritance.c:44)
    ==3017==    by 0x401235: create_family (inheritance.c:56)
    ==3017==    by 0x4011B1: main (inheritance.c:30)

CodePudding user response:

To expand upon the comments and previous answers, I tested out your code. First off, as was noted, you need to return the pointer "p" instead of a NULL value. Also, the two lines of code where you are wanting to generate parents and grandparents need to be changed from

person *person0 = create_family(generations - 1);
person *person1 = create_family(generations - 1);

to

p->parents[0] = create_family(generations - 1);
p->parents[1] = create_family(generations - 1);

The pointers "*person0" and "*person1" appear to just be allocated structures that do not tie back to the child or grandchild. With those revisions, I was able to get a simple family tree with blood types.

Child (Generation 0): blood type AB
Parent (Generation 1): blood type AO
    Grandparent (Generation 2): blood type OA
    Grandparent (Generation 2): blood type OB
Parent (Generation 1): blood type BB
    Grandparent (Generation 2): blood type BB
    Grandparent (Generation 2): blood type OB

Hope that clarifies things.

Regards.

CodePudding user response:

At least this problem

Failed to return allocated pointer

    // return NULL;
    return p;
  •  Tags:  
  • c
  • Related