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

C语言指针异常:print语句前后指针输出值不同的原因与修复

问题原因与修复方案

问题原因

你在set函数里定义的char arr[25]是局部栈变量,它的内存分配在函数调用栈上。当set函数执行完毕返回main时,这块栈内存会被系统标记为可复用空间,但database[code].name还指向这个已经失效的内存地址——这就是所谓的野指针。

在display函数中,第一条printf执行时,这块失效的内存还没被新的操作覆盖,所以碰巧能打印正确字符;但执行打印表头的printf时,函数内部的栈操作会覆盖原arr的内存区域,此时野指针指向的内容已经变成随机垃圾数据,因此输出未知字符。

如果把set里的代码移到main函数中,arr就成为main的局部变量,main函数执行期间栈内存不会被回收,指针始终有效,自然不会出现问题。

修复方案

方案1:使用静态局部变量

将set函数里的arr改为静态变量,它的内存会分配在全局数据区,函数结束后不会被释放:

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

struct team {
    int code;
    char *name;
} database[32];

void set(int code){
    static char arr[25]; // 添加static关键字

    printf("Enter Team Name: ");
    fgets(arr, sizeof(arr), stdin); // 替换不安全的gets,避免缓冲区溢出
    arr[strcspn(arr, "\n")] = '\0'; // 去除fgets读取的换行符

    database[code].name = arr;
}

// display和main函数不变

注意:静态变量是全局共享的,后续调用set会覆盖之前存储的队名,仅适用于单一条目存储的场景。

方案2:动态分配堆内存

使用malloc在堆上分配内存,堆内存不会随函数结束自动释放,可存储多个独立的队名,但需要手动释放避免内存泄漏:

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

struct team {
    int code;
    char *name;
} database[32];

void set(int code){
    char arr[25];

    printf("Enter Team Name: ");
    fgets(arr, sizeof(arr), stdin);
    arr[strcspn(arr, "\n")] = '\0';

    // 分配足够存储字符串的堆内存,+1用于存放终止符'\0'
    database[code].name = malloc(strlen(arr) + 1);
    if (database[code].name != NULL) { // 检查内存分配是否成功
        strcpy(database[code].name, arr);
    }
}

void display(int first, int last)
{
    printf("Name Before line: %c\n", *database[1].name);
    printf("Team Code\tTeam Name\t\tGroup Seeding\tPrimary Kit Colour\n");
    printf("Name After line %c", *database[1].name);
}

int main() {
    for (int i = 0; i < 32; i++) {
        database[i].code = 1;
        database[i].name = NULL; // 初始化改为NULL,便于后续判断是否需要释放
    }

    set(1);
    display(0, 32);

    // 程序结束前释放堆内存
    for (int i = 0; i < 32; i++) {
        if (database[i].name != NULL) {
            free(database[i].name);
        }
    }
    return 0;
}

这个方案更灵活,支持存储多个不同的队名,但必须记得在不需要使用内存时调用free释放,否则会造成内存泄漏。

另外,原代码中的gets函数存在严重的缓冲区溢出风险,已被C标准废弃,因此替换为更安全的fgets函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 11:50:46