指向非 nullptr 结构时出现分段错误

问题描述

我基本上正在开发一个程序,该程序允许您在 Linux 环境中使用 C++ 制作简单的基因图。 这是我现在编写的完整代码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,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,const Genogram&);
    bool arebrothers(Name,const Genogram&);
    
    bool areRelated(Name,const Genogram&);
    
    bool addRelMother(Name,Genogram&);
    bool addRelFather(Name,Genogram&);
    bool addRelCouple(Name,Genogram&);
    bool addRelChildToCouple(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,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,g)->father;
    return emptyGenogram;
}

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

Genogram genogram::getPartner(Name 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,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,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);
        while(sonAux!=emptySon)
        {
            if(sonAux->person->name==n2)
                return true;
            sonAux = sonAux->nextSon;
        }
    }
    return false;
}

bool genogram::areRelated(Name n1,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,g))
        return true;
    if(isSon(n2,n1,g))
        return true;
    if(arebrothers(n1,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(f,g)||s==f)
        return false;
    personNode* aux = getPerson(s,g);
    aux->father = getPerson(f,g);
    
    personNode* aux2 = getPerson(f,g));
    sonAux->nextSon = aux2->linkSons;
    aux2->linkSons = sonAux;
    return true;
}

bool genogram::addRelCouple(Name n1,Genogram& g)
{
    if(arePartners(n1,g))
        return true;
    if(areRelated(n1,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,Genogram& g)
{
    if(!arePartners(m,f,g))
        return false;
    return (addRelMother(s,m,g) && addRelFather(s,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;
}

然后这里是 ma​​in.cpp,我在这里做了一些测试:

#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","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",g))
        cout << "Test2: success" << endl;
    else
        cout << "Test2: no success" << endl;
}

基本上,我遇到的问题是,之后我使用 addRelMother("sonName","motherName",g) 来创建儿子和母亲之间的关系,当我尝试使用函数 "sonName" 查看 "anotherName" 是否以任何方式与 areRelated("sonName","anotherName",g) 相关,会发生分段错误(核心转储)错误。更具体地说,当这个函数被执行时,它首先检查 "sonName" 是否已经使用函数 hasMother("sonName",g) 为他分配了一个母亲(它基本上只是检查函数 getMother("sonName",g) 是否返回 {{1 }},它是 nullptr 的别名,或者不是)。在 if 语句中返回 true 后,它会尝试指向母亲的名字,但即使 emptyGenogram 不返回 {{1} },如果我指向 name 字段,则会发生分段错误(核心转储)错误

getMother("sonName",g)

有人可以帮我找出发生这种情况的原因吗?

解决方法

您的代码在这一行崩溃了:

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

你可以很容易地看到 getFather() 正在返回 null:

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

您需要简化和重构您的代码。还可以考虑使用智能指针。