1

私はCS1クラスのプロジェクトに取り組んでいますが、これまで考えたことのない何かに遭遇しました。Cのすべての配列は、基本的に配列の最初の要素へのポインターであり、文字列は実際には単なる文字配列であることを私は知っています。ただし、私の割り当てでは、ファイルを読み込む必要があり、ファイルの一部は次のとおりです。

Brad Tim Rick(スペースで区切られたより多くの男性の名前)
ルーシーアンジェラティナ(スペースで区切られたより多くの女性の名前)

これは短い例ですが、私がしなければならないのは、名前を抽出して、男性用と女性用の2つの別々の配列に格納することです。

私はこのようなものを使ったことがないので、もちろん混乱しています。これは私がやろうとしていることですが、もちろん機能していません...そうそう、動的割り当てにそれらを格納しようとしています。唯一の仕様では、名前は19文字を超えることはありません(文字列の最後の「/ 0」が何があっても存在できるようにするには、20文字と言う必要がありますか?)コンパイラに「ちょっと欲しい文字列の配列であり、各文字列は「文字列トレーラー'/ 0'」に対して19文字+1を保持できますか?それでは、ポインタを介してそれらにアクセスするにはどうすればよいですか?

char **mens_names, **womens_names;

mens_names = malloc(number_of_couples * sizeof(char[19]));
womens_names = malloc(number_of_couples * sizeof(char[19]));

if(mens_names == NULL){
printf("Malloc failed! Memory could not be allocated to variable mens_names.");
return -1;
}

int i;
for(i = 0; i < number_of_couples; i++){
    fscanf(input_file, "%s", &mens_names[i]);
}


if(womens_names == NULL){
    printf("Malloc failed! Memory could not be allocated to variable womens_names.");
    return -1;
}

for(i = 0; i < number_of_couples; i++){
    fscanf(input_file, "%s", &womens_names[i]);
}

for(i = 0; i < number_of_couples; i++){
    printf("Man: %s ", mens_names[i]);
    printf("Woman: %s\n", womens_names[i]);
}
4

3 に答える 3

2

あなたは2D配列について話していますが、それを1次元配列としてのみ初期化しています。2D 配列 (行列) の正しい初期化は次のとおりです。

static char** allocate_matrix(int nrows, int ncols) 
{
    int i;
    char **matrix;

    /*  allocate array of pointers  */
    matrix = malloc( nrows*sizeof(char*));

    if(matrix==NULL)
        return NULL; /* Allocation failed */

    /*  Allocate column for each name  */
    for(i = 0; i < nrows; i++)
        matrix[i] = malloc( ncols*sizeof(char));

    if(matrix[i-1] == NULL) 
        return NULL; /* Allocation failed */

    return matrix;
}

あなたのmain()で:

<...>
mens_names = allocate_matrix(number_of_couples, 19);
womens_names = allocate_matrix(number_of_couples, 19);
<...>

/* Of course, do not forget to free memory once you are done */
于 2013-01-29T13:06:45.267 に答える
2

Cの配列は、基本的に配列の最初の要素へのポインターであることを知っています

そうではありません。配列とポインターは、まったく別のものです。sizeof_Alignof、または単項演算子のオペランドである場合、または&宣言で配列を初期化するために使用される文字列リテラルである場合を除き、型 "N 要素配列"のは型 "pointer の式に変換されます。へ" となり、その値は配列の最初の要素のアドレスになります。 TT

宣言を考えると

int a[10];

を指定するオブジェクトaは、常に 10 要素の配列ですint。ただし、 aは最初の要素へのポインタとして扱われる場合があります。

文字列の長さが 19 文字 (ターミネータを含めて 20 要素) を超えることはないことがわかっているが、事前に文字列の数がわからない場合は、次のようにすることができます

char (*mens_names)[20];
char (*womens_names)[20];
...
mens_names = malloc(number_of_couples * sizeof *mens_names);
womens_names = malloc(number_of_couples * sizeof *womens_names);
...
fscanf(input_file, "%s", mens_names[i]);
...
free(mens_names);
free(womens_names);

この場合、 (括弧が重要)の 20 要素配列へのポインタとしてmens_namesandを宣言しました。したがって、と同等です。 womens_namescharsizeof *mens_namessizeof (char [20])

通常の 2 次元配列の場合と同様に、個々の文字にアクセスします。

char x = mens_names[i][j];

mens_names[i]mens_namesポインターを暗黙的に逆参照します (式a[i]は として解釈されることに注意して*(a + i)ください)。

この方法には、KBart の方法よりもいくつかの利点があります。まず、すべてのメモリが単一のチャンクとして連続して割り当てられます。これは、キャッシュが問題になる場合に問題になる可能性があります。次に、アレイごとmallocに 1 つだけ必要です。freeもちろん、これは、各名前配列の最大サイズが a) 固定であり、b) コンパイル時にわかっていることを前提としています。

実行時まで名前のサイズがわからず、可変長配列をサポートする C99 コンパイラまたは C2011 コンパイラを使用している場合は、次のようにすることができます。

size_t name_len, number_of_couples;
// get name_len from the user or input file
// get number_of_couples
char (*mens_names)[name_len+1] = malloc(number_of_couples * sizeof *mens_names);
...

実行時まで名前のサイズがわからず、 VLA をサポートしないコンパイラを使用している場合は、KBart の方法を使用する必要があります。

より凝ったものにしたい場合は 2 つの 2 次元配列の代わりに 1 つの 3 次元配列を使用できます。

#define MENS_NAMES 0
#define WOMENS_NAMES 1
...
char (*all_names)[2][20] = malloc(number_of_couples * sizeof *all_names);
...
fscanf(input_file, "%s", all_names[i][MENS_NAMES]);
...
free(all_names);
于 2013-01-29T14:02:08.780 に答える