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

为何非空格非*字符未全复制?strcpy为何修改源字符串?

分析C语言字符串处理代码的异常问题

先来看你提供的原代码:

#include <stdio.h>
#include <string.h>
int main(void){
    char q[100*1000+2];
    fgets(q,100*1000+2,stdin);//enter string
    int len=strlen(q)-1;
    char s[len];
    int i,j;
    for(i=j=0;q[i]!='\0';i++)
        if(q[i]!=' '&&q[i]!='\n'&&q[i]!='*')
        {s[j]=q[i];j++;}//remove all spaces, \n's and *
    len=j;//new length is length of s
    s[j]='\0';
    char copy[len];//copy s
    printf("s=%s\n",s);
    strcpy(copy,s);
    printf("s=%s\n",s);
    return 0;
}

测试用例异常情况

下面是你提到的三个测试用例的表现:

  • 测试用例0:输入x^125-228-7x^27

    实际输出:
    s=x125-228-7x27
    s=x125-228-7x27
    符合预期,无异常。

  • 测试用例1:输入+x^125-228-7x^274

    实际输出:
    s=+x125-228-7x27
    s=+x125-228-7x27
    预期输出:
    s=+x125-228-7x274
    s=+x125-228-7x274
    出现字符串截断异常。

  • 测试用例2:输入+x^125-228-7x^27

    实际输出:
    s=+x125-228-7x27
    s=
    预期输出:
    s=+x125-228-7x27
    s=+x125-228-7x27
    执行strcpy后原字符串s被清空。

异常原因分析

1. 测试用例1的截断问题

原代码中,char s[len];的len是处理前的字符串长度(strlen(q)-1,即去掉换行符后的原字符串长度)。当输入的字符串没有需要过滤的字符(空格、*、换行)时,处理后的j会等于这个初始len,此时执行s[j]='\0';就会越界写入——因为变长数组s的大小是len,下标范围是0~len-1,j=len已经超出了数组的有效范围。这种越界会触发未定义行为,导致字符串被意外截断。

2. 测试用例2的s被清空问题

定义char copy[len];时,len是处理后的s的长度(不包含终止符'\0')。而strcpy会复制从s开始直到'\0'的所有字符,包括'\0'本身。这意味着copy的大小至少需要len+1才能容纳所有内容,否则strcpy会越界写入,破坏栈上的其他变量(比如s的内存区域),最终导致s的内容被清空。

当你换成memcpy(copy,s,len)时,只复制了len个字节(没有包含'\0'),虽然避免了越界破坏s,但copy本身会缺少终止符,依然是隐患,而且测试用例1的越界问题没解决,所以截断还是存在。

修复方案

针对这两个问题,我们可以调整代码的数组定义和终止符处理逻辑:

#include <stdio.h>
#include <string.h>
int main(void){
    char q[100*1000+2];
    fgets(q,100*1000+2,stdin);//enter string
    
    // 先过滤字符,得到处理后的长度j
    int i,j;
    char s[100*1000+2]; // 直接用足够大的数组,避免变长数组的越界问题
    for(i=j=0;q[i]!='\0';i++)
        if(q[i]!=' '&&q[i]!='\n'&&q[i]!='*')
        {s[j]=q[i];j++;}//remove all spaces, \n's and *
    
    s[j]='\0'; // 此时j是处理后的有效字符数,s的大小足够,不会越界
    int len = j;
    
    char copy[len+1]; // 分配足够容纳终止符的空间
    printf("s=%s\n",s);
    strcpy(copy,s);
    printf("s=%s\n",s);
    printf("copy=%s\n",copy); // 可以验证copy的内容
    return 0;
}

修复要点:

  • 直接使用和q同大小的s数组,避免变长数组的长度预判错误,确保s[j]='\0'不会越界。
  • copy数组的大小设为len+1,保证能容纳s的所有字符(包括终止符'\0'),避免strcpy的越界写入。
  • 调整逻辑顺序:先完成过滤得到j,再设置终止符,最后处理复制操作。

这样修改后,两个测试用例的异常都会被修复,所有输入的处理结果都能符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 21:02:58