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

为何sscanf会修改非目标数据?C语言技术问题求助

问题原因分析

其实这个问题的核心是指针指向了栈上的局部变量,导致后续操作覆盖了之前的内容,具体来说:

  1. 你的addent函数只是把传入的id_ent指针直接赋值给nodo_id的ident成员,而id_ent是main函数里的temp2——这是一个在栈上分配的局部数组,它的内存地址是固定不变的(只要main函数在运行)。
  2. 第一次调用addent(temp2)后,testa_e->ident指向的是temp2的内存地址;第二次循环时,sscanf把新的字符串secondword写入temp2,这就直接覆盖了temp2里原来的firstword。因为第一个节点的ident还是指向temp2的地址,所以打印出来的内容自然就变了。
  3. 另外你的代码还有一个隐藏bug:addent的else分支里,循环条件是while (curs != NULL),这会让curs最终变成NULL,之后malloc的新节点根本没有被链接到链表上——也就是说你输入第二次addent时,新节点其实没被加到链表中,只是覆盖了temp2的内容而已。
修复方法及代码示例

要解决这个问题,关键是让每个链表节点拥有独立的字符串内存,而不是共享外部的局部变量内存,同时还要修复链表添加的逻辑错误。

方法1:使用strdup复制字符串(最简单)

strdup会自动为字符串分配内存并复制内容,注意它是POSIX标准函数,如果你的环境不支持,可以用malloc+strcpy替代。修改后的addent函数如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define string 30
#define line 100
typedef const char *identifier;
struct nodo_id {
    identifier ident;
    struct nodo_id *next;
};
typedef struct nodo_id nodo_id;
nodo_id *testa_e = NULL;

void addent(const char *id_ent) {
    if (testa_e == NULL) {
        testa_e = malloc(sizeof(nodo_id));
        // 复制字符串到新分配的内存
        testa_e->ident = strdup(id_ent);
        if (testa_e->ident == NULL) {
            perror("strdup failed");
            free(testa_e);
            exit(EXIT_FAILURE);
        }
        testa_e->next = NULL;
    } else {
        nodo_id *curs = testa_e;
        // 修复循环条件:找到最后一个节点(而不是走到NULL)
        while (curs->next != NULL) {
            curs = curs->next;
        }
        curs->next = malloc(sizeof(nodo_id));
        curs->next->ident = strdup(id_ent);
        if (curs->next->ident == NULL) {
            perror("strdup failed");
            free(curs->next);
            exit(EXIT_FAILURE);
        }
        curs->next->next = NULL;
    }
}

int main() {
    char temp[line];
    char temp2[string];
    char temp5[string];
    fgets(temp, line, stdin);
    while (strncmp(temp, "end", 3) != 0) {
        if (strncmp(temp, "addent", 6) == 0) {
            if (testa_e != NULL) printf("\nbefore sscanf: %s\n", testa_e->ident);
            sscanf(temp, "%s %s", temp5, temp2);
            if (testa_e != NULL) printf("\nafter sscanf: %s\n", testa_e->ident);
            addent(temp2);
        }
        fgets(temp, line, stdin);
    }
}

方法2:手动用malloc+strcpy复制字符串

如果你的环境不支持strdup,可以手动分配内存并复制:

把strdup(id_ent)替换成:

// 分配足够的内存(字符串长度+1,用来存结束符'\0')
testa_e->ident = malloc(strlen(id_ent) + 1);
if (testa_e->ident == NULL) {
    perror("malloc failed");
    free(testa_e);
    exit(EXIT_FAILURE);
}
strcpy(testa_e->ident, id_ent);

额外说明

修复后,每个节点的ident都会指向一块独立的堆内存,后续修改temp2不会影响之前节点的内容,同时链表的添加逻辑也正确了——第二次输入的secondword会被正确添加为第二个节点。

最后别忘了,程序结束时要遍历链表,释放每个节点的ident和节点本身的内存,避免内存泄漏哦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:48:09