前言
先给大家看看一段测试:
char s[10];
cin>>s;
cout<<"strlen(s):"<<strlen(s)<<endl;
cout<<"sizeof(s):"<<sizeof(s)<<endl;
cout<<s[12]<<endl;
cout<<s;
输入:
012345678912345
输出:
下面带着疑问,我们来看看数组到底有几斤几两!
Ⅰ- 超出内容存入数组没有?
实际上并没有!!!
机智的你肯定又会问,那为什么打印字符数组的时候,溢出内容也能打印呢?
我们首先弄清楚 cin>>s 的工作原理。
- 我们在输入时,需要按下回车键,才能将数据送入缓冲区(输入队列),然后将缓冲区的前十个字符送到数组中。(若缓冲区不够10个,则数组中剩余用空字符补充)。但是此时,缓冲区还有过剩的内容,此时,我们称为:缓冲区溢出。
想了解更多的 cin输入流的知识,推荐大家看看这篇文章点这里…
再弄清楚 cout<<s 这句代码实际的工作原理。
- 数组名s 只告诉了 cout ,字符数组中第一个元素的地址,没有告诉数组的长度。cout会往下输出,直到遇到空字符停止。所以按数组名输出字符串就是遇到空字符— \0结束。(我们通过键盘输入时,会自动在末尾加上 \0)
正是这一原因,所以打印的时候,我们会误以为感觉数组被扩容了一样。从sizeof(s)=10也能看出,数组并未被改变。
char s2="123\096";
cout<<s2;
运行结果:
123
举一反三,为什们 strlen[s]=15呢?
我们同样要弄清楚 strlen[s] 的工作原理。
- 相信机智的你已经猜出来了,strlen和cout的工作原理极其相似。它是求字符串的长度,而不是数组的长度(不把空字符计算在内)。值得注意的是:它同样也是将空字符当作结束符。
char s2="123\096";
cout<<strlen(s2);
运行结果:
3
注:关于数组名的运用还不够了解的,可以参考参考这篇文章,点这里。。。。
Ⅱ- s[12] 错误还是正确
这一看就是数组越界了呀?这编译不报错吗?为啥打印结果好像还有点正确呢?
1.首先谈谈为啥编译不报错?
C++作为全世界运行效率最高的语言(rust?什们LJ玩意儿)。鲁迅曾说过,🐟和熊掌不可兼得。C++为了提高程序的运行效率,不会自动检查数组下标,只能由程序员自行检查。
s[12] 的工作原理:
- 数组名只告诉了数组的地址信息,并没有长度信息,另外又加上C++不自动检查数组下标,所以程序可以运行成功。
- 如我们所遇见的,下标越界了,它会自动接着那块内存往后写,读。
2.数组下标为负时
正是因为不检查数组下标,所以数组下标可为负。
char s3[7]="123456";
char *p=s3+1;
cout<<p[-1];
运行结果:
1
在这里,我只是为了它输出正确的值,大家只需要知道它的逻辑关系就行。
3.危险的越界
我们往往正是因为 缓冲区溢出而导致的数组越界。为什们时刻都在说数组不能越界呢?
因为对于数组后面的内存是未知的。如果该内存没有值还好,但是有值的话,我们对其进行修改,后果是不可预估的。
数组越界是一种难以捕捉的错误,因为越界语句本身并不一定导致程序立即出错,可能会在某些情况下才会出现错误,导致程序不按照应当的次序运行的怪现象。这也要看各个系统下各个编译器的实现,可能可以继续访问,也可能直接报段错误。