c - 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;
}
解决方案
我用你的输入数据启动了你的程序。无论您的程序是否因为缺少输入文件而崩溃。但是根据 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);
不,这绝对不是堆栈溢出。
推荐阅读
- jquery - Jquery替换嵌套范围内的文本
- react-native - React Native:错误:捆绑失败:index.js:“”不是有效的标识符名称
- angularjs - 从Angularjs中的数组中获取特定元素
- c# - 外键关系没有出现在 edmx 与 mysql 数据库与 asp mvc 与数据库第一
- angularjs - 在ajax formdata中获取415(不支持的媒体类型)发布到spring
- flutter - 如何在颤动中从 SelectableText 小部件中获取选定的文本
- json - 使用 Spark 2.4 识别空 JSON 文件
- c# - 在 Unity 中捕获 360 度屏幕截图会忽略 UI 层
- sql - 如何将一个 SQL 列转换为同一行的多个列?
- java - 在 Android 中,我如何实现一个全局触摸跟踪服务,即使屏幕上正在运行其他应用程序也能正常工作