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とマークされた行での実行中のセグメンテーション違反*/

私のCコードの何が問題になっていますか?

前もって感謝します

4

4 に答える 4

28

警告は正確に正しいです。関数にはポインターの配列が必要です。あなたはそれに配列の配列を与えています。

期待される:

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

あなたが提供したもの:

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

タイプの要素を持つ配列は、またはXへのポインタに「減衰」する可能性があります。ただし、その変換での値を変更することはできません。1つの減衰操作のみが許可されます。あなたはそれが二度起こる必要があるでしょう。あなたの場合、は-文字の配列です。関数はcharへのポインタになりたいです。それらは同じではないので、コンパイラは警告します。コンパイラーが許可したことからは何も得られないので、それが単なる警告であったことに少し驚いています。XX*XXMAX_STRING_LENGTHX

関数では、次のコードを記述できます。

char* y = NULL;
*sep_foo = y;

であるため、これは合法的なコードでsep_fooあり、であり、であるため、; それらを割り当てることができます。しかし、あなたがやろうとしたことでは、実際にはそうではありませ。それはcharの配列を指しているでしょう。あなたのコードは、事実上、これを行おうとしているでしょう:char***sep_foochar*y*sep_foochar*

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

配列にポインタを割り当てることはできないため、コンパイラは呼び出しが適切でないことを警告します。

これを解決するには2つの方法があります。

  • 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の多次元配列は、ポインターの配列ではありません。これは、配列変数が指すメモリの単一ブロックです。2回逆参照することはできません。

于 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で使用しているためだと思います。

于 2009-01-28T01:11:52.940 に答える