strlen()的奇怪行为,在代码中的不同位置使用时给出不同的输出

时间:2015-03-18 11:10:58

标签: c++

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

我知道不应该使用获取但仍然想知道里面发生了什么,为什么第三行的输出会给出13?

1 个答案:

答案 0 :(得分:5)

唯一真正的答案是未定义的行为。一旦你访问超出数组末尾的内存,如果输入太大就会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可以完全避免这种惨败。