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

Sau*_*abh 0 c++ memory arrays c++11

我编写了以下程序来搜索给定数组字符串中的特定字符串.我在搜索功能中出错并写了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;
}
Run Code Online (Sandbox Code Playgroud)

逻辑上,循环是一个无限循环,不应该停止,但我观察到的是每个搜索的if条件为真,函数返回-1.

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

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

输出上述代码 -

 0 : abc
-1 : def
Inside Return ->
-1 / def / def
Run Code Online (Sandbox Code Playgroud)

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

编辑 - 我知道g ++没有检查边界,但我对S [-1]的值始终与s相同的事实感到好奇.我想知道是否有任何可能的理论

Yak*_*ont 7

访问越界是未定义的行为.

未定义的行为读取不是"垃圾"或"段错误",它实际上是任何东西.读取可以计时,并使程序中较早的代码表现不同.程序的行为,从开始到结束,只要任何未定义的行为发生在任何地方,它就完全没有被C++标准指定.

在这种情况下,naive程序集和ABI告诉您运行时"堆栈"上的参数位于函数参数之类的位置.

因此,将代码简单地重写为汇编会导致负数索引从函数的参数中读取.

但是,对于你的程序作为机器代码,从内联开始并远离那里的整个无数完全无害,通用和安全的替代解释,使得这种情况不会发生.

在没有LTO或动态库边界的情况下进行编译时,您可以对编译器发布的ABI进行调用有一点信心; 别处的任何假设都是危险的.如果您在没有LTO的情况下进行编译并依赖它,那么现在就意味着您必须从现在开始审计代码的每个版本,直到永久,或者冒着出现错误的风险,从现在开始没有明显的原因.