1

数時間取り組んでいる課題がありますが、完全に理解できていないようです。割り当ては、(stdin から) 乱数の名前を取得し、それらを並べ替えてから、アルファベット順に出力することです。この種の並べ替えを具体的に処理するサイトをオンラインで見つけることができず、コードに qsort() を実装しようとしてもうまくいきませんでした。

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


int stringcmp(const void *a, const void *b) 
{ 
    const char **ia = (const char **)a;
    const char **ib = (const char **)b;
    return strcmp(*ia, *ib);
} 

void main(int argc, char *argv[])
{
     char *input[] = {" "};
     char temp[20][20];
     int i = 0;
     int num = 0;
     int place = 0;
     int stringlen = sizeof(temp) / sizeof(char);


          printf("How many names would you like to enter? ");
          scanf("%d", &num);

          while (place < num)
          {
                printf("Please input a name(first only): ");
                scanf("%s", input[place]);
                printf("The name you entered is: ");
                printf("%s\n", input[place]);

                place++;
          }
          //qsort(temp, stringlen, sizeof(char *), stringcmp);      <-- just an idea I was messing with
          qsort(input, stringlen, sizeof(char *), stringcmp);

          printf("Names:\n");

          for(i=0; i<place; i++)
               printf("%s\n", input[i]);



          system("PAUSE");
          return(EXIT_SUCCESS);

}

主な問題は、コードを出力するときに、宣言方法が原因で char *input 変数を使用できないことです。temp[] は表示されますが、ポインターとして宣言されていないため、qsort によってソートされません。何か案は?

4

2 に答える 2

6

入力配列をそのように宣言することはできません。ユーザーが必要とする数がわかっているので、配列を動的に割り当てることができます。

char **input = malloc(num * sizeof(char*));

同様に、文字列を読み込む場合、どこかに移動する必要があります。初期化されていないポインターを単に渡すだけscanfでは問題があります。名前の最大長を定義し、それを読み取るための一時バッファーを用意することをお勧めします。

const size_t MAX_NAME = 50;
char name[MAX_NAME];

...

for( i = 0; i < num; i++ )
{
    printf("Please input a name(first only): ");
    scanf("%s", name);
    input[i] = strdup(name);
}

[これは、ユーザーが 'name' バッファをオーバーフローするのを防ぐものではないことに注意してください。scanf説明のみを目的として使用しました]

に間違った配列の長さを渡しているようですqsort。これを試して:

  qsort(input, num, sizeof(char *), stringcmp);

終了したら、すべての名前と配列のメモリを解放する必要があります。

for( i = 0; i < num; i++ ) free(input[i]);
free(input);

コード全体の ** 宣言について説明していただけますか? stringcmp の関数が広く使用されているアルゴリズムであることは知っていますが、どのように機能するのかわかりません。二重参照解除マーカーにうんざりしています。

ええ、私がそれを使用した場合、私はCに、1文字を取得するには、ポインターを2回逆参照する必要があることを伝えています。ポインターにインデックスを付けると、逆参照になります。num * sizeof(char*)そこで、バイトを含むメモリのブロックを要求して配列を割り当てました。そのポインターを に割り当てたのでchar**、コンパイラーは、値を含むメモリーのチャンクを指していることを認識しchar*ます。

私が要求した場合input[0](これは と同じです*input)、そのメモリの先頭を見て、char*. を要求するとinput[1]、それらのバイトをスキップして、char*. など... 同様に、 a にインデックスを付けると、char*単一の文字が引き出されます。

あなたのstringcmp機能では、次の状況があります。void*ポインターを渡したqsortので、配列に格納されているデータ値のサイズが実際にはわかりません。そのため、配列の長さと単一要素のサイズの両方を渡す必要があります。したがってqsort、任意のサイズの値のこの任意の長さの配列をやみくもにリッピングし、比較のためにデータを格納する必要があるメモリ アドレスを起動します。qsort配列要素が配置されている場所以外は、配列要素について何も知らないため、 を使用するだけvoid*です。

しかし、これらのポインタが 2 つの配列要素のメモリ アドレスになり、配列要素がchar*. したがって、 a のアドレスが必要ですchar*(したがって、ポインターを にキャストしますchar**)。呼び出すときにこれらのポインターを逆参照する必要があります。これはstrcmp()、関数がchar*(つまり、文字列文字を含むメモリを直接指す値) を必要とするためです。そのため、 in を使用*strcmp(*ia, *ib)ます。

于 2012-09-21T02:57:43.080 に答える
2

プログラムを修正する簡単な方法の 1 つはinput、次のようにポインターの配列として宣言することです。

char *input[20];

名前を読み込むときは、次のようtmp[place]に、バッファーに使用し、ポインターを に格納しますinput

scanf("%19s", tmp[place]);
input[place] = tmp[place];

これでソートはinputうまくいくはずです。

これには、最大 20 文字の 20 行に制限されるという制限があります。クラスで学習しmallocた場合は、文字列と文字列配列を動的に割り当てることで修正できるはずです。

于 2012-09-21T02:53:36.207 に答える