1

我有以下有效的 C 代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>

int pw = sizeof(char*);     // width of pointer (to char)

int num;
int first = 1;
int size = 0;
int incr = 10;

char *(*arr)[];     // pointer to array of pointers to char */

test(char* s, int i)
{

  int j;
  char *(*newarr)[];        // pointer to array of pointers to char

  if (first) {          // first time
    arr = malloc(pw*incr);  // malloc array
    first = 0;          // skip from now on
    size = incr;        // save the size
  }


  if (i >= size) {          // out of space
    newarr = malloc(pw*(size+incr));    // get incr bigger space
    for (j=0; j<size; j++)      // copy the elements from the old
      (*newarr)[j] = (*arr)[j];     // array to new array
    free(arr);                  // free the old array space
    arr = newarr;           // point old array to new array
    size = size+incr;

  };

  int len = strlen(s);      // length of s
  (*arr)[i] = malloc(len+1);    // assign pointer to pointer array element
  strcpy((*arr)[i], s);     // copy s to array
                    // both arguments must be pointers

  printf("%d\t%s\n", i, (*arr)[i]);
};

main() 
{

  char* s = "this is a string";

  for (num=0; num<30; num++)    // add 30 pointers to s to *arr
    test(s, num);

  for (num=0; num<30; num++)
    printf("%d\t%s\n", num, (*arr)[num]); // print out what they point to
};

它从 0 到 29 两次打印出 'i\tthis is a string' for 'i'。我想要做的是从文件顶部传递'arr'作为'test'的参数。我想这样做的原因是因为我想传递几个不同的数组,所有这些数组都以相同的方式声明。如果我做出最小的改变,我会得到:

0   this is a string
Segmentation fault (core dumped)

这是 diff 命令的输出,显示了最小的更改:

    13c13
< char *(*arr)[];       // pointer to array of pointers to char */
---
> char *(*jarr)[];      // pointer to array of pointers to char */
15c15
< test(char* s, int i)
---
> test(char* s, int i, char *(*arr)[])
52c52
<     test(s, num);
---
>     test(s, num, jarr);
54,55d53
<   for (num=0; num<30; num++)
<     printf("%d\t%s\n", num, (*arr)[num]); // print out what they point to

换句话说,除了将“arr”重命名为“jarr”并将其传递给“test”之外,一切都是一样的。

在此先感谢,迈克

4

3 回答 3

1

调用时出现问题:

test(s, num, jarr);

你是jarr按价值传递的。在函数内部,您正在重新分配(困难的方式 - 为什么不使用realloc()为您进行复制?)数组,但该更改不会影响jarr'in main()' 的值,因为它是按值传递的。第二次通过循环时,您仍然将一个空指针传递给该函数,但随后您将取消引用该空指针,这是个坏消息。

怎么修?

公平的问题......我不确定旧的“好吧,如果我想到达那里,我不会从这里开始”的恶作剧是否通过召集。

“最简单”的更改是修改调用:

jarr = test(s, num, jarr);

然后“只是”修改函数,使其返回指向字符指针数组的指针。这是一个非常深奥的功能。我的大脑还没醒(咖啡因不足),所以我使用了一个中间体typedef来解决如何编写函数声明和定义的问题:

typedef char *(ArrayString[]);

ArrayString *test3(char *s, int i, char *(*arr)[]);

ArrayString *test3(char *s, int i, char *(*arr)[]) { (*arr)[i] = s; return arr; }

它编译时没有警告;这并不能保证它是正确的。

主要的替代方法是将指针传递给指向函数的 char 指针数组的指针,这更加深奥。


但是,这两个都是“从这里开始”的解决方案。总的来说,你最好设计一种不同的处理方式。指向数组的指针当然是 C 的一部分,但它们位于 C 的外部边缘,您通常应该假设如果您的设计需要使用它们,那么您的设计可能不是最好的。您应该使用更简单的char **(或者,打消这个念头,char ***最好避免三重间接,但这并不总是可能的)。

于 2012-09-05T14:29:58.313 回答
1

您似乎误解了数组和指针的工作原理。假设您想要一个动态的字符串数组,它基本上是一个指向以下指针的指针char

char **arr = NULL;

为此分配内存,例如

arr = malloc(sizeof(char *) * current_size);

现在你有了一个字符指针的“数组”。假设您希望这些中的每一个都是特定的字符串str

for (int i = 0; i < current_size; i++)
{
    arr[i] = strdup(str);
}

哦,现在你需要增加字符串的数量,全部初始化为和之前一样的字符串:

size_t new_size = current_size + 10;
arr = realloc(arr, sizeof(char *) * new_size);

for (int i = current_size; i < new_size)
{
    arr[i] = strdup(str);
}

现在的问题是您想在一个单独的函数中完成上述所有操作。首先,您必须添加另一个间接。

于 2012-09-05T14:37:11.160 回答
0

我认为您可以在 test(s, 0, jarr) 和 test(s, 0, jarr) 中对分配给 jarr 的第一个 malloc 值进行仔细检查;由于您在按值传递中更改了指针值,因此 jarr 分配不成功。

于 2012-09-05T14:37:17.923 回答