strlen()的奇怪行为,当在代码中的不同位置使用时,会给出不同的输出
Strange behavior of strlen(), giving different output when used at different place in code
代码:
#include<iostream>
#include<stdio.h>
int main()
{
char ch[10];
std::cout<<"nnnnnnn";
std::cout<<"Enter the string: ";
gets(ch);
std::cout<<strlen(ch)<<"n";
std::cout<<ch<<"n";
std::cout<<"sizeof ch"<<sizeof(ch)<<"n";
int len=strlen(ch);
std::cout<<strlen(ch)<<"n";
std::cout<<len<<"n";
std::cout<<"second last="<<ch[len-1]<<" last="<<(int)ch[len]<<"n";
std::cout<<"nnnnnnn";
return 0;
}
输出:1.在规定范围内输入(即小于10)输入字符串:123456788.12345678ch10的尺寸8.8.倒数第二=倒数第8=倒数第02.在给出超出定义范围的输入时输入字符串:123456789012341412345678901234ch10的尺寸1314倒数第二=倒数第0输入字符串:12345678901234567818123456789012345678ch10的尺寸1318倒数第二=倒数第8=倒数第0
我知道不应该使用gets,但我仍然想知道里面发生了什么,为什么最后一行输出是13??
唯一真正的答案是未定义的行为。一旦访问数组末尾以外的内存,就像gets
在输入过大时所做的那样,任何事情都可能发生。
如果非要我猜测的话:最可能的解释是编译器将len
放在内存中的ch
之后。因此,分配给len
将覆盖从数组末尾溢出的一些输入。该值的一些字节将为零(因为它是一个小数字),因此当它找到其中一个字节时,对strlen
的下一次调用将停止,从而给出比以前更小的值。
在分配给len
之前和之后,内存布局可能是这样的。我假设ASCII编码,所以'0'
是48,'1'
是49,等等。我假设int
有四个字节,以"小端序"顺序排列,内存中的最低有效位在第一位,并且需要在四个字节的边界上对齐,需要两个填充字节将其存储在数组之后。
| ch, 10 bytes | pad | len, 4 bytes| other |
| 49 50 51 52 53 54 55 56 57 48 | 49 50 | 51 52 53 54 | 55 56 00 | before
| 49 50 51 52 53 54 55 56 57 48 | 49 50 | 18 00 00 00 | 55 56 00 | after
您可以看到,在这种情况下第二次调用strlen
将在零值字节被解释为字符串末尾之前找到13个字符。这符合你的观察结果。
正如您所说,永远不要使用gets
,因为没有办法避免甚至可靠地检测缓冲区溢出。对于固定大小的数组要非常小心,并且更喜欢更友好的C++习惯用法,而不是C风格的内存杂耍。使用std::string
可以完全避免这种惨败。
相关文章:
- 更改.cpp程序的输入文件中数据的位置会意外更改输出
- 如何选择在 csv 文件中输出的位置
- 流中的输入位置和输出位置有什么区别?
- 如何更改输出的位置或光标在输出处,以便在"Code Blocks"中C++
- 来自不同位置的数组输出的执行时间
- 填写C 程序中缺少的位置以获取所需的输出
- 更新:正在输出内存位置,而不是所需的字符串
- 指针在字符串C 中的输出位置
- 排序为最后一个位置的元素提供错误的输出
- 输出文本文件的位置
- 二进制输出到C++中随机位置的文件
- 读取并输出二进制文件(C++)中位置的字节
- strlen()的奇怪行为,当在代码中的不同位置使用时,会给出不同的输出
- 使用 .tellg() 的输出来了解文件中的位置
- 面向对象C++帮助?出于某种原因,对象变量的输出返回数值数组位置而不是实际值
- 集成瓦尔格林德输出以找出数据竞赛的位置
- 构建一个程序,将 10 个整数放入数组中并识别重复的数字并输出它们及其位置编号的位置
- Xcode 4输出文件并从奇怪的位置读取
- 提升:精神:因果报应:如何获得输出的当前位置
- 打印以在c++中的行上的特定位置输出