C语言中使用scanf的%ms读取的字符串无法用于strcpy怎么办
问题原因排查
你遇到的错误主要来自以下几个问题:
- 格式符使用错误:
scanf(" %m[^\n]s", ¬e);中的扫描集%[^\n]不需要额外加后缀s,多余的s会要求scanf额外匹配输入流中的s字符,可能导致输入读取异常。 strcpy参数类型完全错误:strcpy要求两个入参都是char*类型,分别指向目标缓冲区、源字符串的首地址。你写的strcpy(contact.note, *note)中,*note是取指针note指向的第一个字符,属于char类型,把单字符作为地址传入会直接触发内存访问错误。- 结构体指针未初始化:你定义的
struct contact中的note是未初始化的野指针,没有指向合法的可写内存空间,直接作为strcpy的目标参数写入内容也会触发崩溃。 - 格式化输出风险:直接写
printf(note)存在格式化字符串漏洞,如果用户输入包含%s/%d等格式占位符会导致程序异常,建议改为printf("%s", note)。
修复方案
方案1:直接转移堆内存所有权(推荐)
%m修饰符会自动调用malloc为匹配到的字符串分配内存,你不需要额外拷贝,直接把分配好的地址赋值给结构体的note指针即可,后续释放结构体时记得同时free(contact.note)避免内存泄漏。
修正后的核心代码如下:
char *note = NULL; // 去掉多余的s后缀 scanf(" %m[^\n]", ¬e); // 安全打印 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
相关产品推荐
相关产品推荐

