-2

I'm basically working on a program that allows you to make simple genograms, using C++ in a Linux environment. Here's the entire code I've made for now: genogram.h

#include <cstddef>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <vector> 
#include <fstream> 
#include <string>      

using namespace std; 

namespace genogram
{
    typedef string Name;
    typedef char Relationship;
    struct personNode; // to be defined in genogram.cpp
    typedef personNode* Genogram; // a genogram is identified by the pointer to the first person entered

    const Genogram emptyGenogram = nullptr;
    
    Genogram createEmptyGenogram();
    bool addPerson(Name, char, string, string, Genogram&);
    
    Genogram getMother(Name, const Genogram&);
    bool hasMother(Name, const Genogram&);
    Genogram getFather(Name, const Genogram&);
    bool hasFather(Name, const Genogram&);
    Genogram getPartner(Name, const Genogram&);
    bool hasPartner(Name, const Genogram&);
    bool arePartners(Name, Name, const Genogram&);
    bool hasSons(Name, const Genogram&);
    bool isSon(Name, Name, const Genogram&);
    bool areBrothers(Name, Name, const Genogram&);
    
    bool areRelated(Name, Name, const Genogram&);
    
    bool addRelMother(Name, Name, Genogram&);
    bool addRelFather(Name, Name, Genogram&);
    bool addRelCouple(Name, Name, Genogram&);
    bool addRelChildToCouple(Name, Name, Name, Genogram&);
    
    void printGenogram(Genogram);
    
    bool deletePerson(Name, Genogram&);
}

genogram.cpp

#include "genogram.h"

using namespace genogram;


void debugg(int n)
{
    cout << n << endl;
}


struct son
{
    personNode* person;
    son* nextSon;
};

son* emptySon = nullptr;

struct genogram::personNode
{
    Name name;
    char sex;
    string birthDate;
    string deathDate;
    personNode* mother;
    personNode* father;
    personNode* partner;
    son* linkSons;
    personNode* nextPerson;
    bool visited;
};

//**************************************************//

//Returns an empty Genogram
Genogram genogram::createEmptyGenogram()
{
    return emptyGenogram;
}

//**************************************************//

Genogram createPerson(Name n, char sex, string bDate, string dDate)
{
    personNode* p = new personNode;
    p->name = n;
    if(sex=='M'||sex=='F')
        p->sex = sex;
    else
        return emptyGenogram;
    p->birthDate = bDate;
    p->deathDate = dDate;
    p->mother = emptyGenogram;
    p->father = emptyGenogram;
    p->partner = emptyGenogram;
    p->linkSons = emptySon;
    p->visited = false;
    return p;
}

son* createSon(personNode* p)
{
    son* s = new son;
    s->person = p;
    s->nextSon = emptySon;
    return s;
}

personNode* getPerson(Name n, Genogram g)
{
    Genogram aux = g;
    while (aux!=emptyGenogram)
    {
        if(aux->name==n)
            return aux;
        aux=aux->nextPerson;
    }
    return emptyGenogram;
}

bool member(Name n, Genogram g)
{
    return (getPerson(n,g)!=emptyGenogram);
}

bool genogram::addPerson(Name n, char sex, string bDate, string dDate, Genogram& g)
{   
    if(member(n,g))
        return false;
    Genogram aux = createPerson(n,sex,bDate,dDate);
    if(aux==emptyGenogram)
        return false;
    aux->nextPerson = g;
    g = aux;
    return true;
}

//**************************************************//

Genogram genogram::getMother(Name n, const Genogram& g)
{
    if(member(n,g))
        return getPerson(n,g)->mother;
    return emptyGenogram;
}

bool genogram::hasMother(Name n, const Genogram& g)
{
    return getMother(n,g)!=emptyGenogram;
}

Genogram genogram::getFather(Name n, const Genogram& g)
{
    if(member(n,g))
        return getPerson(n,g)->father;
    return emptyGenogram;
}

bool genogram::hasFather(Name n, const Genogram& g)
{
    return getFather(n,g)!=emptyGenogram;
}

Genogram genogram::getPartner(Name n, const Genogram& g)
{
    if(member(n,g))
        return getPerson(n,g)->partner;
    return emptyGenogram;
}

bool genogram::hasPartner(Name n, const Genogram& g)
{
    return getPartner(n,g)!=emptyGenogram;
}

bool genogram::arePartners(Name n1, Name n2, const Genogram& g)
{
    if(hasPartner(n1,g))
        return (getPartner(n1,g)->name==n2);
    else
        return false;
}

son* getSonList(Name n, const Genogram& g)
{
    if(member(n,g))
        return getPerson(n,g)->linkSons;
    return emptySon;
}

bool genogram::hasSons(Name n, const Genogram& g)
{
    return getSonList(n,g)!=emptySon;
}

bool genogram::isSon(Name s, Name p, const Genogram& g)
{
    if(hasSons(p,g))
    {
        son* sonAux = getSonList(p,g);
        while(sonAux!=emptySon)
        {
            if(sonAux->person->name==s)
                return true;
            sonAux = sonAux->nextSon;
        }
    }
    return false;
}

bool genogram::areBrothers(Name n1, Name n2, const Genogram& g)
{
    son* sonAux = emptySon;
    if(hasMother(n1,g))
    {
        sonAux = getSonList(getMother(n1,g)->name,g);
        while(sonAux!=emptySon)
        {
            if(sonAux->person->name==n2)
                return true;
            sonAux = sonAux->nextSon;
        }
    }
    if(hasMother(n1,g))
    {
        sonAux = getSonList(getFather(n1,g)->name,g);
        while(sonAux!=emptySon)
        {
            if(sonAux->person->name==n2)
                return true;
            sonAux = sonAux->nextSon;
        }
    }
    return false;
}

bool genogram::areRelated(Name n1, Name n2, const Genogram& g)
{
    if(hasMother(n1,g))
    {
        Genogram aux = getMother(n1,g);
        //when here, segment. fault
        if(aux->name==n2)
            return true;
    }
    if(hasMother(n2,g))
        if(getMother(n2,g)->name==n1)
            return true;
    if(hasFather(n1,g))
        if(getFather(n1,g)->name==n2)
            return true;
    if(hasFather(n2,g))
        if(getFather(n2,g)->name==n1)
            return true;
    if(arePartners(n1,n2,g))
        return true;
    if(isSon(n1,n2,g))
        return true;
    if(isSon(n2,n1,g))
        return true;
    if(areBrothers(n1,n2,g))
        return true;
    return false;
}

//**************************************************//

bool genogram::addRelMother(Name s, Name m, Genogram& g)
{
    if(hasMother(s,g)||!member(s,g)||!member(m,g)||s==m)
        return false;
    personNode* aux = getPerson(s,g);
    aux->mother = getPerson(m,g);
    
    personNode* aux2 = getPerson(m,g);
    son* sonAux = createSon(getPerson(s,g));
    sonAux->nextSon = aux2->linkSons;
    aux2->linkSons = sonAux;
    return true;
}

bool genogram::addRelFather(Name s, Name f, Genogram& g)
{
    if(hasFather(s,g)||!member(s,g)||!member(f,g)||s==f)
        return false;
    personNode* aux = getPerson(s,g);
    aux->father = getPerson(f,g);
    
    personNode* aux2 = getPerson(f,g);
    son* sonAux = createSon(getPerson(s,g));
    sonAux->nextSon = aux2->linkSons;
    aux2->linkSons = sonAux;
    return true;
}

bool genogram::addRelCouple(Name n1, Name n2, Genogram& g)
{
    if(arePartners(n1,n2,g))
        return true;
    if(areRelated(n1,n2,g)||hasPartner(n1,g)||hasPartner(n2,g)||!member(n1,g)||!member(n2,g)||n1==n2)
        return false;
    personNode* aux = getPerson(n1,g);
    aux->partner = getPerson(n2,g);
    
    personNode* aux2 = getPerson(n2,g);
    aux2->partner = getPerson(n1,g);
    return true;
}

bool genogram::addRelChildToCouple(Name s, Name m, Name f, Genogram& g)
{
    if(!arePartners(m,f,g))
        return false;
    return (addRelMother(s,m,g) && addRelFather(s,f,g));
}

//**************************************************//

void genogram::printGenogram(Genogram g)
{
    Genogram aux = g;
    son* sonAux = emptySon;
    while (aux!=emptyGenogram)
    {
        cout << "-----------------\n";
        cout << "Name: " << aux->name << "; sex: " << aux->sex << "; born: " << aux->birthDate << "; dead: " << aux->deathDate;
        cout << ";\n - mother: ";
        if(aux->mother!=emptyGenogram)
            cout << aux->mother->name << ";";
        cout << "\n - father: ";
        if(aux->father!=emptyGenogram)
            cout << aux->father->name << ";";
        cout << "\n - partner: ";
        if(aux->partner!=emptyGenogram)
            cout << aux->partner->name << ";";
        cout << "\n - sons: ";
        sonAux = aux->linkSons;
        if(aux->linkSons!=emptySon)
        {
            while(sonAux!=emptySon)
            {   
                cout << sonAux->person->name << "; ";
                sonAux = sonAux->nextSon;
            }
            cout << "\b\b.";
        }
        aux = aux->nextPerson;
        cout << "\n";
    }
    cout << "-----------------\n";
}

//**************************************************//


bool genogram::deletePerson(Name n, Genogram& g)
{
    return true;
}

And then here's the main.cpp where I did some tests:

#include <cstdlib>
#include <iostream>

////////////////////////////////////////////////////////////////////////
// Test main
////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <string>
#include "genogram.h"

using namespace std;

int main()
{
    genogram::Genogram g = genogram::createEmptyGenogram();
    genogram::addPerson("Mark",'M',"25/09/2001","29/07/2020",g);
    genogram::addPerson("Elizabeth",'F',"31/02/2003","-",g);
    genogram::addPerson("Karl",'M',"04/03/2020","-",g);
    genogram::addRelCouple("Elizabeth","Mark",g);
    
    genogram::addRelMother("Karl","Elizabeth",g);
    if(genogram::areRelated("Elizabeth","Karl",g))  //  true)//
        cout << "Test1: success" << endl;
    else
        cout << "Test1: no success" << endl;
    
    if(genogram::areRelated("Karl","Mark",g))
        cout << "Test2: success" << endl;
    else
        cout << "Test2: no success" << endl;
}

Basically, the problem I'm having is that, after I use addRelMother("sonName","motherName",g) to create the relationship between the son and the mother, when I try to see if "sonName" is related in any way to "anotherName" using the function areRelated("sonName","anotherName",g), a segmentation fault (core dumped) error occurs. More specifically, when this function is executed, it first checks if "sonName" already has a mother assigned to him using the function hasMother("sonName",g) (which basically simply checks if the function getMother("sonName",g) returns emptyGenogram, which is an alias for nullptr, or not). After it has returned true in the if statement, it tries to point to the mother's name, but even though getMother("sonName",g) doesn't return an emptyGenogram, if I point to the name field a segmentation fault (core dumped) error happens.

bool genogram::areRelated(Name n1, Name n2, const Genogram& g)
{
    if(hasMother(n1,g))
    {
        Genogram aux = getMother(n1,g);
        //when here, segment. fault
        if(aux->name==n2)
            return true;
    }

Can somebody help me find the reason of why this happens?

  • Overall design aside, `using namespace std;` is a bad idea, **especially** in a header. – sweenish Jun 27 '21 at 11:44
  • You are not checking if getMother() will return emptyGenogram which you have defined as nullptr. Ofcource that this will crash. I will also suggest refactoring your code, it create/destroy too many new objects everywhere without need and is hard to track. – Baj Mile Jun 27 '21 at 11:47
  • @BajMile I don't think that thing is the problem, simply because before using getMother() I use hasMother(), that simply checks if getMother() returns emptyGenogram or not... In fact, I did some testing and I can tell you that it ***doesn't*** return any emptyGenogram... But even though it's not an emptyGenogram, if I point to the name field of the mother, segmentation fault happens... – Bruno Bernardini Jun 27 '21 at 12:19
  • Please start using const references everywhere when possible. For example Name n1, Name n2 --> const Name& n1...., Also in genome.cpp, should have the namespace genogram also contain the code like in the header. Your project seems interesting so I wish you luck :) – Baj Mile Jun 27 '21 at 12:40
  • @BajMile Thank you so much! It's a project for university stuff, eventually it got interesting to me too, ahah! EDIT: Also thank you for your corrections, very appreciated. :) – Bruno Bernardini Jun 27 '21 at 12:53
  • Please, before even posting here, extract a [mcve]. Not only is it required as part of your question, it also helps you to focus on the actual problem. As a new user here, also take the [tour] and read [ask]. – Ulrich Eckhardt Jun 27 '21 at 13:07

1 Answers1

0

Your code is crashing at this line:

 sonAux = getSonList(getFather(n1, g)->name, g);

You can easy see that getFather() is returning null:

 Genogram gg = getFather(n1, g);  // it is null
 sonAux = getSonList(gg->name, g);

You need to simplify and refactor your code. Also consider using smart pointers.

Baj Mile
  • 750
  • 1
  • 8
  • 17