【问题标题】:Segmentation fault, structs, ncurses, drawing分段错误,结构,ncurses,绘图
【发布时间】:2014-03-14 19:14:39
【问题描述】:

我的代码出现分段错误。我的代码是:

#define STARTING_POINT 5
int main(int argc, char *argv[])
{
input(argc, argv);
parser(argc, argv);
drawingRooms();
return 0;
}


void drawingRooms(room roomInfo[6]) 
{
int rooms;
int i;
int positionX;
int positionY;
rooms = 0;
initscr();
noecho();
for(rooms = 0; rooms < 6; rooms++)
{
    switch(rooms)
    {
        case 0:
        for(i = 0; i <= roomInfo[rooms].length; i++);
        {
            move(STARTING_POINT + i, STARTING_POINT);
            printw("|");
        }
        break;
    }
}   
getch();
endwin();
}


void parser(int argc, char **argv)
{
FILE * rooms;
char * theString;
char * theToken;
int width;
int length;
int k;
int x;
int placeInt;
int posX;
int posY;
char a[ROOM_STRING_LENGTH];
item gold;
item monster;
item potion;
item hero;
item stairs;
room roomInfo[6];
rooms = fopen(argv[1], "r");

if(rooms == NULL)
{
    printf("error opening file\n");
}
x = 0;
while(fgets(a, ROOM_STRING_LENGTH, rooms) != NULL)
{ 

    theString = malloc((sizeof(char)*(strlen(a)+1)));
    strcpy(theString, a);

    for(theToken = strtok(theString, " "); theToken; theToken = strtok(NULL, " "))
    {
        sscanf(theToken, "%dX%d", &length, &width);
        roomInfo[x].roomNumber = x;
        roomInfo[x].width = width;
        roomInfo[x].length = length;

        if(theToken[0] == 'd')
        {
            switch(theToken[1])
            {
                case 'e':
                {
                    placeInt = theToken[2] - '0';
                    roomInfo[x].eastDoor = placeInt;
                    break;
                }
                case 'w':
                {
                    placeInt = theToken[2] - '0';
                    roomInfo[x].westDoor = placeInt;
                    break;
                }
                case 's':
                {
                    placeInt = theToken[2] - '0';
                    roomInfo[x].southDoor = placeInt;
                    break;
                }
                case 'n':
                {
                    placeInt = theToken[2] - '0';
                    roomInfo[x].northDoor = placeInt;
                    break;
                }
                default:
                {
                    break;
                } 
            }       
        }

        else if(theToken[0] == 'g' || theToken[0] == 'm' || theToken[0] == 'p' || theToken[0] == 'h')
        {
             k = 0;
             while(k <= (strlen(theToken)))
             {

                 switch(theToken[k])
                 {
                     case 'g':
                     posY = theToken[1] - '0';
                     posX = theToken[3] - '0';

                     gold.Xposition = posX;
                     gold.Yposition = posY;
                     break;

                     case 'm':
                     posY = theToken[1] - '0';
                     posX = theToken[3] - '0';

                     monster.Xposition = posX;
                     monster.Yposition = posY;
                     break;

                     case 'p':
                     posY = theToken[1] - '0';
                     posX = theToken[3] - '0';

                     potion.Xposition = posX;
                     potion.Yposition = posY;
                     break;

                     case 'h':
                     posY = theToken[1] - '0';
                     posX = theToken[3] - '0';

                     hero.Xposition = posX;
                     hero.Yposition = posY;                  
                     break;

                     case 's':
                     posY = theToken[1] - '0';
                     posX = theToken[3] - '0';

                     stairs.Xposition = posX;
                     stairs.Yposition = posY;   
                     break;
                 }
                 k++;
             }
        }
        else if(theToken == NULL)
        {
            printf("end of file");
        }
    }

    if(theToken == NULL)
    {
        printf("\n");
    }
    x++;
}
free(theString);
fclose(rooms);
}

我的结构是:

typedef struct 
{
int roomNumber;
int length;
int width;
int eastDoor;
int westDoor;
int southDoor;
int northDoor;
}room;

我想要做的是访问我的结构数组中的第一个结构,然后用我获得的信息做一些事情。每当我运行以下代码时,都不会打印任何内容,并且出现段错误

【问题讨论】:

  • 什么是STARTING_POINT
  • 你和this guy同班吗?
  • 与问题无关,但如果这是我认为的方向(您要将部分或全部案例 1 到 5 添加到 switch),您可能会有loop-switch antipattern 这里。
  • 起点已经更新,我很可能和那家伙在同一班
  • 你能显示你正在推入这个函数的room roomInfo[6] 数组吗?也许是你调用这个drawingRooms的函数

标签: c segmentation-fault ncurses


【解决方案1】:

您创建的变量在它之前的左大括号{ 的相应右大括号} 之前一直有效。

每对左大括号和右大括号以及{ ... } 中的内容被称为代码块,通过这个定义,我们可以说一个变量在它所在的代码块中仍然有效声明。

您在函数parser 中声明了一个roomsInfo[6] 数组,看起来您希望能够直接访问它而无需从另一个函数执行任何操作:drawingRooms

事情不会这样发展的。

另一件事,C 编译器不应该允许您调用一个要求参数的函数,而没有参数。所以你根本不能拨打drawingRooms( );,因为void drawingRooms( room roomInfo[6] ) { ... }是这样定义的。如果确实允许,那么它可能会将room roomInfo[6] 视为未初始化的变量,如下所示:

    void drawingRooms(  )
    {
        room roomInfo[6];
        ...
    }

无论如何,你应该做的是给drawingRooms 提供一个适当的参数,这将是地址,指向6 个room 结构数组的第一个元素的指针;如果你已经这样声明了它的功能。

要解决此特定问题,您有两种选择,我将从简单的一种开始:

1) 使roomInfo[6] 成为文件范围变量

通过将roomInfo[6] 设为全局(文件范围)变量,该变量将贯穿程序的整个生命周期,因此可以从代码中的任何位置访问。为此:

  • 删除room roomInfo[6];函数内的parser
  • 从函数drawingRooms 中删除参数room roomInfo[6]
  • 声明 room roomInfo[6]; 高于一切,高于 main 函数

像这样:

    #define STARTING_POINT 5

    //somewhere above the roomInfo declaration, somewhere here
    //there has to be the typedef for the room structure,
    //either through the inclusion of a header file
    //or the typedef struct {...} room; itself

    room roomInfo[6];

    int main( ... )
    {
        ...
    ...

2) 将指针推送到drawingRooms

为此,您必须先自己为room 结构数组分配内存,这样它就不会在parser 函数结束时被自动杀死;然后使用parser 函数返回指向第一个元素的指针,在调用drawingRooms 函数时使用返回的地址:

  • parser 函数中的room roomInfo[6]; 行替换为room * roomInfo;
  • 为您的房间分配 6 个 room 结构价值内存

像这样:

    roomInfo = calloc( 6, sizeof * roomInfo );
  • 确保您已将&lt;stdlib.h&gt;&lt;malloc.h&gt; 加入到calloc 调用中
  • parser函数末尾添加这一行:return roomInfo;
  • parser函数的返回值从void改为room *
  • 在调用drawingRooms 函数时在main 函数中使用此返回值

像这样:

    //either like this:
    ...
        input( argc, argv );
        drawingRooms( parser( argc, argv ) );
    ...

    //or like this (allows you to free it inside main):
    ...
        room * roomInfo;
        input( argc, argv );
        roomInfo = parser( argc, argv );
        drawingRooms( roomInfo );
    ...
  • 如果您的程序要进一步运行,请确保您free 分配的内存。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-26
    • 2021-06-12
    • 1970-01-01
    • 2011-08-24
    • 2020-02-17
    • 2014-01-18
    • 2023-04-04
    相关资源
    最近更新 更多