C言語関係掲示板

過去ログ

No.1025 構造体を用いた入力&ソート結果

[戻る] [ホームページ]
No.13042

構造体を用いた入力&ソート結果
投稿者---アンナ(2004/03/05 06:26:14)


どなたか教えてください。お願いします。
****************************************************************
ローマ字の名前と生年月日(形式YYYY/MM)を入力するとアルファベット順にソートされた結果の名前、生年月日、年齢が表示される構造体を用いたプログラム

*氏名の長さは最長10文字、入力は最大10名

****************************************************************



No.13043

Re:構造体を用いた入力&ソート結果
投稿者---RiSK(2004/03/05 07:50:29)


まず【掲示板ご利用上の注意】を読みましょう。
また、マルチポストは嫌われます。→プログラミング質問掲示板

>どなたか教えてください。
問題のどの部分が分からないのか教えてください。
どこまでできたのでしょうか?
それが分かればレスをつけてくれる人はたくさんいますよ。


No.13045

Re:構造体を用いた入力&ソート結果
投稿者---アンナ(2004/03/05 15:36:48)


ごめんなさい!!注意を全く読んでませんでした。。
****************************************************************
ローマ字の名前と生年月日(形式YYYY/MM、日は無し)を入力するとアルファベット順にソートされた結果の名前、生年月日、年齢が表示される構造体を用いたプログラム

*氏名の長さは最長10文字、入力は最大10名
****************************************************************

これまでローマ字の名前の入力、ソートまでができました。元の問題は下のプログラムに生年月日の入力を追加し構造体として書き換えるものでしたが構造体の使い方がいまいちわかりません。

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

void main()
{
int i, j, k, ruikei, check, len[2];
char name[10][10], temp[10];

for( i = 0;i < 10;i++ ){ /*最大10人まで入力*/
printf( "%d人目の名前を入力してください\n", i + 1 );
scanf( "%s", &name[i] );
printf("累計件数:%d\n", i + 1 );

if( name[i][0] == '0' ){ /*名前の最初が0なら終了*/
printf( "***登録の完了***\n" );
break;
}
}

ruikei = i;

/* i が ruikei - 1 以下である限り i を 1 増加 */
for( i = 0;i < ruikei - 1;i++ ){
/* j が ruikei - 1 以下である限り jを 1 増加 */
for( j = 0;j < ruikei - 1;j++ ){

/*先に入力されたものの1文字目の方が大きかったとき*/
if( name[j][0] > name[j + 1][0] ){
strcpy( temp, name[j] );
strcpy( name[j], name[j + 1] );
strcpy( name[j + 1], temp );
}

/*入力されたものの1文字目が同じであったとき*/
else if( name[j][0] == name[j + 1][0] ){
check = 1;
k = 1;
len[0] = strlen( name[j] );
len[1] = strlen( name[j + 1] );
/*checkが0でない限り以下の文を繰り返す*/
do {
/*先に入力されたもののk文字目の方が大きかったとき*/
if( name[j][k] > name[j + 1][k] ){
strcpy( temp, name[j] );
strcpy( name[j], name[j + 1] );
strcpy( name[j + 1], temp );
check = 0;
}

k++;

/*先に入力されたものと次のものの文字数のどちらかがkであったとき*/
if( len[0] == k || len[1] == k ){
/*さらに先に入力されたものの方が文字数が長いとき*/
if( len[0] > len[1] ){
strcpy( temp, name[j] );
strcpy( name[j], name[j + 1] );
strcpy( name[j + 1], temp );
}
check = 0;
}
} while( check != 0 );
}
}
}

printf( "登録結果\n" );
for( i = 0;i < ruikei; i++ ){ /*ソートした結果を出力*/
printf( "%s\n", name[i] );
}
}

No.13046

Re:構造体を用いた入力&ソート結果
投稿者---Cマニア(超初心者)(2004/03/05 16:22:43)


>ローマ字の名前と生年月日(形式YYYY/MM、日は無し)を入力するとアルファベット順にソートされた結果の名前、生年月日、年齢が表示される構造体を用いたプログラム

年齢は現在時間を取得してから計算させるのでしょうか?
年齢を算出しているようには見えませんが・・・。どうなんでしょう?


>これまでローマ字の名前の入力、ソートまでができました。元の問題は下のプログラムに生年月日の入力を追加し構造体として書き換えるものでしたが構造体の使い方がいまいちわかりません。

構造体はこのサイトの第15章 構造体 のところにわかりやすく載っていますよ。
あと、ソート処理の部分ですが、strcmp関数を使えばもっと簡単にできると思います。


No.13048

Re:構造体を用いた入力&ソート結果
投稿者---RiSK(2004/03/05 16:45:57)


ごめんなさい!!注意を全く読んでませんでした。。
うーん…。ちょっと読んだようですが、まだ足りないですねぇ。  
続いて、問題について質問ですが
生年月を入力(日は無し)なのに、どうやって生年月日の日を出力するのでしょう?
年齢はどうやって計算するのですか?
「氏名の長さは最長10文字」との事ですが、これは '\0' を含めて10文字で間違いは無いですね。
以上、よろしくです。
元の問題は下のプログラムに生年月日の入力を追加し構造体として書き換えるものでしたが構造体の使い方がいまいちわかりません。
#define NAME_MAX 10
#define PEOPLE_MAX 10
#define BUF_SIZE 256

typedef struct TAG_PERSON {
  char name[NAME_MAX]; /* '\0' を含めないで10文字ならば +1 が必要 */
  unsigned int birth_year;
  unsigned int birth_month;
} PERSON;

PERSON people[PEOPLE_MAX]; /* people 構造体が10個あるイメージ */
今まで name[i] となっていた部分は people[i].name に変更。
誕生年は people[i].birth_year
誕生月は people[i].birth_month

これぐらい分かれば結構進むと思いますが、がんばってください。 経過・結果報告よろしくです。


No.13050

Re:構造体を用いた入力&ソート結果
投稿者---アンナ(2004/03/06 06:32:28)


丁寧な解説ありがとうございました。。
現在こういった状態なのですが、入力した誕生年・月の出力がうまくいきません。どこがダメなんでしょう!?
また、Cマニア(超初心者)さんに指摘されたstrcmp関数への変更はこんな感じでよかったですか?



/*
    SampleSource
#include <stdio.h>
#include <string.h>

#define NAME_MAX 10
#define PEOPLE_MAX 10
#define BUF_SIZE 256


typedef struct TAG_PERSON {
    char name[NAME_MAX];
    unsigned int birth_year;
    unsigned int birth_month;
} PERSON;

void main()
{
    PERSON people[PEOPLE_MAX];
    
    int i, j, k, ruikei, check, len[2];
    char temp[10];

    for( i = 0;i < 10;i++ ){
        printf( "%d人目の名前を入力してください\n", i + 1 );
        scanf( "%s", &people[i].name );
        scanf( "%s", &people[i].birth_year );
        scanf( "%s", &people[i].birth_month );
        printf("累計件数:%d\n", i + 1 );
        
/*    if( people[i].name == '0' ){
            printf( "***登録の完了***\n" );
            break;
        }*/
    }

    ruikei = i;

    for( i = 0;i < ruikei - 1;i++ ){
        for( j = 0;j < ruikei - 1;j++ ){
            if( (strcmp( people[j].name, people[j + 1].name)) > 0 ){    
                            strcpy( temp, people[j].name );
                            strcpy( people[j].name, people[j + 1].name );
                            strcpy( people[j + 1].name, temp );
            }

            else if( (strcmp( people[j].name, people[j + 1].name)) > 0 ){
                check = 1;
                k = 1;
                len[0] = strlen( people[j].name );
                len[1] = strlen( people[j + 1].name );
                do {
                    if( (strcmp( people[j].name, people[j + 1].name)) > 0 ){
                            strcpy( temp, people[j].name );
                            strcpy( people[j].name, people[j + 1].name );
                            strcpy( people[j + 1].name, temp );
                        check = 0;
                    }
                    
                    k++;

                    if( len[0] == k || len[1] == k ){
                        if( len[0] > len[1] ){
                            strcpy( temp, people[j].name );
                            strcpy( people[j].name, people[j + 1].name );
                            strcpy( people[j + 1].name, temp );
                        }
                        check = 0;
                    }
                } while( check != 0 );
            }
        }
    }

    printf( "\n***登録結果***\n" );
    for( i = 0;i < ruikei; i++ ){
        printf( "%s\n", people[i].name );
        printf( "誕生年:%s\n", people[i].birth_year );
        printf( "誕生月:%s\n", people[i].birth_month );
    }
}


No.13053

Re:構造体を用いた入力&ソート結果
投稿者---YuO(2004/03/06 14:58:08)


>現在こういった状態なのですが、入力した誕生年・月の出力がうまくいきません。どこがダメなんでしょう!?

誕生年と誕生月はunsigned int型としているのですから,
scanfとprintfでは%uを使う必要があります。

さらに,struct TAG_PERSONのnameメンバはcharの配列ですから,
単項&演算子を適用してはならず,
scanf("%s" people[i].name);

とする必要があります。


>また、Cマニア(超初心者)さんに指摘されたstrcmp関数への変更はこんな感じでよかったですか?

ソート処理では,誕生年や誕生月も入れ替える必要があります。
さらに,else節は何がしたいのかわかりません。
#多分不要。

ちなみに,構造体は代入ができるので,strcpyを使う必要はありません。


No.13055

Re:構造体を用いた入力&ソート結果
投稿者---RiSK(2004/03/06 15:02:37)


ごめんなさい。入れ違いです。
リロードしたのですが…

>ちなみに,構造体は代入ができるので,strcpyを使う必要はありません。
仰るとおりでした str*() にやたら目がいってしまったので…

No.13054

Re:構造体を用いた入力&ソート結果
投稿者---RiSK(2004/03/06 14:59:07)


Give-and-take ですので、無視しないで欲しいです…。 もう一度、質問するのでよろしくです。
  • 生年月だけを入力(日は無し)で、どうやって生年月日の日を出力するのでしょうか?
  • 年齢はどうやって計算するのでしょうか?
    # Cマニア(超初心者)さんも聞いておられます。
  • 氏名の長さは'\0'を含めて最長10文字と見ます。(ソースから判断)

では、アンナさんの質問に答えます。
現在こういった状態なのですが、入力した誕生年・月の出力がうまくいきません。どこがダメなんでしょう!?
まず、birth_year, birth_month の型を確認しましょう。
typedef struct TAG_PERSON {
    char name[NAME_MAX];
    unsigned int birth_year;
    unsigned int birth_month;
} PERSON;
続いて scanf の書式指定文字列を確認しましょう。 unsigned int 型の書式は何でしたか?
ん? ないですね…。
ということで管理人様、勝手に追加いたします。(^^
【scanf の書式指定文字列】
型指定文字 意味 使われるデータ型
%u 符号無し10進数で入力する unsigned int型

今までの資料とアンナさんのソースを比べてください。
    scanf( "%s", &people[i].birth_year );
    scanf( "%s", &people[i].birth_month );
printf に関しても、同様に調べてみましょう。
また、Cマニア(超初心者)さんに指摘されたstrcmp関数への変更はこんな感じでよかったですか?
strcmp は文字列全体を比較します。
ですから
    else if( (strcmp( people[j].name, people[j + 1].name)) > 0 ){
このブロックはすべて必要ありません。便利でしょ。

何か調べるときにも、ここのサイトはかなり使えますよ。(掲示板は二次的なものと私は思います。)
質問の方よろしくです。


No.13058

Re:構造体を用いた入力&ソート結果
投稿者---アンナ(2004/03/06 16:25:21)


RiSKさんのおっしゃるとおりです。。
問題にはそう書いてあったので、そのまま書いたのですが不可能ですね!恐らく入力が2000/3と入力なら4歳と判定していいのではないかと思います。

年齢の計算は、現在の年月をコマンドラインパラメータで指定(形式YYYY/MM)ですが、time関数などを使用すればいいのでしょうか?

氏名の長さは'\0'を含まず、最長10文字です。11文字以上入力されたら、それ以降を無視します。

解答遅れて申し訳無いです・・・。

No.13063

Re:構造体を用いた入力&ソート結果
投稿者---Cマニア(超初心者)(2004/03/08 10:28:34)


>ローマ字の名前と生年月日(形式YYYY/MM)を入力するとアルファベット
順にソートされた結果の名前、生年月日、年齢が表示される構造体を用い
たプログラム

>*氏名の長さは最長10文字、入力は最大10名

アンナさんには申し訳ないですが、私も問題を解いてみました。
一初心者が書く例として参考にして下さい。
C歴が浅いので、皆さんの意見を頂けるとありがたいです。
 *年齢計算と入力のエラーチェックはしていません。
#include<stdio.h>
#include<string.h>
#include<time.h>

#define MAX 10
#define NAME_SIZE 11
#define BIRTH_SIZE 11

/*--------個人データの構造体--------*/
struct PERSON_DATA{

    char name[NAME_SIZE];
    char birth[BIRTH_SIZE];
};

/*------------関数プロトタイプ宣言-----------------*/
void InputData(struct PERSON_DATA *);         /*  名前と生年月日を入力      */
void OutputData(struct PERSON_DATA *);      /*  名前と生年月日を出力      */
void PersonDataSort(struct PERSON_DATA *);    /*  名前と生年月日を並び替え  */

/*--------------------------------------------------------*/
/*                     メイン関数                         */
/*--------------------------------------------------------*/
int main(void){

    struct PERSON_DATA per_data[MAX];

    /*  名前と生年月日を入力   */
    InputData(per_data);

    /*  並び替え前のデータ出力  */
    printf("-----------並び替え前------------\n");
    OutputData(per_data);

    /*  名前と生年月日を昇順に並べる  */
    PersonDataSort(per_data);

    /*  並び替え後のデータ出力  */
    printf("-----------並び替え後------------\n");
    OutputData(per_data);

    return 0;
}

/*---------------------------------------------------------*/
/*                  名前と生年月日を入力                   */
/*---------------------------------------------------------*/
void InputData(struct PERSON_DATA *per_data){

    int i;
    char yes_no[3];

    for( i = 0 ;  i < MAX ; i++ , per_data++){
        /*  名前を入力  */
        printf("名前を入力してください。 -> ");
        fgets( per_data->name, NAME_SIZE, stdin);
        per_data->name[strlen(per_data->name)-1] = '\0';    /*  改行を捨てる  */

        /*  生年月日を入力  */
        printf("生年月日を入力してください。(形式YYYY/MM) -> ");
        fgets( per_data->birth, BIRTH_SIZE, stdin);
        per_data->birth[strlen(per_data->birth)-1] = '\0';  /*  改行を捨てる  */
    }
}

/*--------------------------------------------------------*/
/*               名前と生年月日を出力                     */
/*--------------------------------------------------------*/
void OutputData(struct PERSON_DATA *per_data){

    int i;

    for( i = 0 ; i < MAX ; i++ , per_data++){
        printf("%-10s : %-10s\n", per_data->name, per_data->birth);
    }
}

/*--------------------------------------------------------*/
/*               個人データを並び替える                   */
/*--------------------------------------------------------*/
void PersonDataSort(struct PERSON_DATA *per_data){

    int i, j;
    struct PERSON_DATA swapbox;

    /*  バブルソート  */
    for( i = 0 ; i < MAX ; i++ ){
        for( j = i+1 ; j < MAX ; j++){
            if( strcmp(per_data[i].name, per_data[j].name) > 0){
                /*  名前と生年月日を入れ替える  */
                 swapbox = per_data[i];
                 per_data[i] = per_data[j];
                 per_data[j] = swapbox;
            }
        }
    }
}



No.13065

Re:構造体を用いた入力&ソート結果
投稿者---Cマニア(超初心者)(2004/03/08 11:00:18)


すみません、fflushを忘れてました。
/*---------------------------------------------------------*/
/*                  名前と生年月日を入力                   */
/*---------------------------------------------------------*/
void InputData(struct PERSON_DATA *per_data){

    int i;
    char yes_no[3];

    for( i = 0 ;  i < MAX ; i++ , per_data++){
        /*  名前を入力  */
        printf("名前を入力してください。 -> ");
        fgets( per_data->name, NAME_SIZE, stdin);
        per_data->name[strlen(per_data->name)-1] = '\0';    /*  改行を捨てる  */
        fflush(stdin);

        /*  生年月日を入力  */
        printf("生年月日を入力してください。(形式YYYY/MM) -> ");
        fgets( per_data->birth, BIRTH_SIZE, stdin);
        per_data->birth[strlen(per_data->birth)-1] = '\0';  /*  改行を捨てる  */
        fflush(stdin);
    }
}



No.13070

Re:構造体を用いた入力&ソート結果
投稿者---YuO(2004/03/08 13:33:16)


        fgets( per_data->name, NAME_SIZE, stdin);
        per_data->name[strlen(per_data->name)-1] = '\0';    /*  改行を捨てる  */


fgetsで取得した文字列の最後の文字が'\n'である保証はありません。
入力文字数が多いと末尾にあるのは'\n'ではなく何らかの削除してはいけない文字です。
例えば,名前のところに「武者小路実篤」と入力された場合,
大抵の処理系で12バイト以上必要になるので,
per_data->nameには「武者小路実」までが入ると思います。

そうすると,勝手にper_data->name[9] = '\0';なんてことをすると,"実"の字が壊れます。

改行を捨てる処理はちゃんと判断を行って,
size_t length = strlen(per_data->name);
if (pre_data->name[length - 1] == '\n') pre_data->name[length - 1] = '\0';

のようにする必要があります。


すみません、fflushを忘れてました。
        fflush(stdin);


何がしたいのですか?

fflushは出力ストリームか,更新ストリームで直前に入力を行っていない場合にのみ意味をもちます。
それ以外の場合は未定義とされており,何が起こってもおかしくないです。
#当然,fflush(stdin)は未定義動作。


ついでに,年と月は整数型で保持する方が処理しやすいかと。
#年齢を計算するため。

No.13071

Re:構造体を用いた入力&ソート結果
投稿者---Cマニア(超初心者)(2004/03/08 14:23:15)


>fgetsで取得した文字列の最後の文字が'\n'である保証はありません。
>入力文字数が多いと末尾にあるのは'\n'ではなく何らかの削除してはいけない文字です。
>例えば,名前のところに「武者小路実篤」と入力された場合,
>大抵の処理系で12バイト以上必要になるので,
>per_data->nameには「武者小路実」までが入ると思います。
>
>そうすると,勝手にper_data->name[9] = '\0';なんてことをすると,"実"の字が壊れます。
>
>改行を捨てる処理はちゃんと判断を行って,
><pre>size_t length = strlen(per_data->name);
if (pre_data->name[length - 1] == '\n') pre_data->name[length - 1] = '\0';</pre>
>のようにする必要があります。

そういうケースを考えていませんでした。ありがとうございます。


>fflushは出力ストリームか,更新ストリームで直前に入力を行っていない場合にのみ意味をもちます。
>それ以外の場合は未定義とされており,何が起こってもおかしくないです。
>#当然,fflush(stdin)は未定義動作。

ん〜すみません、いまいち理解できません・・。
とりあえず、fflushについて全然理解してないみたいです。
もっと勉強したいと思います、YuOさんありがとうございましたm(_ _)m