将一个字符串数组作为参数传递给C中的函数

时间:2021-08-09 21:45:09

I want a simple function that receives a string and returns an array of strings after some parsing. So, this is my function signature:

我想要一个简单的函数,它接收一个字符串并在一些解析后返回一个字符串数组。所以,这是我的功能签名:

int parse(const char *foo, char **sep_foo, int *sep_foo_qty) {
    int i;
    char *token;
    ...
    strcpy(sep_foo[i], token); /* sf here */
    ...
}

Then I call it like this:

然后我称之为:

char sep_foo[MAX_QTY][MAX_STRING_LENGTH];
char foo[MAX_STRING_LENGTH];
int sep_foo_qty, error;

...

error = parse(foo, sep_foo, &sep_foo_qyt);

...

This way I get a warning during compilation:

这样我在编译期间会收到警告:

warning: passing argument 2 of 'parse' from incompatible pointer type

And then a segmentation fault during execution in the line marked with /* sf here */

然后在标记为/ * sf的行中执行期间出现分段错误* /

What is wrong in my C code?

我的C代码有什么问题?

Thanks in advance

提前致谢

4 个解决方案

#1


27  

The warning is exactly right. Your function wants an array of pointers. You're giving it an array of arrays.

警告是完全正确的。你的函数想要一个指针数组。你给它一个数组数组。

Expected:

预期:

 sep_foo:
 +------+       +-----+
 |char**|--> 0: |char*|-->"string1"
 +------+       +-----+
             1: |char*|-->"string2"
                +-----+
*sep_foo_qty-1: |...  |
                +-----+

What you provided:

你提供的是什么:

           sep_foo:
           +--------------------------------+
        0: | char[MAX_STRING_LENGTH]        |
           +--------------------------------+
        1: | char[MAX_STRING_LENGTH]        |
           +--------------------------------+
MAX_QTY-1: | ...                            |
           +--------------------------------+

An array with elements of type X can "decay" into a pointer-to-X, or X*. But the value of X isn't allowed to change in that conversion. Only one decay operation is allowed. You'd need it to happen twice. In your case, X is array-of-MAX_STRING_LENGTH-chars. The function wants X to be pointer-to-char. Since those aren't the same, the compiler warns you. I'm a bit surprised it was just a warning since nothing good can come from what the compiler allowed to happen.

具有X类型元素的数组可以“衰减”为指向X或X *的指针。但是X的值不允许在该转换中发生变化。只允许一次衰减操作。你需要它发生两次。在您的情况下,X是MAX_STRING_LENGTH-chars数组。该函数希望X成为指向char的指针。由于它们不相同,编译器会发出警告。我有点惊讶它只是一个警告,因为编译器允许发生的事情没有任何好处。

In your function, you could write this code:

在您的函数中,您可以编写以下代码:

char* y = NULL;
*sep_foo = y;

That's legal code since sep_foo is a char**, so *sep_foo is a char*, and so is y; you can assign them. But with what you tried to do, *sep_foo wouldn't really be a char*; it would be pointing to an array of char. Your code, in effect, would be attempting to do this:

这是合法代码,因为sep_foo是一个char **,所以* sep_foo是一个char *,所以是y;你可以分配它们。但是你试图做的事情,* sep_foo真的不是一个char *;它会指向一个char数组。实际上,您的代码将尝试执行此操作:

char destination[MAX_STRING_LENGTH];
char* y = NULL;
destination = y;

You can't assign a pointer into an array, and so the compiler warns that the call is no good.

您不能将指针分配给数组,因此编译器会警告该调用没有问题。

There are two ways to solve this:

有两种方法可以解决这个问题:

  • Change the way you declare and allocate sep_foo on the calling side so it matches what the function expects to receive:

    更改您在调用端声明和分配sep_foo的方式,以便它与函数期望接收的内容匹配:

    char** sep_foo = calloc(MAX_QTY, sizeof(char*));
    for (int i = 0; i < MAX_QTY; ++i)
      sep_foo[i] = malloc(MAX_STRING_LENGTH);
    

    or, equivalently

    或者,等效地

    char* sep_foo[MAX_QTY];
    for (int i = 0; i < MAX_QTY; ++i)
      sep_foo[i] = malloc(MAX_STRING_LENGTH);
    
  • Change the prototype of the function to accept what you're really giving it:

    更改函数的原型以接受您真正给出的内容:

    int parse(const char *foo, char sep_foo[MAX_QTY][MAX_STRING_LENGTH], int *sep_foo_qty);
    

#2


15  

Parameter 2 should be

参数2应该是

char sep_foo[][MAX_STRING_LENGTH]

To clarify, you are passing a pointer to parse() and treating it as a pointer to a pointer. A multidimensional array in C is NOT an array of pointers. It is a single block of memory that is pointed to by the array variable. You cannot dereference it twice.

为了澄清,您传递一个指向parse()的指针并将其视为指向指针的指针。 C中的多维数组不是指针数组。它是由数组变量指向的单个内存块。你不能两次取消引用它。

#3


4  

sep_foo is defined as an array of arrays. In other words, when you use sep_foo, it points to the beginning of sequential memory. Here's a model:

sep_foo被定义为数组数组。换句话说,当您使用sep_foo时,它指向顺序内存的开头。这是一个模型:

(assume MAX_STRING_LENGTH = 16, MAX_QTY = 2)
sep_foo       = &&0000
sep_foo[0]    =  &0000
sep_foo[0][0] = *&0000 = 12
sep_foo[0][8] = *&0008 = 74
sep_foo[1]    =  &0010
sep_foo[1][0] = *&0010 = 12


0000  12 34 56 78  9A BC DE F0  74 10 25 89  63 AC DB FE
0010  12 34 56 78  9A BC DE F0  74 10 25 89  63 AC DB FE

However, your function expects an array of pointers (actually, a pointer to a pointer). This is modeled as such:

但是,您的函数需要一个指针数组(实际上,指向指针的指针)。这是建模的:

sep_foo_arg       =   &&0000
sep_foo_arg[0]    =  *&&0000 = &0010
sep_foo_arg[0][0] =  *&*&0000 = 12
sep_foo_arg[0][8] = *(&*&0000 + 8) = 74
sep_foo_arg[1]    =  *&&0002 = &0020
sep_foo_arg[1][0] = *&*&0000 = 12

0000  0010 0020  xxxx xxxx  xxxx xxxx  xxxx xxxx

0010  12 34 56 78  9A BC DE F0  74 10 25 89  63 AC DB FE
0020  12 34 56 78  9A BC DE F0  74 10 25 89  63 AC DB FE

Yeah ... Syntax may be a bit confusing for my explanations...

是的...语法对我的解释可能有点混乱......

Anyway, you can solve this issue by telling your function how to treat the pointer pointed to. In particular, you would want to treat it as an array (a sequence of memory):

无论如何,你可以通过告诉你的函数如何处理指向的指针来解决这个问题。特别是,您可能希望将其视为一个数组(一系列内存):

int parse(const char *foo, char (*sep_foo)[MAX_STRING_LENGTH], int *sep_foo_qty);

#4


-2  

If that is your exact code, then I'm guessing the segfault is because of the fact that you haven't allocated memory to the char* token inside your parse function, and then using that in your strcpy.

如果这是你的确切代码,那么我猜测segfault是因为你没有为你的解析函数中的char *令牌分配内存,然后在你的strcpy中使用它。

#1


27  

The warning is exactly right. Your function wants an array of pointers. You're giving it an array of arrays.

警告是完全正确的。你的函数想要一个指针数组。你给它一个数组数组。

Expected:

预期:

 sep_foo:
 +------+       +-----+
 |char**|--> 0: |char*|-->"string1"
 +------+       +-----+
             1: |char*|-->"string2"
                +-----+
*sep_foo_qty-1: |...  |
                +-----+

What you provided:

你提供的是什么:

           sep_foo:
           +--------------------------------+
        0: | char[MAX_STRING_LENGTH]        |
           +--------------------------------+
        1: | char[MAX_STRING_LENGTH]        |
           +--------------------------------+
MAX_QTY-1: | ...                            |
           +--------------------------------+

An array with elements of type X can "decay" into a pointer-to-X, or X*. But the value of X isn't allowed to change in that conversion. Only one decay operation is allowed. You'd need it to happen twice. In your case, X is array-of-MAX_STRING_LENGTH-chars. The function wants X to be pointer-to-char. Since those aren't the same, the compiler warns you. I'm a bit surprised it was just a warning since nothing good can come from what the compiler allowed to happen.

具有X类型元素的数组可以“衰减”为指向X或X *的指针。但是X的值不允许在该转换中发生变化。只允许一次衰减操作。你需要它发生两次。在您的情况下,X是MAX_STRING_LENGTH-chars数组。该函数希望X成为指向char的指针。由于它们不相同,编译器会发出警告。我有点惊讶它只是一个警告,因为编译器允许发生的事情没有任何好处。

In your function, you could write this code:

在您的函数中,您可以编写以下代码:

char* y = NULL;
*sep_foo = y;

That's legal code since sep_foo is a char**, so *sep_foo is a char*, and so is y; you can assign them. But with what you tried to do, *sep_foo wouldn't really be a char*; it would be pointing to an array of char. Your code, in effect, would be attempting to do this:

这是合法代码,因为sep_foo是一个char **,所以* sep_foo是一个char *,所以是y;你可以分配它们。但是你试图做的事情,* sep_foo真的不是一个char *;它会指向一个char数组。实际上,您的代码将尝试执行此操作:

char destination[MAX_STRING_LENGTH];
char* y = NULL;
destination = y;

You can't assign a pointer into an array, and so the compiler warns that the call is no good.

您不能将指针分配给数组,因此编译器会警告该调用没有问题。

There are two ways to solve this:

有两种方法可以解决这个问题:

  • Change the way you declare and allocate sep_foo on the calling side so it matches what the function expects to receive:

    更改您在调用端声明和分配sep_foo的方式,以便它与函数期望接收的内容匹配:

    char** sep_foo = calloc(MAX_QTY, sizeof(char*));
    for (int i = 0; i < MAX_QTY; ++i)
      sep_foo[i] = malloc(MAX_STRING_LENGTH);
    

    or, equivalently

    或者,等效地

    char* sep_foo[MAX_QTY];
    for (int i = 0; i < MAX_QTY; ++i)
      sep_foo[i] = malloc(MAX_STRING_LENGTH);
    
  • Change the prototype of the function to accept what you're really giving it:

    更改函数的原型以接受您真正给出的内容:

    int parse(const char *foo, char sep_foo[MAX_QTY][MAX_STRING_LENGTH], int *sep_foo_qty);
    

#2


15  

Parameter 2 should be

参数2应该是

char sep_foo[][MAX_STRING_LENGTH]

To clarify, you are passing a pointer to parse() and treating it as a pointer to a pointer. A multidimensional array in C is NOT an array of pointers. It is a single block of memory that is pointed to by the array variable. You cannot dereference it twice.

为了澄清,您传递一个指向parse()的指针并将其视为指向指针的指针。 C中的多维数组不是指针数组。它是由数组变量指向的单个内存块。你不能两次取消引用它。

#3


4  

sep_foo is defined as an array of arrays. In other words, when you use sep_foo, it points to the beginning of sequential memory. Here's a model:

sep_foo被定义为数组数组。换句话说,当您使用sep_foo时,它指向顺序内存的开头。这是一个模型:

(assume MAX_STRING_LENGTH = 16, MAX_QTY = 2)
sep_foo       = &&0000
sep_foo[0]    =  &0000
sep_foo[0][0] = *&0000 = 12
sep_foo[0][8] = *&0008 = 74
sep_foo[1]    =  &0010
sep_foo[1][0] = *&0010 = 12


0000  12 34 56 78  9A BC DE F0  74 10 25 89  63 AC DB FE
0010  12 34 56 78  9A BC DE F0  74 10 25 89  63 AC DB FE

However, your function expects an array of pointers (actually, a pointer to a pointer). This is modeled as such:

但是,您的函数需要一个指针数组(实际上,指向指针的指针)。这是建模的:

sep_foo_arg       =   &&0000
sep_foo_arg[0]    =  *&&0000 = &0010
sep_foo_arg[0][0] =  *&*&0000 = 12
sep_foo_arg[0][8] = *(&*&0000 + 8) = 74
sep_foo_arg[1]    =  *&&0002 = &0020
sep_foo_arg[1][0] = *&*&0000 = 12

0000  0010 0020  xxxx xxxx  xxxx xxxx  xxxx xxxx

0010  12 34 56 78  9A BC DE F0  74 10 25 89  63 AC DB FE
0020  12 34 56 78  9A BC DE F0  74 10 25 89  63 AC DB FE

Yeah ... Syntax may be a bit confusing for my explanations...

是的...语法对我的解释可能有点混乱......

Anyway, you can solve this issue by telling your function how to treat the pointer pointed to. In particular, you would want to treat it as an array (a sequence of memory):

无论如何,你可以通过告诉你的函数如何处理指向的指针来解决这个问题。特别是,您可能希望将其视为一个数组(一系列内存):

int parse(const char *foo, char (*sep_foo)[MAX_STRING_LENGTH], int *sep_foo_qty);

#4


-2  

If that is your exact code, then I'm guessing the segfault is because of the fact that you haven't allocated memory to the char* token inside your parse function, and then using that in your strcpy.

如果这是你的确切代码,那么我猜测segfault是因为你没有为你的解析函数中的char *令牌分配内存,然后在你的strcpy中使用它。