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

'i\tこれは'i'の文字列'を0から29まで2回出力します。私がやりたいのは、ファイルの先頭から「test」の引数として「arr」を渡すことです。私がそれをしたい理由は、すべて同じ方法で宣言されているいくつかの異なる配列を渡したいからです。それを行うために最小限の変更を加えると、次のようになります。

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ています。関数内で、配列を再割り当てしています(難しい方法です。どちらを使用してコピーを行うのですか?)が、値によって渡されたため、その変更は'in 'realloc()の値には影響しません。2回目のループでは、まだnullポインターを関数に渡していますが、そのnullポインターを逆参照しています。これは、悪いニュースです。jarrmain()

直し方?

公正な質問...古い「まあ、そこに行きたいのなら、ここから始めない」ギャグが集まるかどうかはわかりません。

「最も簡単な」変更は、呼び出しを修正することです。

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

テスト(s、0、jarr)とテスト外(s、0、jarr)の両方でjarrに割り当てられた最初のmalloc値を再確認できると思います。値渡しでポインタ値を変更したため、jarrの割り当ては成功しません。

于 2012-09-05T14:37:17.923 に答える