在C ++中访问数组负索引处的内存不会返回垃圾

时间:2018-10-24 12:29:41

标签: c++ arrays c++11 memory

我编写了以下程序来搜索给定字符串数组中的特定字符串。我在搜索功能中出错,然后写了i-而不是i ++。

#include <iostream>
#include <string>
using namespace std;

int search(string S[], int pos, string s)
{
    for(int i=0; i<pos; i--) {
        cout << i << " : " << S[i] << "\n";
        if (S[i] == s) {
            cout << "Inside Return ->\n";
            cout << i << " / " << S[i] << " / " << s << "\n";
            return i;
        }
    }
    return -1;
}

int main()
{
    string S[] = {"abc", "def", "pqr", "xyz"};
    string s = "def";
    cout << search(S,2,s) << "\n";
    return 0;
}

从逻辑上讲,该循环是一个无限循环,不应停止,但我观察到的是每次搜索的条件为true且该函数返回-1。

我打印了这些值,并注意到S [-1]的值始终与传递给该函数的第三个参数(要搜索的字符串)相同,这是因为该循环每次都返回-1。

这是g ++正在做的事情吗,还是与为函数的形式参数分配内存的方式有关?

以上代码的输出-

 0 : abc
-1 : def
Inside Return ->
-1 / def / def

PS-我正在使用g ++(Ubuntu 7.3.0-27ubuntu1〜18.04)7.3.0

编辑-我知道g ++不会检查边界,但我对S [-1]的值始终与s相同感到很感兴趣。我想知道是否有任何可能的理论

1 个答案:

答案 0 :(得分:7)

访问权限超出范围是不确定的行为。

未定义的行为读取不是“垃圾”或“ segfault”,实际上是任何东西。读取可能会花费时间,并使程序中较早的代码行为有所不同。该程序的行为从开始到结束,只要任何未定义的行为发生在任何地方,它就完全不受C ++标准的约束。

在这种情况下,朴素的汇编和ABI会告诉您在运行时“堆栈”上的参数与函数的参数等位置相邻。

因此,天真地将代码重写为程序集会导致从函数的参数读取负索引。

但是,将程序作为机器代码进行无数种完全无害,通用和安全的替代解释,从内联代码开始,然后再远离那里,就不会发生这种情况。

在没有LTO或超出动态库边界的情况下进行编译时,您可以放心一点,即使用编译器已发布的ABI进行调用;任何其他假设都是危险的。而且,如果您是在没有LTO的情况下进行编译并依靠它,那么这意味着从现在开始直到永恒之前,您都必须审核代码的每一个版本,否则很可能会出现没有明显原因的错误。