每当我尝试打印字符串时,我的代码都会出现段错误

My code keeps segfaulting whenever I try to print strings

提问人:Hogan 提问时间:11/15/2023 最后编辑:Hogan 更新时间:11/15/2023 访问量:88

问:

我正在开发一款在 Linux 终端中运行的游戏。我一直在研究一个系统,以加载地图文件,将其转换为自定义结构的字符串,然后打印结构所包含的字母和颜色。问题是每当我使用 .问题代码如下:printf("%s", myString);

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define BUFFLEN 3
#define DICLEN 3


/*a structure that holds basic tile info*/
typedef struct{
    char letter;
    char *color;
    char *name;
} tile;

/*a struture that holds general map info*/
typedef struct{
    const int mapHight;
    const int mapWidth;
    const int mapSize;
    const char *mapname;
} mapinfo;

/*dictionary that holds tiles*/
tile dic[DICLEN] = {
        {'T', "\033[38;5;2m", "Tree"},
        {' ', "\033[0m", "Path1"},
        {'\n', "\033[0m", "newLine"}
};

/*return a tile when given a name*/
tile dictionary(char *tileName){
    int i = 0;
    for (; i<DICLEN; i++){
        if ( (strcmp(tileName, dic[i].name) ) == 0){
                        goto END;
                }
    }
    goto ERROR;
    
    END:
    return dic[i];

    ERROR:
    fprintf(stderr, "that string is unreconnized");
    exit(-1);
}

/*gets map size to make into an array*/
mapinfo getMapSize(char *mapName){
    char mapFilePath[24] = "maps/";

    strcat(mapFilePath, mapName);
    char buffer[BUFFLEN];

    FILE *mapfile = fopen(mapFilePath, "r");
    
    for(int i; i < BUFFLEN; i++){
        buffer[i] = getc(mapfile); 
    }
    int mapWidth = atoi(buffer)+1;
    getc(mapfile);

    for(int i = 0; i < BUFFLEN; i++){
        buffer[i] = getc(mapfile);
    }
    int mapHight = atoi(buffer);

    int mapSize = mapHight * mapWidth;
    fclose(mapfile);
    
    mapinfo finalMap = {mapHight, mapWidth, mapSize, mapFilePath};
    return finalMap;
}

/*initalize map; put tiles into the map array*/
void mapInit(tile *mapArray, char *mapName){
    FILE *mapFile = fopen(mapName, "r");
    int i = 1, o = 0;
    char c;

    //this is to skip over the map size information
    for(;(c = getc(mapFile))!= '\n';){}

    for(;(c = getc(mapFile)) != EOF; i++){
        for(o = 0; o < DICLEN; o++){
            if(c == dic[o].letter){
                mapArray[i] = dictionary(dic[o].name);
            }
        }
        // un-comment this line for debug if needed
        //printf("%d\t%c%c\n",i, c, mapArray[i].letter);
    }

    fclose(mapFile);
}

int main(){
    mapinfo map1Info = getMapSize("map1.map");
    tile map1[map1Info.mapSize];
    mapInit(map1, map1Info.mapname);
    
    printf("%s%c\n", map1[0].color, map1[0].letter);

    return 0;
}

我试图阅读的信息()是这样的:maps/map1.map

011 010
TT TT T TTT
T T TTT TTT
T TT TTT TT
TTT TTTT TT
T T TTT  TT
TT TT TT TT
TT TT TTT T
T TTT TT TT
T TT T T  T
TTT TT    T

它应该打印一个绿色的 T

每当我更改为代码打印时,但显然,不再有颜色,我宁愿有颜色。 我试图将瓦片结构中的指针转换为数组,但编译器还是给了我警告和段错误。printf("%s%c\n", map1[0].color, map1[0].letter);printf("%c\n", map1[0].letter);

附加说明:是的,我知道 in 应该是一个 int,以及我有需要解决的嵌套 for 循环。对于大多数代码,只放入其中足以使其工作,但不能很好地工作(尽管提示会很好,因为我仍然不知道如何解决其中一些问题)。char cmapInit

编辑:通过调试器(GDB)运行我的代码后,这是我可以找到的:

(gdb) run
Starting program: /home/iggoth/Desktop/Programs/AKnightsTale/Game 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2 () at ../sysdeps/x86_64/multiarch/strlen-vec.S:126
126 ../sysdeps/x86_64/multiarch/strlen-vec.S: No such file or directory.
(gdb) list
121 in ../sysdeps/x86_64/multiarch/strlen-vec.S
(gdb) 

我没有找到任何其他信息

编辑2:运行Backtrace命令后:

(gdb) run
Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2 () at ../sysdeps/x86_64/multiarch/strlen-vec.S:126
126 ../sysdeps/x86_64/multiarch/strlen-vec.S: No such file or directory.
(gdb) backtrace
#0  __strlen_sse2 () at ../sysdeps/x86_64/multiarch/strlen-vec.S:126
#1  0x00007ffff7df1d31 in __vfprintf_internal (s=0x7ffff7f95780 <_IO_2_1_stdout_>, format=0x555555556129 "%s%c\n", ap=ap@entry=0x7fffffffce70, 
    mode_flags=mode_flags@entry=0) at ./stdio-common/vfprintf-internal.c:1517
#2  0x00007ffff7ddb79f in __printf (format=<optimized out>) at ./stdio-common/printf.c:33
#3  0x0000555555555906 in main () at Main.c:12
(gdb) 
c 指针 struct segmentation-fault printf

评论

1赞 Ken White 11/15/2023
您是否尝试在调试器中单步执行代码以查看发生了什么?这是跟踪逻辑错误和程序流的最佳方式。如果您不知道如何使用调试器,那么现在是开始学习的最佳时机。调试器是编码人员可用的最佳工具。
2赞 tadman 11/15/2023
PSA:检查通常失败的操作的结果,例如 .不要以为一切都很好。fopen
1赞 tadman 11/15/2023
也是一个非常小的缓冲区。为什么不或更慷慨的东西呢?char mapFilePath[24]PATH_MAX
0赞 Hogan 11/15/2023
@KenWhite不,我没有,我的大部分工作都是在终端中完成的,并没有深入研究基于终端的调试器。如果您推荐一个,我会更新结果。
0赞 Ken White 11/15/2023
这取决于你使用的编译器/工具链,以及你使用的操作系统。GDB 似乎很普遍。

答:

2赞 Chris Dodd 11/15/2023 #1

我发现了一个明显的问题。

在代码中:

mapinfo getMapSize(char *mapName){
    char mapFilePath[24] = "maps/";
    :
    mapinfo finalMap = {mapHight, mapWidth, mapSize, mapFilePath};
    return finalMap;
}

mapFilePath是一个局部变量,并且您将指向它的指针放入要返回的对象中,因此它将悬空(当您返回时,局部 var 消失,使指针无效)。finalMap

并不是说没有其他问题 - 代码看起来像是悬空指针问题的秘诀。

0赞 SmellyCat 11/15/2023 #2

分段错误的原因可能是指针从未初始化过。或者,它可能指向已解除分配的对象。就像克里斯写的,有很多潜在的悬而未决的指针。color

最好将结构定义为具有自己的数组缓冲区。

static const int TILE_NAME_LENGTH = 16;

struct{
    char letter;
    char color[TILE_NAME_LENGTH];
    char name[TILE_NAME_LENGTH];
} tile;

当实例化 时,您将调用将所有值设置为零(例如 ),除非您有像数组中那样的初始值。这样,没有初始值的 char 数组就是空字符串。tilememsetmemset(pTile, 0, sizeof(tile))dic

复制项目时,您需要一个用于从源复制到目标的函数。如果成员是数组,则不允许进行简单赋值。const tile *tile *=