You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用C结构体构建地图位置图时遇只读变量赋值错误求助

问题分析与解决方案

咱们先拆解你遇到的两个核心问题:编译器报错的直接原因,还有隐藏的致命内存风险,然后一步步给出修复方案。

1. 编译器错误:assignment to read only variable

你写的current_location = current_location.portals[0];其实犯了两个小错误:

  • 类型不匹配:portals[0]是location*指针类型,而current_location是location结构体变量,直接把指针赋值给结构体变量完全不对,正确的写法应该是解引用指针拿到结构体内容:current_location = *current_location.portals[0];
  • const成员的赋值限制:你的location结构体里有多个const修饰的成员(比如const point portal_in、const byte width),这些成员一旦初始化就不允许被修改。而结构体赋值本质是逐个成员复制,尝试把另一个结构体的const成员复制过来时,编译器会判定这是修改只读变量,直接报错。

2. 隐藏的致命问题:悬空指针

你的build_locations函数里,loc是局部变量,函数执行完毕后,这个变量占用的内存会被系统回收。但你把&loc赋值给了village.portals[0],这就导致返回的village里的portals[0]指向了一块已经无效的内存——后续访问这个指针会触发未定义行为(比如程序崩溃、出现奇怪的地图数据)。


修复方案

针对这两个问题,最合理的调整是用指针管理所有位置实例,避免结构体复制和局部变量指针失效的问题:

方案A:全局静态变量(适合小型设备,无需内存分配)

因为小型游戏设备通常内存有限,用全局静态变量可以避免动态内存管理的麻烦,同时保证位置实例的内存一直有效:

typedef unsigned char byte;

static const byte VILLAGE[] = { /* 你的地图数据 */ };
static const byte HOUSE[] = { /* 你的地图数据 */ };

typedef struct point { int x; int y; } point;

typedef struct location {
    const point portal_in;
    const point portal_out;
    const byte *map;
    const byte width;
    const byte height;
    struct location *portals[8];
    point player;
    struct location *return_to;
} location;

// 定义全局静态的位置实例,内存会在程序运行期间一直存在
static location village = {
    .portal_in={15, 14},
    .portal_out={0, 0},
    .map=&VILLAGE[0],
    .width=32,
    .height=16,
    .player={15, 14},
    .return_to=NULL
};

static location house = {
    .portal_in={8, 7},
    .portal_out={11, 10},
    .map=&HOUSE[0],
    .width=8,
    .height=8,
    .player={0, 0},
    .return_to=&village
};

// 初始化位置间的链接
void init_locations() {
    village.portals[0] = &house;
}

int main(void) {
    init_locations();
    // 用指针跟踪当前位置,避免结构体复制
    location *current_location = &village;

    if (current_location->player.x == 5 && current_location->player.y == 4) {
        // 直接切换指针,完全避开const成员的赋值问题
        current_location = current_location->portals[0];
    }

    // 后续访问位置成员用 -> 操作符,比如 current_location->player.x
    return 0;
}

方案B:动态内存分配(适合灵活扩展的场景)

如果你的设备支持malloc,可以用动态分配来创建位置实例,适合需要动态生成地图的场景:

// ... 结构体定义和地图数据与之前一致 ...

location* build_village() {
    location *village = malloc(sizeof(location));
    if (!village) return NULL; // 处理内存分配失败的情况
    *village = (location){
        .portal_in={15, 14},
        .portal_out={0, 0},
        .map=&VILLAGE[0],
        .width=32,
        .height=16,
        .player={15, 14},
        .return_to=NULL
    };
    return village;
}

location* build_house(location *return_loc) {
    location *house = malloc(sizeof(location));
    if (!house) return NULL;
    *house = (location){
        .portal_in={8, 7},
        .portal_out={11, 10},
        .map=&HOUSE[0],
        .width=8,
        .height=8,
        .player={0, 0},
        .return_to=return_loc
    };
    return house;
}

int main(void) {
    location *village = build_village();
    location *house = build_house(village);
    village->portals[0] = house;

    location *current_location = village;

    if (current_location->player.x == 5 && current_location->player.y == 4) {
        current_location = current_location->portals[0];
    }

    // 程序结束前记得释放内存
    free(house);
    free(village);
    return 0;
}

修复逻辑说明

  • 用指针管理位置:直接切换指针不需要复制整个结构体,完美避开了const成员无法被赋值的问题,同时也更高效(节省结构体复制的内存和时间)。
  • 解决悬空指针:全局静态变量的内存会一直存在,动态分配的内存直到你调用free才会被回收,不会出现局部变量销毁后指针失效的问题。

如果坚持要保留结构体赋值的方式,只能去掉location结构体里所有成员的const修饰,但这样会失去const带来的安全性(比如防止意外修改地图尺寸、传送门坐标),所以更推荐用指针的方案。

内容的提问来源于stack exchange,提问作者MalphasWats

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:06:20