将 char* [] 传递给接受 char** 作为参数的函数
Passing char* [] to a function which accepts char** as arguments
我编写了一个对命令行参数进行排序的程序。但是,当我尝试打印输出(使用函数)时,我无法执行 it.Because 我试图在接受 char** 作为参数的函数中传递 char *[] 。经过大量搜索,结果一无所获,因此我在这里提出了我在 SO 中的第一个问题。
#include "iostream"
#include "cstdlib"
#include "cstring"
using namespace std;
void sortArgs();
int stringcomp (const void * x, const void * y);
void parse(char **argv, int argc);
void printArgs();
void setArgs(char **argv, int argc);
int size;
char** argNew;
int main (int argc, char** argv)
{
parse(argv, argc);
printArgs();
return 0;
}
int stringcomp (const void *x, const void *y)
{
return strcmp (*(char * const *)x, *(char * const *)y);
}
void parse(char **argv, int argc)
{
setArgs(argv, argc);
sortArgs();
}
void setArgs(char **argv, int argc)
{
argNew=argv;
size=argc;
}
void printArgs()
{
char *s[size-1];
cout<<size<<endl;
for (int i = 1; i < size; i++)
{
s[i-1] = argNew[i];
}
for (int i = 0; i < size-1; i++)
cout<<" "<< s[i];
cout <<endl;
}
void sortArgs()
{
int i;
char *strings[size-1];
/* assign each argument to a pointer */
for (i = 1; i < size; i++)
{
strings[i-1] = argNew[i];
}
/* sort the array of pointers alphabetically with qsort */
qsort (strings, size - 1, sizeof *strings, stringcomp);
for (int i = 0; i < size-1; i++)
cout<<" "<< strings[i]; //this prints the output just fine
setArgs(strings, size); // pass the *strings[] here
}
我试图在函数 setArgs() 中从函数 sort() 传递 strings。后来当我用它来打印数组时,它给了我段错误。谁能帮我 visualize/rectify 解决这里的问题?
PS:我知道我可以在排序方法本身中打印 char* strings[],但我的主要关注点是如何将它传递给接受 char** 作为参数的函数。
setArgs(strings, size); // pass the *strings[] here
那是错误的。
strings
是局部数组。它在函数 returns 时被删除。因此,当函数 returns 时,argNew
将成为悬挂指针。尝试打印 argNew
的内容是未定义的行为。
通过将 strings
的元素复制到 argNew
来替换该行。
for (i = 1; i < size; i++)
{
argNew[i] = strings[i-1];
}
您通过 setArgs
从 sortArgs
进行赋值,将自动变量 strings
的基地址存储到全局变量中。一旦 sortArgs
退出并且控制返回到 parse
,该数组将不再存在。其中的任何评估或取消引用都会调用 未定义的行为。
你可以通过简单地坚持将 argv
和 argc
设置到你的全局变量中来解决这个问题(术语使用不严格,请参阅下一节了解原因),并对它们进行排序,而不是将一些参数传递给一些功能。或者您可以像现在一样将指针复制到指针床,然后对它们进行排序,然后将它们复制回 argvNew
.
或者你会完全消除全局并在这个过程中抛弃 set
意识形态,简单地让 parse
直接对 argv
中的指针进行排序你不能做太多它,但您可以对其重新排序并仍然在定义的行为范围内说。
但是为什么?这是之后,C++。
跳入 C++ 池
我不会美化这个。代码很可怕。除了基本 IO 之外,它正在拼命尝试使用尽可能少的 C++ 标准库产品走在 C++ 的土地上。 C 是一门伟大的语言,并且拥有出色的、完善的标准库,但是如果您想深入研究 C++,请不要害怕它;拥抱它。
要在 C++ 中执行此操作,请使用一些基本的 C++ 标准库产品。人们可以以截然不同的方式做事。例如:
- 从
argv
和 argc
加载 std::vector<std::string>
- 做任何你想做的事,包括排序。
该代码比您想象的要简单得多:
#include <iostream>
#include <vector>
#include <string>
std::vector<std::string> parseArgs(char **argv, int argc)
{
std::vector<std::string> args(argv+1, argv+argc);
std::sort(args.begin(), args.end());
return args;
}
int main (int argc, char** argv)
{
auto args = parseArgs(argv, argc);
// move to your own function.
for (auto const& s : args)
std::cout << s << '\n';
return 0;
}
有很多好的搜索,例如 Whosebug 上的 "double pointers c" 或 Google。例如。 c/c++ questions on pointers (double pointers) and http://www.cplusplus.com/doc/tutorial/pointers/.
也就是说,我建议的第一件事是您可以像打印数字一样打印指针的值。为此,请写:
printf("Pointer is %p.\n", ptr);
或:
std::cout << "Pointer is " << (void *)ptr << ".\n";
然后您可以分析以下输出:
#include <iostream>
// Sometimes it's char *, sometimes const char *
template <typename T>
void print_argv_style_array(const char *label, int argc, T **argv) {
int i = 0;
std::cout << label << ": Printing argv array of size " << argc << " at " << (void *)argv << ":\n";
for (int i = 0; i < argc; i++) {
std::cout << " " << i << ": " << (void *)argv[i] << " -- " << argv[i] << "\n";
}
}
void f1() {
const char *strings[] = { "foo", "bar" , "baz" };
print_argv_style_array("f1", sizeof(strings) / sizeof(strings[0]), strings);
}
void f2() {
const char *strings[] = { "foo", "bar" , "quux" };
print_argv_style_array("f2", sizeof(strings) / sizeof(strings[0]), strings);
}
const char *global_array[] = { "foo", "bar", "baz" };
const char **global_ptr = global_array;
int main(int argc, char **argv) {
std::cout << "main: argv is at " << &argv << "\n";
print_argv_style_array("main", argc, argv);
f1();
f2();
std::cout << "global_array is at: " << (void *)global_array << "\n";
print_argv_style_array("global_array", sizeof(global_array)/sizeof(global_array[0]), global_array);
std::cout << "global_ptr is at: " << (void *)&global_ptr << "\n";
print_argv_style_array("global_ptr", sizeof(global_array)/sizeof(global_array[0]), global_ptr);
}
我的系统看起来像:
main: argv is at 0x7fff5a8c38f0
main: Printing argv array of size 1 at 0x7fff5a8c3928:
0: 0x7fff5a8c3ab8 -- ./pointer_help
f1: Printing argv array of size 3 at 0x7fff5a8c38a0:
0: 0x10533dedc -- foo
1: 0x10533dee0 -- bar
2: 0x10533dee4 -- baz
f2: Printing argv array of size 3 at 0x7fff5a8c38a0:
0: 0x10533dedc -- foo
1: 0x10533dee0 -- bar
2: 0x10533deeb -- quux
global_array is at: 0x10533e140
global_array: Printing argv array of size 3 at 0x10533e140:
0: 0x10533dedc -- foo
1: 0x10533dee0 -- bar
2: 0x10533dee4 -- baz
global_ptr is at: 0x10533e158
global_ptr: Printing argv array of size 3 at 0x10533e140:
0: 0x10533dedc -- foo
1: 0x10533dee0 -- bar
2: 0x10533dee4 -- baz
请注意 strings
数组的位置对于 f1
和 f2
是相同的。 (这不能保证,这里恰好是这种情况。然而,这通常是正确的,并且有助于理解 re: 您看到的 SEGV 错误。)请注意字符串文字 "foo"、"bar",并且 "baz" 被合并——也就是说,即使它们被多次使用,它们也只有一个副本。字符串指针值的顺序也与链接器在内存中的顺序一致。
请注意 &global_array
与 global_array
的值相同,但 global_ptr
并非如此。
我编写了一个对命令行参数进行排序的程序。但是,当我尝试打印输出(使用函数)时,我无法执行 it.Because 我试图在接受 char** 作为参数的函数中传递 char *[] 。经过大量搜索,结果一无所获,因此我在这里提出了我在 SO 中的第一个问题。
#include "iostream"
#include "cstdlib"
#include "cstring"
using namespace std;
void sortArgs();
int stringcomp (const void * x, const void * y);
void parse(char **argv, int argc);
void printArgs();
void setArgs(char **argv, int argc);
int size;
char** argNew;
int main (int argc, char** argv)
{
parse(argv, argc);
printArgs();
return 0;
}
int stringcomp (const void *x, const void *y)
{
return strcmp (*(char * const *)x, *(char * const *)y);
}
void parse(char **argv, int argc)
{
setArgs(argv, argc);
sortArgs();
}
void setArgs(char **argv, int argc)
{
argNew=argv;
size=argc;
}
void printArgs()
{
char *s[size-1];
cout<<size<<endl;
for (int i = 1; i < size; i++)
{
s[i-1] = argNew[i];
}
for (int i = 0; i < size-1; i++)
cout<<" "<< s[i];
cout <<endl;
}
void sortArgs()
{
int i;
char *strings[size-1];
/* assign each argument to a pointer */
for (i = 1; i < size; i++)
{
strings[i-1] = argNew[i];
}
/* sort the array of pointers alphabetically with qsort */
qsort (strings, size - 1, sizeof *strings, stringcomp);
for (int i = 0; i < size-1; i++)
cout<<" "<< strings[i]; //this prints the output just fine
setArgs(strings, size); // pass the *strings[] here
}
我试图在函数 setArgs() 中从函数 sort() 传递 strings。后来当我用它来打印数组时,它给了我段错误。谁能帮我 visualize/rectify 解决这里的问题?
PS:我知道我可以在排序方法本身中打印 char* strings[],但我的主要关注点是如何将它传递给接受 char** 作为参数的函数。
setArgs(strings, size); // pass the *strings[] here
那是错误的。
strings
是局部数组。它在函数 returns 时被删除。因此,当函数 returns 时,argNew
将成为悬挂指针。尝试打印 argNew
的内容是未定义的行为。
通过将 strings
的元素复制到 argNew
来替换该行。
for (i = 1; i < size; i++)
{
argNew[i] = strings[i-1];
}
您通过 setArgs
从 sortArgs
进行赋值,将自动变量 strings
的基地址存储到全局变量中。一旦 sortArgs
退出并且控制返回到 parse
,该数组将不再存在。其中的任何评估或取消引用都会调用 未定义的行为。
你可以通过简单地坚持将 argv
和 argc
设置到你的全局变量中来解决这个问题(术语使用不严格,请参阅下一节了解原因),并对它们进行排序,而不是将一些参数传递给一些功能。或者您可以像现在一样将指针复制到指针床,然后对它们进行排序,然后将它们复制回 argvNew
.
或者你会完全消除全局并在这个过程中抛弃 set
意识形态,简单地让 parse
直接对 argv
中的指针进行排序你不能做太多它,但您可以对其重新排序并仍然在定义的行为范围内说。
但是为什么?这是之后,C++。
跳入 C++ 池
我不会美化这个。代码很可怕。除了基本 IO 之外,它正在拼命尝试使用尽可能少的 C++ 标准库产品走在 C++ 的土地上。 C 是一门伟大的语言,并且拥有出色的、完善的标准库,但是如果您想深入研究 C++,请不要害怕它;拥抱它。
要在 C++ 中执行此操作,请使用一些基本的 C++ 标准库产品。人们可以以截然不同的方式做事。例如:
- 从
argv
和argc
加载 - 做任何你想做的事,包括排序。
std::vector<std::string>
该代码比您想象的要简单得多:
#include <iostream>
#include <vector>
#include <string>
std::vector<std::string> parseArgs(char **argv, int argc)
{
std::vector<std::string> args(argv+1, argv+argc);
std::sort(args.begin(), args.end());
return args;
}
int main (int argc, char** argv)
{
auto args = parseArgs(argv, argc);
// move to your own function.
for (auto const& s : args)
std::cout << s << '\n';
return 0;
}
有很多好的搜索,例如 Whosebug 上的 "double pointers c" 或 Google。例如。 c/c++ questions on pointers (double pointers) and http://www.cplusplus.com/doc/tutorial/pointers/.
也就是说,我建议的第一件事是您可以像打印数字一样打印指针的值。为此,请写:
printf("Pointer is %p.\n", ptr);
或:
std::cout << "Pointer is " << (void *)ptr << ".\n";
然后您可以分析以下输出:
#include <iostream>
// Sometimes it's char *, sometimes const char *
template <typename T>
void print_argv_style_array(const char *label, int argc, T **argv) {
int i = 0;
std::cout << label << ": Printing argv array of size " << argc << " at " << (void *)argv << ":\n";
for (int i = 0; i < argc; i++) {
std::cout << " " << i << ": " << (void *)argv[i] << " -- " << argv[i] << "\n";
}
}
void f1() {
const char *strings[] = { "foo", "bar" , "baz" };
print_argv_style_array("f1", sizeof(strings) / sizeof(strings[0]), strings);
}
void f2() {
const char *strings[] = { "foo", "bar" , "quux" };
print_argv_style_array("f2", sizeof(strings) / sizeof(strings[0]), strings);
}
const char *global_array[] = { "foo", "bar", "baz" };
const char **global_ptr = global_array;
int main(int argc, char **argv) {
std::cout << "main: argv is at " << &argv << "\n";
print_argv_style_array("main", argc, argv);
f1();
f2();
std::cout << "global_array is at: " << (void *)global_array << "\n";
print_argv_style_array("global_array", sizeof(global_array)/sizeof(global_array[0]), global_array);
std::cout << "global_ptr is at: " << (void *)&global_ptr << "\n";
print_argv_style_array("global_ptr", sizeof(global_array)/sizeof(global_array[0]), global_ptr);
}
我的系统看起来像:
main: argv is at 0x7fff5a8c38f0
main: Printing argv array of size 1 at 0x7fff5a8c3928:
0: 0x7fff5a8c3ab8 -- ./pointer_help
f1: Printing argv array of size 3 at 0x7fff5a8c38a0:
0: 0x10533dedc -- foo
1: 0x10533dee0 -- bar
2: 0x10533dee4 -- baz
f2: Printing argv array of size 3 at 0x7fff5a8c38a0:
0: 0x10533dedc -- foo
1: 0x10533dee0 -- bar
2: 0x10533deeb -- quux
global_array is at: 0x10533e140
global_array: Printing argv array of size 3 at 0x10533e140:
0: 0x10533dedc -- foo
1: 0x10533dee0 -- bar
2: 0x10533dee4 -- baz
global_ptr is at: 0x10533e158
global_ptr: Printing argv array of size 3 at 0x10533e140:
0: 0x10533dedc -- foo
1: 0x10533dee0 -- bar
2: 0x10533dee4 -- baz
请注意 strings
数组的位置对于 f1
和 f2
是相同的。 (这不能保证,这里恰好是这种情况。然而,这通常是正确的,并且有助于理解 re: 您看到的 SEGV 错误。)请注意字符串文字 "foo"、"bar",并且 "baz" 被合并——也就是说,即使它们被多次使用,它们也只有一个副本。字符串指针值的顺序也与链接器在内存中的顺序一致。
请注意 &global_array
与 global_array
的值相同,但 global_ptr
并非如此。