14

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

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

然后我这样称呼它:

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);

...

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

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

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

我的 C 代码有什么问题?

提前致谢

4

4 回答 4

28

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

预期的:

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

您提供的内容:

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

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

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

char* y = NULL;
*sep_foo = y;

那是法律代码,因为sep_foo是 a char**,所以*sep_foo是 a char*,所以是y;你可以分配他们。但是,对于您尝试做的事情,实际上*sep_foo不会是; 它将指向一个字符数组。实际上,您的代码将尝试执行此操作:char*

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

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

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

  • 更改您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);
    

    或者,等效地

    char* sep_foo[MAX_QTY];
    for (int i = 0; i < MAX_QTY; ++i)
      sep_foo[i] = malloc(MAX_STRING_LENGTH);
    
  • 更改函数的原型以接受你真正给它的东西:

    int parse(const char *foo, char sep_foo[MAX_QTY][MAX_STRING_LENGTH], int *sep_foo_qty);
    
于 2009-01-28T01:13:04.217 回答
15

参数 2 应该是

char sep_foo[][MAX_STRING_LENGTH]

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

于 2009-01-28T01:13:39.580 回答
4

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

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

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

是的......我的解释可能有点令人困惑......

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

int parse(const char *foo, char (*sep_foo)[MAX_STRING_LENGTH], int *sep_foo_qty);
于 2009-01-28T01:18:27.777 回答
-2

如果那是您的确切代码,那么我猜测段错误是因为您没有为char* token解析函数内部分配内存,然后在 strcpy.xml 中使用它。

于 2009-01-28T01:11:52.940 回答