首页 > 解决方案 > SIGSEGV 访问 C 中结构的参数

问题描述

我已经编写了一个基本的数据结构来解决 C 中的递归问题。我不明白为什么在一个特定情况下我会遇到分段错误,即使在其他情况下似乎工作得很好。这里只是代码的主要部分:如果你有耐心,这里是完整的代码。

typedef struct{
    char color;
    int val;
}pipe;

typedef struct _tile tile;

struct _tile{
    pipe pipe1;
    pipe pipe2;
    int inUse;
};

typedef struct{
    tile *theTiles;
    tile *possibleTiles;
    int tileNum;
    int numInUse;
}tileCollection;

typedef struct{
    tile *tilePointer;
    int rotation;
}box;

typedef struct{
    box **board;
    box **solMax;
    int nCol;
    int nRow;
}boardWrap;


void findMax(boardWrap *theBoardWrap, tileCollection *theTileColl, int col, int row){

    if(col == (theBoardWrap->nCol-1)){//se sono arrivato alla fine della riga
        if(row == (theBoardWrap->nRow -1)){//sono arrivato alla fine della scacchiera
            if(evaluateScore(theBoardWrap)){// se la soluzione è massima
                theBoardWrap->solMax = theBoardWrap->board; // copio la soluzione max
            }
            return;
        }
        findMax(theBoardWrap, theTileColl, 0, row+1);//ricorro sulla riga successiva, alla prima colonna
    }

    if(theBoardWrap->board[col][row].tilePointer != NULL){//se la casella è già occupata
            findMax(theBoardWrap, theTileColl, col+1, row); //ricorro sulla colonna successiva
    }
    else{//se la casella è vuota
        for(int i = 0; i < (theTileColl->tileNum * 2); i++){//ciclo che scorre tutte le possibili piastrelle inseribili
            if(theTileColl->possibleTiles[i].inUse == 0){//controllo se la posso mettere
                theTileColl->possibleTiles[i].inUse = 1;//la marco come inserita
                //inserimento piastrella
                theBoardWrap->board[col][row].tilePointer = &theTileColl->possibleTiles[i];//inserisco la piastrella
                findMax(theBoardWrap, theTileColl, col+1, row);//ricorro sulla colonna successiva
                theTileColl->possibleTiles[i].inUse = 0;//BACKTRACK
            }
        }
    }
}

int evaluateScore(boardWrap *theBoardWrap){//ritorna '1' se il valore attuale è maggiore del Max passato, '0' se non è così
    int scoreBoard1, scoreBoardMax;

    scoreBoardMax = boardScoreCalc(theBoardWrap, theBoardWrap->solMax);
    scoreBoard1 = boardScoreCalc(theBoardWrap, theBoardWrap->board);
    if(scoreBoard1 > scoreBoardMax) {
        return 1;
    }
    else
            return 0;
    }

int boardScoreCalc(boardWrap *theBoardWrap, box **board){//se passo la la board by reference ho un SIGSEGV, se la passo by value no
    int flagRowColor = 0, flagColColor = 0;
    int totScoreRow = 0;
    int totScoreCol = 0;
    int rowPoints[theBoardWrap->nRow], colPoints[theBoardWrap->nCol];

    for(int i = 0; i < theBoardWrap->nRow; i++){
        for(int j = 0; j < theBoardWrap->nCol; j++){
            //calcolo il punteggio per la riga
            if(j == 0){//inizio riga
                rowPoints[i] = board[i][j].tilePointer->pipe1.val;
                flagRowColor = 1;
            }
            else if(matchColor(theBoardWrap->board[i][j].tilePointer->pipe1.color,theBoardWrap->board[i][j-1].tilePointer->pipe1.color) && flagRowColor){
                rowPoints[i] += board[i][j].tilePointer->pipe1.val;
            }
            else{
                rowPoints[i] = 0;
                flagRowColor = 0;
            }
            //calcolo il punteggio per le colonne
            if(i == 0){//inizio colonna
                colPoints[j] = board[i][j].tilePointer->pipe2.val;
                flagColColor = 1;
            }
            else if(matchColor(theBoardWrap->board[i][j].tilePointer->pipe1.color,theBoardWrap->board[i-1][j].tilePointer->pipe1.color) && flagColColor){//HERE I GET SEGSIGV
                colPoints[j] += board[i][j].tilePointer->pipe2.val;
            }
            else {
                colPoints[j] = 0;
                flagColColor = 0;
            }
        }
    }
    for(int i = 0; i < theBoardWrap->nRow; i++){
        totScoreRow += rowPoints[i];
    }
    for(int j = 0; j < theBoardWrap->nCol; j++){
        totScoreCol *= colPoints[j];
    }
    return totScoreCol + totScoreRow;
}

标签: cstructsegmentation-fault

解决方案


我用你的输入数据启动了你的程序。无论您的程序是否因为缺少输入文件而崩溃。但是根据 GDB 输出,您的程序没有填充theBoardWrap->board[2][0].tilePointer第 241 行的字段并尝试取消引用它。我的建议是学习使用调试器(如 GDB),使用断言<assert.h>,非常准确地处理手动分配的内存,至少执行与NULL指针的比较,如下所示:

assert(theBoardWrap != NULL);
assert(theBoardWrap->board[i][j].tilePointer != NULL);
assert(theBoardWrap->board[i-1][j].tilePointer != NULL);

不,这绝对不是堆栈溢出。


推荐阅读