为什么通过***char传递给函数的以nullptr结尾的数组会丢失终止元素?
Why does a nullptr terminated array passed to function through ***char loose the termination element?
注意1:我不是在寻找不同的解决手头问题的方法。我很好奇这里到底发生了什么。
注2:我在c++上下文中这样做,但我假设这也适用于c,因此使用c标签。(除了空指针的表示)
这是关于c字符串和访问原始函数。我将使用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
,但我不能修改原来的argv
指向不同的地址,因为函数中的f_argv是原始指针的值传递副本。它在内存中有不同的地址。
如果我像这样声明函数:func2(int &f_argc, char ***f_argv)
,我可以通过函数中的*f_argv
访问原来的argv
,但是最后一个元素(应该是nullptr
)被切断了。这意味着,如果我试图检查函数内的终止nullptr
,我就会尝试访问数组范围之外的元素,从而在运行时导致核心转储。
Q1:为什么在func2中到达nullptr
时f_argv
被切断,而在func1中没有?
argv
的写访问,而不删除终止符?编辑:(添加代码以显示我的意思)
#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;
}
如果运行func2,运行程序会在这一行产生一个核心转储:
if (*f_argv[f_argc] == nullptr) {
下标操作符的优先级高于解引用操作符。*f_argv[f_argc]
为*(f_argv[f_argc])
。你需要的是(*f_argv)[f_argc]
。
因为你正在使用c++,你应该考虑通过引用f_argv
- void f(int &f_argc, char **& f_argv);
。