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

C语言中使用scanf的%ms读取的字符串无法用于strcpy怎么办

问题原因排查

你遇到的错误主要来自以下几个问题:

  1. 格式符使用错误:scanf(" %m[^\n]s", &note);中的扫描集%[^\n]不需要额外加后缀s,多余的s会要求scanf额外匹配输入流中的s字符,可能导致输入读取异常。
  2. strcpy参数类型完全错误:strcpy要求两个入参都是char*类型,分别指向目标缓冲区、源字符串的首地址。你写的strcpy(contact.note, *note)中,*note是取指针note指向的第一个字符,属于char类型,把单字符作为地址传入会直接触发内存访问错误。
  3. 结构体指针未初始化:你定义的struct contact中的note是未初始化的野指针,没有指向合法的可写内存空间,直接作为strcpy的目标参数写入内容也会触发崩溃。
  4. 格式化输出风险:直接写printf(note)存在格式化字符串漏洞,如果用户输入包含%s/%d等格式占位符会导致程序异常,建议改为printf("%s", note)。
修复方案

方案1:直接转移堆内存所有权(推荐)

%m修饰符会自动调用malloc为匹配到的字符串分配内存,你不需要额外拷贝,直接把分配好的地址赋值给结构体的note指针即可,后续释放结构体时记得同时free(contact.note)避免内存泄漏。
修正后的核心代码如下:

char *note = NULL;
// 去掉多余的s后缀
scanf(" %m[^\n]", &note);

// 安全打印
printf("%s", note);

struct contact contact;
// 假设name、num已经合法初始化,注意长度不要超出数组上限
strncpy(contact.name, name, sizeof(contact.name)-1);
contact.name[sizeof(contact.name)-1] = '\0';
strncpy(contact.number, num, sizeof(contact.number)-1);
contact.number[sizeof(contact.number)-1] = '\0';
// 直接转移内存所有权
contact.note = note;

// 后续使用完contact后执行释放
// free(contact.note);

方案2:手动拷贝字符串

如果你需要单独保留原来的note指针另作他用,可以先给结构体的note分配足够的内存再拷贝:

// 前面读取note的逻辑不变
if (note != NULL) {
    // 分配空间:字符串长度 + 末尾结束符的1字节
    contact.note = malloc(strlen(note) + 1);
    if (contact.note != NULL) {
        strcpy(contact.note, note);
    }
}
// 这种情况下原来的note使用完后需要自己单独free
// free(note);
注意事项
  • %m是POSIX扩展的scanf格式修饰符,不属于标准C的内容,跨平台编译时需要确认编译环境支持该特性。
  • 拷贝固定长度的字符数组时建议使用strncpy限制拷贝长度,避免缓冲区溢出。
  • 所有malloc分配的内存使用完毕后都要手动free,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 12:24:04