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

C/C++中字符数组大小是否为动态?两段代码引发的技术疑问

C/C++数组大小固定,但为何越界操作能"正常运行"?

问题描述

一直以为C和C++中的数组大小是固定的,但遇到两段代码似乎与此矛盾:

代码片段1

#include <iostream>
#include <string.h>

using namespace std;

int main()
{
    char str1[]="Good"; //size of str1 should be 5
    char str2[]="Afternoon";  //size of str2 should be 10
    
    cout<<"\nSize of str1 before the copy: "<<sizeof(str1);
    cout<<"\nstr1: "<<str1;
    
    strcpy(str1,str2);     //copying str1 into str2      
    
    cout<<"\nSize of str1 after the copy: "<<sizeof(str1);
    cout<<"\nstr1: "<<str1;

    return 0;
}

输出:

Size of str1 before the copy: 5
str1: Good
Size of str1 after the copy: 5
str1: Afternoon

用strcpy将长度更大的str2复制到大小为5的str1中,理论上因数组大小固定应报错,但代码正常执行,且str1的sizeof值仍为5却能存储更长字符串。

代码片段2

#include <iostream>
#include <cstring>

using namespace std;
int main()  
{  
    char first_string[10]; // declaration of char array variable  
    char second_string[20]; // declaration of char array variable  
    int i;  // integer variable declaration  
    
    cout<<"Enter the first string: ";  
    cin>>first_string;  
    cout<<"\nEnter the second string: ";  
    cin>>second_string;  
    
    for(i=0;first_string[i]!='\0';i++);   
      
    
    for(int j=0;second_string[j]!='\0';j++)  
    {  
        
        first_string[i]=second_string[j];  
        i++;  
    }  
    first_string[i]='\0';  
   cout<<"After concatenation, the string would look like: "<<first_string;  
return 0;  
}

输出:

Enter the first string: good
Enter the second string: afternoon
After concatenation, the string would look like: goodafternoon

将更长的字符串拼接到大小为10的first_string中,拼接后长度远超其大小,但仍能正常输出结果,这与认知不符。


解答

首先明确:C/C++中数组的大小确实是固定不变的,你看到的"正常运行"只是一种危险的假象,本质是缓冲区溢出引发的未定义行为。

核心原因:未定义行为与数组越界

C/C++标准不要求编译器对数组越界访问做运行时检查——这是为了极致的性能,但代价是程序员必须自己确保内存访问的合法性。当你越界写入数组时:

  • 你在覆盖数组后面的内存区域,这些区域可能属于其他变量、函数栈帧的返回地址,甚至是其他数据结构。
  • 程序的行为完全不可预测:可能看起来正常输出、可能崩溃、可能输出乱码、甚至可能被利用执行恶意代码。你这次运行没出问题,只是因为越界覆盖的内存暂时没有影响到程序的关键执行逻辑,属于"运气好"。

针对代码片段1的细节解释

  • char str1[]="Good"; 在编译阶段就确定了数组大小为5(4个字符+1个字符串结束符'\0'),sizeof(str1)是编译期常量,所以无论后续怎么操作,它的值始终是5,不会因为你写入了更多内容而改变。
  • strcpy(str1, str2) 会把str2的全部内容(包括'\0')拷贝到str1,但str1只有5字节的空间,剩下的5字节会直接覆盖str1之后的内存,这完全违反了内存安全规则。

针对代码片段2的细节解释

  • first_string[10]是固定大小为10的数组,拼接后的字符串长度远超10,循环写入时会直接越界覆盖数组后的内存。能正常输出只是因为越界区域暂时未被其他关键数据占用,一旦程序的内存布局变化(比如调整变量顺序、优化等级),立刻会出现崩溃或异常。

正确的处理方式

  • C语言:使用malloc/realloc动态分配内存,根据需要调整字符串的存储空间,使用strncpy/strncat等带长度限制的函数避免越界。
  • C++语言:直接使用std::string,它会自动管理内存,动态扩容,完全避免手动处理数组大小的麻烦。

额外提示

开启编译器的警告选项(比如GCC的-Wall -Wextra,MSVC的/W4),可以在编译阶段发现一些明显的数组越界隐患,提前规避问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 16:15:53