将 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];
}

您通过 setArgssortArgs 进行赋值,将自动变量 strings 的基地址存储到全局变量中。一旦 sortArgs 退出并且控制返回到 parse,该数组将不再存在。其中的任何评估或取消引用都会调用 未定义的行为

你可以通过简单地坚持将 argvargc 设置到你的全局变量中来解决这个问题(术语使用不严格,请参阅下一节了解原因),并对它们进行排序,而不是将一些参数传递给一些功能。或者您可以像现在一样将指针复制到指针床,然后对它们进行排序,然后将它们复制回 argvNew.

或者你会完全消除全局并在这个过程中抛弃 set 意识形态,简单地让 parse 直接对 argv 中的指针进行排序你不能做太多它,但您可以对其重新排序并仍然在定义的行为范围内说。

但是为什么?这是之后,C++。

跳入 C++ 池

我不会美化这个。代码很可怕。除了基本 IO 之外,它正在拼命尝试使用尽可能少的 C++ 标准库产品走在 C++ 的土地上。 C 是一门伟大的语言,并且拥有出色的、完善的标准库,但是如果您想深入研究 C++,请不要害怕它;拥抱它。

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

  1. argvargc
  2. 加载 std::vector<std::string>
  3. 做任何你想做的事,包括排序。

该代码比您想象的要简单得多:

#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 数组的位置对于 f1f2 是相同的。 (这不能保证,这里恰好是这种情况。然而,这通常是正确的,并且有助于理解 re: 您看到的 SEGV 错误。)请注意字符串文字 "foo"、"bar",并且 "baz" 被合并——也就是说,即使它们被多次使用,它们也只有一个副本。字符串指针值的顺序也与链接器在内存中的顺序一致。

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