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

C程序参数解析中变量莫名被修改的问题排查求助

变量莫名被修改的C程序问题排查与解决

问题现象:传入参数对应的变量在未被代码显式修改时发生了变更。

初始执行命令:

anonymous DELAI_ANONYME=O sanspm=O

主函数代码:

int main(int argc, char *argv[])
{  
  EXEC SQL BEGIN DECLARE SECTION;
    SQL100 qstrRefIndiv = {0};
    int qiCheckIndiv = 0;
    SQL20 qstrTrigStatus = {0};
  EXEC SQL END DECLARE SECTION;

  char strLogName[100] = {0};
  char strRef[100] = {0};
  int iNoCommit = 0;
  int i = 0;
  int iDelCase=0;
  char strDelai[1];
  char strSanspm[1];
  strcpy(strDelai, "N");  
  strcpy(strSanspm, "N");  
  char selectcof[1000]= {0};
  initscr();
  bkg_init();

  for(i=1; i<argc; i++)
  {
    refresh();
    db_log_message (LL_INFO, "Iter Nbr= [%d]\n", i);

    if(strcmp(argv[i],"NOCOMMIT")==0)
    {
      iNoCommit = 1;
    }
    if(strncmp(argv[i], "ref=", 4)==0)
    {
       strcpy(strRef,&argv[i][4]);
       strcpy (qstrRefIndiv, strRef);
       db_log_message (LL_INFO, "ref param= [%s]\n", qstrRefIndiv);
    }
    if(strncmp(argv[i], "DELAI_ANONYME=", 14)==0)
    {
       strcpy(strDelai,&argv[i][14]); 
       db_log_message (LL_INFO, "ref Delai= [%s]\n", strDelai);
    } 
    if(strncmp(argv[i], "delcase=", 8)==0)
    {
       iDelCase=atoi(&argv[i][8]);
       db_log_message (LL_INFO, "ref iDelCase= [%s]\n", iDelCase);
    }
    if(strncmp(argv[i], "sanspm=", 7)==0)
    {
       db_log_message (LL_INFO, "[sanspm] before ref Delai= [%s]\n", strDelai);
       strcpy(strSanspm,&argv[i][7]);
       db_log_message (LL_INFO, "ref strSanspm= [%s]\n", strSanspm);
       db_log_message (LL_INFO, "[sanspm] after ref Delai= [%s]\n", strDelai);
    }
  }

  db_log_message (LL_INFO, "ref Delai 1= [%s]\n", strDelai);
  db_log_message (LL_INFO, "ref strSanspm 1= [%s]\n", strSanspm);
  ...
  endwin();
  return(0);
}

第一次执行日志:

[INFO ] [    0.017] Iter Nbr= [1]
[INFO ] [    0.000] ref Delai= [O]
[INFO ] [    0.000] Iter Nbr= [2]
[INFO ] [    0.000] [sanspm] before ref Delai= [O]
[INFO ] [    0.000] ref strSanspm= [O]
[INFO ] [    0.000] [sanspm] after ref Delai= []
[INFO ] [    0.000] ref Delai 1= []
[INFO ] [    0.000] ref strSanspm 1= [O]

调整参数顺序后的执行命令:

anonymous sanspm=O DELAI_ANONYME=O

调整参数后的执行日志:

[INFO ] [    0.001] Iter Nbr= [1]
[INFO ] [    0.000] [sanspm] before ref Delai= []
[INFO ] [    0.000] ref strSanspm= [O]
[INFO ] [    0.000] [sanspm] after ref Delai= []
[INFO ] [    0.000] Iter Nbr= [2]
[INFO ] [    0.000] ref Delai= [O]
[INFO ] [    0.000] ref Delai 1= [O]
[INFO ] [    0.000] ref strSanspm 1= [OO]

原因分析

  • 数组越界与字符串结束符问题:C语言中strcpy会自动复制字符串的结束符'\0',而代码中strDelai和strSanspm仅被定义为char [1],只能容纳1个字符。执行strcpy(strDelai, "N");时,"N"实际是包含'\0'的两个字符,strcpy会把这两个字符都写入,直接导致内存越界;复制"O"时同理。
  • 栈内存覆盖:这两个变量在栈上连续存储,越界写入的内容会直接覆盖相邻变量的内存区域。第一次执行时,strSanspm的越界写入覆盖了strDelai的内存;调整参数顺序后,strDelai的越界写入又覆盖了strSanspm的内存,从而出现变量值异常变更的现象。

解决方案

方案1:调整数组大小

将strDelai和strSanspm的数组大小改为至少2,以容纳单个字符加上字符串结束符:

char strDelai[2] = {0};
char strSanspm[2] = {0};

方案2:使用安全的字符串复制函数

用strncpy代替strcpy,明确指定复制长度,并手动添加结束符,彻底避免越界:

// 初始化时
strncpy(strDelai, "N", sizeof(strDelai)-1);
strDelai[sizeof(strDelai)-1] = '\0';
strncpy(strSanspm, "N", sizeof(strSanspm)-1);
strSanspm[sizeof(strSanspm)-1] = '\0';

// 处理参数时
strncpy(strDelai, &argv[i][14], sizeof(strDelai)-1);
strDelai[sizeof(strDelai)-1] = '\0';
strncpy(strSanspm, &argv[i][7], sizeof(strSanspm)-1);
strSanspm[sizeof(strSanspm)-1] = '\0';

方案3:直接使用字符变量

如果仅需要存储单个字符,无需用字符串数组,直接定义为char类型:

char strDelai = 'N';
char strSanspm = 'N';

// 处理参数时直接赋值
strDelai = argv[i][14];
strSanspm = argv[i][7];

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 05:41:19