将char * []传递给接受char **作为参数的函数

时间:2017-09-14 19:18:30

标签: c++ command-line-arguments

我编写了一个对命令行参数进行排序的程序。但是,当我尝试打印输出(使用函数)时,我无法执行此操作。因为我试图在接受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 **作为参数的函数。

3 个答案:

答案 0 :(得分:1)

您从setArgs通过sortArgs进行分配,将自动变量strings的基地址存储到全局变量中。退出sortArgs并将控件返回parse后,该阵列将不再存在。其中的任何评估或取消引用都会调用未定义的行为

您可以通过简单地将argvargc设置到您的全局变量中来修复此(松散地使用术语,参见下一节的原因),并对这些进行排序,而不是将某些参数传递给某些函数。或者你可以像现在一样将指针复制到指针床上,然后对它们进行排序,然后将它们复制回argvNew

或者你会完全消除全局变量并在此过程中抛弃set意识形态,只需parse直接在argv内对指针进行排序你不能对它做很多事情,但是你可以对它进行重新排序,并且仍然可以在已定义的行为领域中说出来。

为什么?这是在C ++之后。

跳入C ++池

我不打算涂这个。代码很可怕。尽管除了基本的IO之外,它还是尽可能地使用尽可能少的C ++标准库产品来拼命地走在C ++的土地上。 C是一门优秀的语言,拥有一流的,精心打造的标准库,但是如果你想深入了解C ++,那么就不要害怕它;拥抱它。

要在C ++中执行此操作,请使用一些基本的C ++标准库产品。人们可以做大不相同的事情。例如:

  1. std::vector<std::string>argv
  2. 加载argc
  3. 做任何你想做的事情,包括排序。
  4. 这段代码比你想象的要简单得多:

    #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

请注意,stringsf1 f2数组的位置相同。 (这不保证,这恰好就是这里的情况。当然,这当然是正确的,并且有助于理解re:你看到的SEGV错误。)注意字符串文字&#34; foo&#34;,& #34; bar&#34;和&#34; baz&#34;汇集 - 即使它们不止一次使用,它们只有一个副本。字符串指针值的序列与链接器在内存中按顺序排列是一致的。

请注意,&global_arrayglobal_array的值相同,但global_ptr的情况并非如此。