为什么通过*** char传递给函数的nullptr终止数组会松散终止元素?

时间:2014-08-10 10:54:43

标签: c++ c arrays

注1:我不是在寻找不同的解决方案。我很好奇这里发生了什么。

注2:我在c ++上下文中这样做,但我假设这也适用于C,因此也适用于C标签。 (除了空指针的表示)

这是关于c-strings和从函数访问原始文件。我将使用argv和argc来说明数组应该是nullptr终止的。我声明他们是这样的:

int argc = 1;
char **argv = (char**) malloc( (argc + 1) * sizeof(char*) );
argv[0] = (char*)"argument 0";
argv[1] = nullptr;

如果我声明这样的函数:func1(int &f_argc, char **f_argv)我可以访问函数范围内的所有元素,包括f_argv[f_argc]nullptr,但我无法修改原始{{1}指向一个不同的地址,因为函数中的f_argv是一个传递原始指针副本的值。它在内存中有不同的地址。

如果我声明这样的函数:argv,我可以在函数中访问原始func2(int &f_argc, char ***f_argv)argv,但是最后一个元素(应该是*f_argv }被切断了。这意味着如果我尝试检查函数内的终止nullptr,我会尝试访问数组范围之外的元素,从而在运行时生成核心转储。

问题1:为什么在func2中到达nullptrf_argv会被切断,但在func1中却没有?

Q2:有没有办法从函数中获取原始nullptr的写入权限,而无需删除终结符?

编辑:(添加代码以显示我的意思)

argv

如果运行func2,则运行该程序会在此行导致核心转储:

#include <iostream>
#include <cstring>

void func1(int &f_argc, char **f_argv) {
    using std::cout;
    using std::endl;

    cout << "    In function:" << endl;
    cout << "    argv passed as **f_argv" << endl;
    cout << "    f_argv = " << f_argv << " , &f_argv = " << &f_argv << endl;

    for (int pos = 0; pos < f_argc; pos++) {
        if (f_argv[pos] != nullptr) {
            cout << "    f_argv[" << pos << "] = \"" << f_argv[pos] << "\"" << endl;
        } else {
            cout << "    f_argv is prematurely terminated" << endl;
        }
    }

    if (f_argv[f_argc] == nullptr) {
        cout << "    f_argv is correctly terminated" << endl;
    } else {
        cout << "    f_argv[" << f_argc << "] = \"" << f_argv[f_argc] << "\"" << endl;
        cout << "    f_argv is not terminated" << endl;
    }

    // Intention is to copy argv here, add elements, terminate it with
    // nullptr and change original argv to point to copy. This wouldn't
    // work in this function, as &f_argv != &argv.

    return;
}

void func2(int &f_argc, char ***f_argv) {
    using std::cout;
    using std::endl;

    cout << "    In function:" << endl;
    cout << "    array passed as ***f_argv" << endl;
    cout << "    f_argc = " << f_argc
         << " , &f_argc = " << &f_argc << endl;
    cout << "    *f_argv = " << *f_argv
         << " , f_argv = " << f_argv << endl;

    for (int pos = 0; pos < f_argc; pos++) {
        cout << "    about to check: "
             << "if (*f_argv[" << pos << "] != nullptr)" << endl;
        if (*f_argv[pos] != nullptr) {
            cout << "    *f_argv[" << pos << "] = \""
                 << *f_argv[pos] << "\"" << endl;
        } else {
            cout << "    *f_argv is prematurely terminated" << endl;
        }
    }

    if (*f_argv[f_argc] == nullptr) {
        cout << "    *f_argv is correctly terminated" << endl;
    } else {
        cout << "    *f_argv[" << f_argc << "] = \""
             << *f_argv[f_argc] << "\"" << endl;
        cout << "    *f_argv is not terminated" << endl;
    }

    // Intention is to copy argv here, add elements, terminate it with
    // nullptr and change original argv to point to copy.

    return;
}



// --------------------------------------------

int main() {
    using std::cout;
    using std::endl;

    int argc=1;
    char **argv = (char**) malloc( (argc + 1) * sizeof(char*) );
    argv[0] = (char*)"argument 0";
    argv[1] = nullptr;

    cout << "Before function call" << endl;
    cout << "argv = " << argv << " , &argv = " << &argv << endl;
    for (int i = 0; i < argc; i++) {
        if (argv[i] != nullptr) {
            cout << "argv[" << i << "] = \"" << argv[i] << "\"" << endl;
        } else {
            cout << "argv is prematurely terminated" << endl;
        }
    }
    if (argv[argc] == nullptr) {
        cout << "argv is correctly terminated" << endl;
    } else {
        cout << "argv[" << argc << "] = \"" << argv[argc] << "\"" << endl;
        cout << "argv is not terminated" << endl;
    }

    // run one of these
    //func1(argc, argv);
    func2(argc, &argv);

    free(argv);

    return 0;

}

1 个答案:

答案 0 :(得分:3)

下标运算符的优先级高于解除引用运算符。 *f_argv[f_argc]*(f_argv[f_argc])。你想要的是(*f_argv)[f_argc]

由于您使用的是C ++,因此您应该考虑通过引用f_argv - void f(int &f_argc, char **& f_argv);