我编写了一个对命令行参数进行排序的程序。但是,当我尝试打印输出(使用函数)时,我无法执行此操作。因为我试图在接受char **作为参数的函数中传递char * []。经过大量的搜索,没有什么结果,因此我在这里提出我的第一个问题。
#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
}
我正在尝试从函数sort()传递函数setArgs()中的字符串。后来当我用它来打印阵列时,它给了我seg故障。谁能帮助我在这里想象/纠正问题?
PS:我知道我可以在sort方法本身中打印char * strings [],但我主要关注的是如何将它传递给接受char **作为参数的函数。
答案 0 :(得分:1)
您从setArgs
通过sortArgs
进行分配,将自动变量strings
的基地址存储到全局变量中。退出sortArgs
并将控件返回parse
后,该阵列将不再存在。其中的任何评估或取消引用都会调用未定义的行为。
您可以通过简单地将argv
和argc
设置到您的全局变量中来修复此(松散地使用术语,参见下一节的原因),并对这些进行排序,而不是将某些参数传递给某些函数。或者你可以像现在一样将指针复制到指针床上,然后对它们进行排序,然后将它们复制回argvNew
。
或者你会完全消除全局变量并在此过程中抛弃set
意识形态,只需parse
直接在argv
内对指针进行排序你不能对它做很多事情,但是你可以对它进行重新排序,并且仍然可以在已定义的行为领域中说出来。
但为什么?这是在C ++之后。
跳入C ++池
我不打算涂这个。代码很可怕。尽管除了基本的IO之外,它还是尽可能地使用尽可能少的C ++标准库产品来拼命地走在C ++的土地上。 C是一门优秀的语言,拥有一流的,精心打造的标准库,但是如果你想深入了解C ++,那么就不要害怕它;拥抱它。
要在C ++中执行此操作,请使用一些基本的C ++标准库产品。人们可以做大不相同的事情。例如:
std::vector<std::string>
和argv
argc
这段代码比你想象的要简单得多:
#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;
}
答案 1 :(得分:0)
setArgs(strings, size); // pass the *strings[] here
这是错误的。
strings
是一个本地数组。它在函数返回时被删除。因此,当函数返回时,argNew
将成为悬空指针。尝试打印argNew
的内容是未定义的行为。
通过将strings
的元素复制到argNew
来替换该行。
for (i = 1; i < size; i++)
{
argNew[i] = strings[i-1];
}
答案 2 :(得分:0)
有许多好的搜索,例如&#34;双指针c&#34;在StackOverflow或Google上。例如。 c/c++ questions on pointers (double pointers)和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错误。)注意字符串文字&#34; foo&#34;,& #34; bar&#34;和&#34; baz&#34;汇集 - 即使它们不止一次使用,它们只有一个副本。字符串指针值的序列与链接器在内存中按顺序排列是一致的。
请注意,&global_array
与global_array
的值相同,但global_ptr
的情况并非如此。