[英]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<<"\n\n\n\n\n\n\n";
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<<"\n\n\n\n\n\n\n";
return 0;
}
OUTPUT: 1. On giving input within defined range(i.e less than 10) Enter the string: 12345678 8 12345678 sizeof ch10 8 8 second last=8 last=0 2. On giving input beyond defined range Enter the string: 12345678901234 14 12345678901234 sizeof ch10 13 14 second last= last=0 Enter the string: 123456789012345678 18 123456789012345678 sizeof ch10 13 18 second last=8 last=0
我知道不应使用gets用法,但我仍然想了解内部发生了什么,为什么输出的最后三行给出13?
唯一真正的答案是不确定的行为。 一旦你访问内存超过数组的结尾,就gets
确实,如果输入过大,什么事情都可能发生。
如果我猜的话:最有可能的解释是,放置编译len
后ch
内存。 因此,分配给len
将会覆盖从数组末尾溢出的一些输入。 该值的某些字节将为零(因为它是一个小数字),因此,在找到这些字节之一时,对strlen
的下一次调用将停止,从而提供比以前小的值。
在分配给len
之前和之后,也许内存布局看起来像这样。 我假设使用ASCII编码,因此'0'
为48, '1'
为49,依此类推。我假设int
有四个字节,以“ little-endian”顺序排列,内存中的最低有效位在前,并且需要要在四字节边界上对齐,需要两个填充字节才能将其存储在数组之后。
| 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
可以完全避免这种惨败。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.