3

ここで、char 配列を関数に渡し、関数で各インデックス メモリを指定し (malloc() を使用)、gets() を使用してキーボードから何かを挿入すると、何が間違っていますか。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>

void test(char *arr[]);
int main(){
  char *arr[2];//2 is the rows
 /* arr[0] = malloc(80);//This commented code works
  arr[1] = malloc(80);
  strcpy(arr[0], "hey");
  strcpy(arr[1], "whats up");
*/

  test(*arr);
  printf("in array[0]: %s", arr[0]);
  printf("in array[1]: %s", arr[1]);
  return 0;
}
void test(char *arr[]){
  int index;
  char *input = malloc(80);
  for(index = 0; index < 2; index++){
  arr[index] = malloc(80);
  gets(input);
  strcpy(arr[index], input);
  //arr[0] = input;
  }
}

何らかの理由で私が問題を抱えている非常に基本的なプログラムです。また、もう1つの質問配列を宣言するとき、これらのフォームの違いは何ですか

char *array

反対に

char *array[size]

また

char **array

ありがとう、ケビン

4

3 に答える 3

3

として宣言arrchar *arr[2]ます。次に、テストする*arrタイプのを渡します。char*ただし、テストではchar *[]。だからそれはうまくいきません。そのまま渡す必要がありarrますtest(arr)

char * array文字へのポインタであり、通常、文字の配列の最初の文字、つまり文字列を指すために使用されます。 char **array文字へのポインタへのポインタです。通常、文字列の配列を表すために使用されます。 char *array[size]上記のものとほとんど同じですが、それとは異なり、トップレベルポインタはすでに有効な配列を指しているため、配列をmalloc編集する必要はありません。

ちなみに、test関数は少し単純化できます。これstrcopyは不要です。

void test(char *arr[])
{
    int i;
    for(i=0;i<2;i++)
    {
        arr[i] = malloc(80);
        gets(arr[i]);
    }
}
于 2012-11-01T00:14:58.077 に答える
1

OK、C宣言では、宣言から読み取った最初のものだけが割り当てられます。

宣言の読み方を理解するまで、これは少しわかりにくいです。

演算子には優先順位があり、その優先順位は宣言に適用されます。簡単にするために、次のようにします。

() - Either raises precedence, or means "function taking parameters and returning..."
[] - Array of
* - Pointer to (right associative)

したがって、宣言:

char *a[3];

は「charへの3つのポインタの配列」ですが、

char (*a)[3];

「3文字の配列へのポインタ」(行幅3のマルチディメンション文字配列の行へのポインタ)です。

コンパイラーは、スタックの最初のものを割り当てます。したがって、最初の例では、(まだ割り当てられていない)文字を指すことができる3つのポインターを取得します。

| ptr | --> (unallocated char)
| ptr | --> (unalloc char)
| ptr | --> (unalloc char)

2番目に:

| ptr | --> (unallocated block of 3 char)

次のルールは次のとおりです。ポインタがある場合は、配列があります。したがって、どちらの場合も、最終的に多次元配列になります。

最初は、行数は固定されていますが(すでに割り当てられています)、コンパイラーはポインターを1文字でオフセットして次の文字に到達できることを知っているため、各行のサイズを変えることができます。

2番目の例では、行サイズは固定されていますが、コンパイラーはベースポインターを(それぞれ3文字ずつ)オフセットする方法を知っているため、任意の数の行があります。

Cは値による呼び出し言語でもあります。したがって、変数を宣言した場合:

char *a[3];

その場合、「a」自体は「3 ptrからcharの配列」ですが、a[0]は「ptrからchar」であり、a[0][0]はcharです。

次のことを期待する関数を作成する場合:

void f(char *arg[]) {
...
}

charへのポインタの配列を渡す必要があります。行がいくつあるかは関係ありません(それを追跡する必要があります)...タイプが正しいことだけを気にします。

したがって、最初の例のように「a」を宣言している場合は、f(a)を呼び出す必要があります。関数呼び出しは、関数argsに対して割り当てのようなことを行います。

f(a)は、(arg = a)でfを呼び出すことを意味します。

優先順位の規則は特に重要であり、次のような宣言を読み取ることができるようになるまで、これらに取り組む必要があります。

int (*f(int (*a)[4], void (*f)()))[6];

which is "f is a function that takes:
  - a pointer to arrays of 4 int
  - a pointer to a function that takes nothing and returns nothing)
and (then f) returns a pointer to arrays of 6 int".
于 2012-11-01T00:17:49.153 に答える
0

char *array は、メモリーのバイトへのポインターを作成します。char *array[size] は、長さ 'size' の配列へのポインタを作成します。char **配列は、メモリのバイトへのポインタへの単なるポインタです

ご覧のとおり、コードの問題は、テスト関数に予期しないものを渡そうとしていることです。テスト関数はポインターへのポインターを必要とします。ポインターを渡すだけです。正しいパッセージは次のようになります: test(arr);

2番目のものを大局的に見ると、コマンドラインプログラムを作成するときにこれが表示されます(一種)。

次のコードを検討してください。

#include<stdio.h>

int main(int argc, char *argv[]) {
    printf("%s\n", argv[0]);
    return 0;
}

argv ポインターはコマンド ライン引数を指し、それぞれが文字列 (単なるポインターまたは配列) です。したがって、Linux で次のことを行ったとします。

./some_program -option opt-input

これらはそれぞれ独自の文字列として扱われます。char *argv[] は各文字列を指します。最初の printf は ./some_program を出力します。これは、argv が指す最初の文字列だからです。

于 2012-11-01T00:27:38.340 に答える