宿題でつまずいてます

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
へにっくす

Re: 宿題でつまずいてます

#61

投稿記事 by へにっくす » 13年前

れお さんが書きました:でもまだ動作を停止するんですね・・・^^;難しい・・・
れお さんが書きました:後半:void Numberをintにして return n; しました
このように変えましたか?

コード:

int Number(FILE* fpi)
{
	int n;
	fscanf(fpi, "%d", &n);
	return n;
}
// ・・・省略
// メイン関数のNumber呼び出しを以下に変える
// n = Number(fpi);
上記のように変えたら、落ちることなくいきますが。
並べ替えがcreditだけなので、結果としてはおかしいですけどね。
その部分は、
れお さんが書きました:

コード:

            if (func(&array[i],&array[j])==1)
            {
                N.credit = array[i].credit;
                array[i].credit = array[j].credit;
                array[j].credit = N.credit;
            }
からも自明かと思います。

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#62

投稿記事 by れお » 13年前

>beatleさん
ん~><
使ってるのがeclipsなんですよね・・・
前やろうとしたんですが設定とかよくわからずやめてしまって。

>へにっくすさん
そういうふうにはしてませんでした・・・><
そうしないとうまくいかないんですね・・・
ポインタをつかわないと値をかえれないみたいなそういう感じなんですかね。。。

たしかにそれをgpaなどの分もつくればいけますよね?
でも .creditとかにしなくてもいけるような話がでてるのでちょっとまってみますね^^

ありがとうございました!!

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: 宿題でつまずいてます

#63

投稿記事 by beatle » 13年前

Eclipse + CDTでしょうか。でしたら、図のようにやればできるかもです。
eclipse_reo.png

へにっくす

Re: 宿題でつまずいてます

#64

投稿記事 by へにっくす » 13年前

れお さんが書きました:>へにっくすさん
そういうふうにはしてませんでした・・・><
そうしないとうまくいかないんですね・・・
ポインタをつかわないと値をかえれないみたいなそういう感じなんですかね。。。
どのように変えたんだか。すげー気になりますが、、
関数の引数には「値渡し」と「参照渡し」があります。
Number関数を参照渡しにするなら以下のような感じになりますが、普通しないです。

コード:

void Number(FILE* fpi, int *n)
{
    fscanf(fpi, "%d", n); // ←★ここ注意!ポインタ変数になるので & はいらない
}
// ・・・省略
// メイン関数のNumber呼び出しを以下に変える
// Number(fpi, &n); // ★←ここも注意!参照渡しなので & がいる
れお さんが書きました:たしかにそれをgpaなどの分もつくればいけますよね?
でも .creditとかにしなくてもいけるような話がでてるのでちょっとまってみますね^^
構造体コピーで検索かけると幸せになれるかもしれません。
構造体の変数がポインタ型を含む場合は使えませんけどね。

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#65

投稿記事 by れお » 13年前

学校にいれてもらってCDTかはわかりませんが、
起動に問題が発生しました
セッションの作成エラー

とでてなにもできません><
実行はできるのにデバッグができないのははじめてです・・・

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#66

投稿記事 by れお » 13年前

へにっくす さんが書きました:どのように変えたんだか。すげー気になりますが、、
関数の引数には「値渡し」と「参照渡し」があります。
Number関数を参照渡しにするなら以下のような感じになりますが、普通しないです。

コード:

void Number(FILE* fpi, int *n)
{
    fscanf(fpi, "%d", n); // ←★ここ注意!ポインタ変数になるので & はいらない
}
// ・・・省略
// メイン関数のNumber呼び出しを以下に変える
// Number(fpi, &n); // ★←ここも注意!参照渡しなので & がいる
れお さんが書きました:たしかにそれをgpaなどの分もつくればいけますよね?
でも .creditとかにしなくてもいけるような話がでてるのでちょっとまってみますね^^
構造体コピーで検索かけると幸せになれるかもしれません。
構造体の変数がポインタ型を含む場合は使えませんけどね。
&なしでわたしてました・・・
ちょっとだけ調べましたがいまのところまだ幸せにはなってませんww
もうちょっと調べますね^^

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 宿題でつまずいてます

#67

投稿記事 by softya(ソフト屋) » 13年前

printfデバッグ法を伝授しておきます。

「簡単RPG講座 番外編。 デバッグ入門 • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/blog.php?u=114&b=982&c=2
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#68

投稿記事 by れお » 13年前

今おもったんですが、構造体のコピーとかしなくてももうこれでいけてませんか?

コード:

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

typedef struct school_record
{
	float gpa;
	int credit;
	char name[200];
} SRec;

void simple_sort(SRec* array, int n, int (*func)(const void*,const void*))
{
	SRec N;
	int i = 0, j = 0;
	for (i = 0; i < n; i++)
	{
		for (j = i + 1; j < n; j++)
		{
			if (func(&array[i],&array[j])==1)
			{
				N = array[i];
				array[i] = array[j];
				array[j] = N;
			}
		}
	}
	return;
}

int compare_float(const void * a, const void * b)
{
	SRec* tmp1 = (SRec*) a;
	SRec* tmp2 = (SRec*) b;
	if (tmp1->gpa == tmp2->gpa)
		return 0;
	else if (tmp1->gpa > tmp2->gpa)
		return 1;
	else
		return -1;
}

int compare_int(const void* a, const void* b)//gpa
{ /* 引数はvoid*型と規定されているのでSRec型にcastする */
	SRec* tmp1 = (SRec*) a;
	SRec* tmp2 = (SRec*) b;
	if (tmp1->credit == tmp2->credit)
		return 0;
	else if (tmp1->credit > tmp2->credit)
		return 1;
	else
		return -1;
}

int compare_char(const void * a, const void * b)
{
	SRec* tmp1 = (SRec*) a;
	SRec* tmp2 = (SRec*) b;
	if (strcmp(tmp1->name, tmp2->name) == 0)
		return 0;
	else if (strcmp(tmp1->name, tmp2->name) == 1)
		return 1;
	else
		return -1;
}

int Number(FILE* fpi)
{
	int n;
	fscanf(fpi, "%d", &n);
	return n;
}

void Input(SRec* array,int n,FILE* fpi)
 {
     int i=0;
     while (!feof(fpi))
     {
         fscanf(fpi, "%f%d%s", &array[i].gpa, &array[i].credit, array[i].name);
         i++;
     }
 }
 void Output(SRec* array,int n,FILE* fpo)
 {
     int i;
     fprintf(fpo,"%d\n",n);
     for(i=0;i<n;i++)
         {
             fprintf(fpo,"%1.1f %d %s\n",array[i].gpa,array[i].credit,array[i].name);
         }

 }


int main(int argc, char *argv[])
{
	FILE *fpi, *fpo;
	SRec *array;//構造体をようい
	int (*func)(const void*,const void*);
	int n;
	if (argc != 4)//コマンドライン数がたりてるか?
	{
		fprintf(stderr, "Illegal number of argument.\n");
		return (-1);
	}
	if ((fpi = fopen(argv[2], "r")) == NULL)
	{
		fprintf(stderr, "Can't open input file <%s>.\n", argv[2]);
		return (-1);
	}
	if ((fpo = fopen(argv[3], "w")) == NULL)
	{
		fprintf(stderr, "Can't open output file <%s>.\n", argv[3]);
		return (-1);
	}

	n=Number(fpi);
	array = (SRec *) malloc(sizeof(SRec) * n);//並べ替えで使う SRec型
	if (array == NULL)
	{
		printf("error");
		return (-1);
	}

	Input(array,n,fpi);


	if (strcmp(argv[1], "gpa") == 0)
		func=compare_float;//&はどちらでもいい
	else if (strcmp(argv[1], "credit") == 0)
		func=compare_int;
	else if (strcmp(argv[1], "name") == 0)
		func=compare_char;

	simple_sort(array, n, func);

	Output(array,n,fpo);
	fclose(fpi);

	fclose(fpo);

	free(array);
	return 0;
}
構造体の中身全部わたして、比較関数でgpa credit nameを区別するのでもうこれでいいですよね?
構造体のコピーはstrcpyでコピーできるようですが、どこで利用するのかわかりません・・・

へにっくす

Re: 宿題でつまずいてます

#69

投稿記事 by へにっくす » 13年前

れお さんが書きました:構造体の中身全部わたして、比較関数でgpa credit nameを区別するのでもうこれでいいですよね?
構造体のコピーはstrcpyでコピーできるようですが、どこで利用するのかわかりません・・・
もう出来てるじゃないですか 笑

コード:

            if (func(&array[i],&array[j])==1)
            {
                N = array[i];
                array[i] = array[j];
                array[j] = N;
            }
上記の、N=array;array = array[j];array[j] = N;の部分です。
次のように置き換えることも可能です。

コード:

            if (func(&array[i],&array[j])==1)
            {
                memcpy(&N, &array[i], sizeof(N));
                memcpy(&array[i], &array[j], sizeof(array[i]));
                memcpy(&array[j], &N, sizeof(N);
            }
とゆーわけで、OKです。

へにっくす

Re: 宿題でつまずいてます

#70

投稿記事 by へにっくす » 13年前

へにっくす さんが書きました:次のように置き換えることも可能です。

コード:

            if (func(&array[i],&array[j])==1)
            {
                memcpy(&N, &array[i], sizeof(N));
                memcpy(&array[i], &array[j], sizeof(array[i]));
                memcpy(&array[j], &N, sizeof(N);
            }
とゆーわけで、OKです。
修正。。かっこがたりなかった。。

コード:

            if (func(&array[i],&array[j])==1)
            {
                memcpy(&N, &array[i], sizeof(N));
                memcpy(&array[i], &array[j], sizeof(array[i]));
                memcpy(&array[j], &N, sizeof(N));
            }

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#71

投稿記事 by れお » 13年前

なるほど!strcpyだとヌル文字も含んでしまうからmemcpyのほうがいいわけですね^^

アドバイス・回答をくださったみなさまありがとうございました。
今後もどうかよろしくお願いしますm(__)m

へにっくす

Re: 宿題でつまずいてます

#72

投稿記事 by へにっくす » 13年前

れお さんが書きました:なるほど!strcpyだとヌル文字も含んでしまうからmemcpyのほうがいいわけですね^^
えっと、、
strcpyはあくまでも文字列のコピーです。
構造体のコピーでは使われません。
memcpyは指定されたサイズ分、コピーすると言う関数なので、構造体のコピーに使えるというわけです。
ここ勘違いしないでね。
strcpyで構造体のコピーはできません。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 宿題でつまずいてます

#73

投稿記事 by softya(ソフト屋) » 13年前

基本、構造体はmemcpyなど使わず構造体代入を使って下さい。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#74

投稿記事 by れお » 13年前

strcpyじゃ無理なんですかwわかりましたm(__)m


memcpyの役立ちどころがいまいちまだわかりませんね・・・

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 宿題でつまずいてます

#75

投稿記事 by softya(ソフト屋) » 13年前

れお さんが書きました:strcpyじゃ無理なんですかwわかりましたm(__)m


memcpyの役立ちどころがいまいちまだわかりませんね・・・
mallocしたメモリ上でバイナリデータを動かすときとか役に立つ場面はあります。
教科書や課題の範囲だとまず無いかなと思いますが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#76

投稿記事 by れお » 13年前

バイナリデータがわからないので理解できませんがまだ関係なさそうですねw

ありがとうございました^^

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: 宿題でつまずいてます

#77

投稿記事 by beatle » 13年前

れお さんが書きました:バイナリデータがわからないので理解できませんがまだ関係なさそうですねw

ありがとうございました^^
strcpyとmemcpyの違いは、簡単にいえばデータの途中に0x00がある場合に、strcpyはコピーが止まり、memcpyは止まらずに指定したバイト数だけ必ずコピーします。

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#78

投稿記事 by れお » 13年前

0x00はヌルですかね?

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: 宿題でつまずいてます

#79

投稿記事 by beatle » 13年前

はい。0x00はヌル文字のことです。
C言語では御存知の通り、文字列はヌル文字で終端することになっていますから、文字列用のコピー関数strcpyはヌル文字までしかコピーしません。
しかしバイナリデータというのは0x00を通常のデータとして含む可能性がありますから、strcpyではデータ全体をコピーできません。
そこで、memcpy関数を使って指定したバイト数だけコピーするようにします。

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#80

投稿記事 by れお » 13年前

なるほど!!
わかりました^^
わざわざありがとうございますm(__)m

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#81

投稿記事 by れお » 13年前

↑までは成績データ件数をファイルからよみとってやってたんですが、今回はファイルの中身を
3.5 27 jiro
2.7 24 taro
3.7 30 saburo
のようにデータだけにして、成績データ件数をよみとらずにやりたいと思います。
つまり、成績データの件数に上限を設けることなく、また、扱うデータ件数の増減に柔軟に対応できるように一方向の連結リストを用いて成績データを記憶するように↑でやったコードをかきかえたいです。
コマンドライン引数は前回とかわらず gpa input.txt output.txtです。

この課題の条件は
a.今回はソート処理を省略するものとする。したがって、入力したデータをそのまま出力ファイルに書き込むようにプログラムを記述せよ。
c.入力ファイルには、データ件数は記載しないものとする。
d.入力処理関数では、入力ファイルに記録されていたデータ順を保って線形リストを作成すること。

というもので自分でいろいろしらべてやろうとしたのですが、いまいち連結リストとmallocの関係というかなんか理解できません。一応連結リストは軽く勉強したのでなんとなくはわかってます。↓は一応つくろうとしたコードの途中なんですが、イメージできずどうしていいかわからず変なところでつまってます(Input関数のなかみを変えればいいとおもうのですが・・・現段階ではまだめちゃくちゃです)
順番としては
1.1件ぶんのデータを入力
2.ノードの領域確保(malloc)  (1と2は逆でもいい)
3.リスト追加(挿入)
としたいのですが。
mallocってなんで必要なんですかね?どのサイトみてもあるんですが。自分のやつでは今回は省略されてるソートをするときに便利なのでやってるのだと思いますがソートしないときでもやってますよね?p->next->next->next->gpaとかやるのが嫌だからmallocの配列にいれてるだけですか?

コード:










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

typedef struct school_record SRec;
struct school_record {
float gpa;
int credit;
char name[200];
SRec *next;
};
SRec head;//リストの先頭要素

/*void simple_sort(SRec* array, int n, int (*func)(const void*,const void*))
{
    SRec N;
    int i = 0, j = 0;
    for (i = 0; i < n; i++)
    {
        for (j = i + 1; j < n; j++)
        {
            if (func(&array[i],&array[j])==1)
            {
                N = array[i];
                array[i] = array[j];
                array[j] = N;
            }
        }
    }
    return;
}

int compare_float(const void * a, const void * b)
{
    SRec* tmp1 = (SRec*) a;
    SRec* tmp2 = (SRec*) b;
    if (tmp1->gpa == tmp2->gpa)
        return 0;
    else if (tmp1->gpa > tmp2->gpa)
        return 1;
    else
        return -1;
}

int compare_int(const void* a, const void* b)//gpa
{
    SRec* tmp1 = (SRec*) a;
    SRec* tmp2 = (SRec*) b;
    if (tmp1->credit == tmp2->credit)
        return 0;
    else if (tmp1->credit > tmp2->credit)
        return 1;
    else
        return -1;
}

int compare_char(const void * a, const void * b)
{
    SRec* tmp1 = (SRec*) a;
    SRec* tmp2 = (SRec*) b;
    if (strcmp(tmp1->name, tmp2->name) == 0)
        return 0;
    else if (strcmp(tmp1->name, tmp2->name) == 1)
        return 1;
    else
        return -1;
}*/


SRec* Input(FILE* fpi)
{
    SRec* array,* save;
    array = (SRec *) malloc(sizeof(SRec));//並べ替えで使う SRec型
    if (array == NULL)
        {
            printf("メモリ不足");
            return NULL;
        }
    SRec *p;
    SRec *tail;
    head.next=NULL;
    p=head.next;
    tail=&head;
    int i=0;
    while(!feof(fpi))//i+1がデータ件数
     {
    	tail=p;
         fscanf(fpi, "%f%d%s", &array[i].gpa, &array[i].credit, array[i].name);
         memcpy(save[i],array,sizeof(SRec));
     }
     p->next = NULL;
     tail->next = p;
     tail = p;
     return save;
}
 void Output(SRec* array,int n,FILE* fpo)
 {
     int i;
     fprintf(fpo,"%d\n",n);
     for(i=0;i<n;i++)
         {
             fprintf(fpo,"%1.1f %d %s\n",array[i].gpa,array[i].credit,array[i].name);
         }

 }


int main(int argc, char *argv[])
{
    SRec* array;
    FILE *fpi, *fpo;
    int (*func)(const void*,const void*);

    if (argc != 4)//コマンドライン数がたりてるか?
    {
        fprintf(stderr, "Illegal number of argument.\n");
        return (-1);
    }
    if ((fpi = fopen(argv[2], "r")) == NULL)
    {
        fprintf(stderr, "Can't open input file <%s>.\n", argv[2]);
        return (-1);
    }
    if ((fpo = fopen(argv[3], "w")) == NULL)
    {
        fprintf(stderr, "Can't open output file <%s>.\n", argv[3]);
        return (-1);
    }



    array=Input(fpi);

/*
    if (strcmp(argv[1], "gpa") == 0)
        func=compare_float;//&はどちらでもいい
    else if (strcmp(argv[1], "credit") == 0)
        func=compare_int;
    else if (strcmp(argv[1], "name") == 0)
        func=compare_char;*/

    simple_sort(array, n, func);

    Output(array,n,fpo);
    fclose(fpi);

    fclose(fpo);

    free(array);
    return 0;
}



かずま

Re: 宿題でつまずいてます

#82

投稿記事 by かずま » 13年前

れお さんが書きました:↓は一応つくろうとしたコードの途中なんですが、イメージできずどうしていいかわからず変なところでつまってます(Input関数のなかみを変えればいいとおもうのですが・・・現段階ではまだめちゃくちゃです)
先頭に空行が 9行もあるのはどういうことか理解に苦しみます。説明してください。

次に示すプログラムは、そのままでは解答にならないように、特殊なことをやっていますが、
一応は思ったように動くはずです。参考にして自分のコードを書いてみてください。
あるいは、真面目に考えた質問ならいくらでも受け付けます。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
typedef struct school_record SRec;
struct school_record {
    float gpa;
    int credit;
    char *name;
    SRec *next;
};

int comp_gpa(const void *a, const void *b)
{
    const SRec *s1 = (const SRec *)a;
    const SRec *s2 = (const SRec *)b;
    return s1->gpa < s2->gpa ? -1 : s1->gpa > s2->gpa;
}

int comp_credit(const void *a, const void *b)
{
    const SRec *s1 = (const SRec *)a;
    const SRec *s2 = (const SRec *)b;
    return s1->credit - s2->credit;
}

int comp_name(const void *a, const void *b)
{
    const SRec *s1 = (const SRec *)a;
    const SRec *s2 = (const SRec *)b;
    return strcmp(s1->name, s2->name);
}

void InputAndSort(SRec *sp, int comp(const void *, const void *), FILE *fp)
{
    float gpa;  int credit;  char name[200];

    while (fscanf(fp, "%f%d%199s", &gpa, &credit, name) == 3) {
        SRec *np = malloc(sizeof(SRec));
        if (np == NULL) fprintf(stderr, "out of memory\n"), exit(1);
        np->gpa = gpa,  np->credit = credit,  np->name = strdup(name);
        for ( ; sp->next && comp(sp->next, np) <= 0; sp = sp->next) ;
        np->next = sp->next;
        sp->next = np;
    }
}

void Output(SRec *sp, FILE *fp)
{
    while (sp = sp->next)
        fprintf(fp, "%5.1f %3d %s\n", sp->gpa, sp->credit, sp->name);
}

void Free(SRec *sp)
{
    SRec *next;
    for (sp = sp->next; sp; sp = next) {
        next = sp->next;
        free(sp->name);
        free(sp);
    }
}

int main(int argc, char *argv[])
{
    FILE *fp;
    int (*comp)(const void *, const void *);
    SRec head = { 0 };

    if (argc != 4) { fprintf(stderr, "usage: %s key infile outfile\n", argv[0]); return 1; }
    if (strcmp(argv[1], "gpa") == 0)
        comp = comp_gpa;
    else if (strcmp(argv[1], "credit") == 0)
        comp = comp_credit;
    else if (strcmp(argv[1], "name") == 0)
        comp = comp_name;
    else { fprintf(stderr, "key must be 'gpa', 'credit' or 'name'\n"); return 1; }

    fp = fopen(argv[2], "r");
    if (fp == NULL) { fprintf(stderr, "can't open %s\n", argv[2]); return 1; }
    InputAndSort(&head, comp, fp);
    fclose(fp);
    fp = fopen(argv[3], "w");
    if (fp == NULL) { fprintf(stderr, "can't create %s\n", argv[3]); return 1; }
    Output(&head, fp);
    fclose(fp);
    Free(&head);
    return 0;
}

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#83

投稿記事 by れお » 13年前

ちょっと連結リストとmallocの関係?がいまいちつかめておらずどうしていいのかわかりませんでした・・・
明日か明後日にしかやる時間ないのでまたそのとき考えますが、示してくれたコードをみるに、さきにノードにファイルからよみとって、それをmallocの配列にいれるようにすればいいんですね^^

またすぐつまずくとは思いますが考えてつくってコードはるのでその時また指摘くれたらうれしいです><

かずま

Re: 宿題でつまずいてます

#84

投稿記事 by かずま » 13年前

れお さんが書きました:示してくれたコードをみるに、さきにノードにファイルからよみとって、それをmallocの配列にいれるようにすればいいんですね^^
malloc の配列なんてどこにあるんですか?

参考となるプログラムを提示しても真面目には読んでもらえないようですね。
実は、そのプログラムにはバグがあって、

3.5 27 jiro
2.7 24 taro
3.7 30 saburo

というデータに関しては偶然思った通りの結果が出るのですが、

3.5 27 jiro
2.7 24 taro
3.7 30 saburo
2.3 20 shiro

だと、だめです。
どこを直せばよいのか考えてもらえそうもないので、修正版を挙げておきます。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
typedef struct school_record SRec;
struct school_record {
    float gpa;
    int credit;
    char *name;
    SRec *next;
};
 
int comp_gpa(const void *a, const void *b)
{
    const SRec *s1 = (const SRec *)a;
    const SRec *s2 = (const SRec *)b;
    return s1->gpa < s2->gpa ? -1 : s1->gpa > s2->gpa;
}
 
int comp_credit(const void *a, const void *b)
{
    const SRec *s1 = (const SRec *)a;
    const SRec *s2 = (const SRec *)b;
    return s1->credit - s2->credit;
}
 
int comp_name(const void *a, const void *b)
{
    const SRec *s1 = (const SRec *)a;
    const SRec *s2 = (const SRec *)b;
    return strcmp(s1->name, s2->name);
}
 
void InputAndSort(SRec *sp, int comp(const void *, const void *), FILE *fp)
{
    float gpa;  int credit;  char name[200];
 
    while (fscanf(fp, "%f%d%199s", &gpa, &credit, name) == 3) {
        SRec *p, *np = malloc(sizeof(SRec));
        if (np == NULL) fprintf(stderr, "out of memory\n"), exit(1);
        np->gpa = gpa,  np->credit = credit,  np->name = strdup(name);
        for (p = sp ; p->next && comp(p->next, np) <= 0; p = p->next) ;
        np->next = p->next;
        p->next = np;
    }
}
 
void Output(SRec *sp, FILE *fp)
{
    while (sp = sp->next)
        fprintf(fp, "%5.1f %3d %s\n", sp->gpa, sp->credit, sp->name);
}
 
void Free(SRec *sp)
{
    SRec *next = sp->next;
    while (sp = next) {
        next = sp->next;
        free(sp->name);
        free(sp);
    }
}
 
int main(int argc, char *argv[])
{
    FILE *fp;
    int (*comp)(const void *, const void *);
    SRec head = { 0 };
 
    if (argc != 4) { fprintf(stderr, "usage: %s key infile outfile\n", argv[0]); return 1; }
    if (strcmp(argv[1], "gpa") == 0)
        comp = comp_gpa;
    else if (strcmp(argv[1], "credit") == 0)
        comp = comp_credit;
    else if (strcmp(argv[1], "name") == 0)
        comp = comp_name;
    else { fprintf(stderr, "key must be 'gpa', 'credit' or 'name'\n"); return 1; }
 
    fp = fopen(argv[2], "r");
    if (fp == NULL) { fprintf(stderr, "can't open %s\n", argv[2]); return 1; }
    InputAndSort(&head, comp, fp);
    fclose(fp);
    fp = fopen(argv[3], "w");
    if (fp == NULL) { fprintf(stderr, "can't create %s\n", argv[3]); return 1; }
    Output(&head, fp);
    fclose(fp);
    Free(&head);
    return 0;
}

かずま

Re: 宿題でつまずいてます

#85

投稿記事 by かずま » 13年前

かずま さんが書きました:malloc の配列なんてどこにあるんですか?
この掲示板の投稿ルールに
~回答者様へのお願い~ 目指すは「アットホームで温かい」
というのがありますね。

質問者の気持ちになって考えてみました。
http://dixq.net/forum/viewtopic.php?f=3 ... =60#p87092 のプログラムに

コード:

    array = (SRec *) malloc(sizeof(SRec));//並べ替えで使う SRec型
とあります。
malloc は sizeof(SRec) のサイズのデータ領域を確保します。
これはバイトの配列だから、array という名前の変数に入れて、
malloc の配列と呼んだのではないでしょうか?
そうは考えないでください。確保したのは SRec 構造体 1個であって配列ではありません。
これが連結リストの 1つのノードとなります。

もっと前のプログラムで、

コード:

    array = (SRec *) malloc(sizeof(SRec)*n);//並べ替えで使う SRec型
というのがありました
これはデータの件数 n = 3 を読み込んだ後だったので SRec構造体 3個分のデータ領域を確保しています。
読み込まれたデータは array[0]、array[1]、array[2] のように参照されます。

今回は、読み込むデータの件数があらかじめ分かっているのではないので
1件ずつ読み込み、1個ずつのノードを確保してリストにつないでいくことになります。

だから、本当は次のように書くべきでしょう。

コード:

    SRec *node;
    node = (SRec *) malloc(sizeof(SRec)); //リストに追加する SRec型のノード
私のプログラムでは「ノードへのポインタ」で np としています。

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#86

投稿記事 by れお » 13年前

mallocをちゃんと理解しきれてませんでした。

修正版みましたがどうしたらいいのか・・・申し訳ないです・・・
ありがとうございました。
今回は無理そうです。

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#87

投稿記事 by れお » 13年前

コード:

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

typedef struct school_record SRec;
struct school_record {
float gpa;
int credit;
char name[200];
SRec *next;
};
SRec head;//リストの先頭要素

/*void simple_sort(SRec* array, int n, int (*func)(const void*,const void*))
{
    SRec N;
    int i = 0, j = 0;
    for (i = 0; i < n; i++)
    {
        for (j = i + 1; j < n; j++)
        {
            if (func(&array[i],&array[j])==1)
            {
                N = array[i];
                array[i] = array[j];
                array[j] = N;
            }
        }
    }
    return;
}

int compare_float(const void * a, const void * b)
{
    SRec* tmp1 = (SRec*) a;
    SRec* tmp2 = (SRec*) b;
    if (tmp1->gpa == tmp2->gpa)
        return 0;
    else if (tmp1->gpa > tmp2->gpa)
        return 1;
    else
        return -1;
}

int compare_int(const void* a, const void* b)//gpa
{
    SRec* tmp1 = (SRec*) a;
    SRec* tmp2 = (SRec*) b;
    if (tmp1->credit == tmp2->credit)
        return 0;
    else if (tmp1->credit > tmp2->credit)
        return 1;
    else
        return -1;
}

int compare_char(const void * a, const void * b)
{
    SRec* tmp1 = (SRec*) a;
    SRec* tmp2 = (SRec*) b;
    if (strcmp(tmp1->name, tmp2->name) == 0)
        return 0;
    else if (strcmp(tmp1->name, tmp2->name) == 1)
        return 1;
    else
        return -1;
}*/


SRec* Input(FILE* fpi)
{
    SRec* node;
    SRec* tail;
    head.next=NULL;
    node=head.next;
    tail=&head;
    while(!feof(fpi))//i+1がデータ件数
     {
    	node=(SRec *) malloc(sizeof(SRec));//この時点では配列でなく1つのノードのみ
    	    if (node == NULL)
    	           {
    	               fprintf(stderr,"メモリ不足");
    	               return NULL;
    	           }
    	fscanf(fpi, "%f%d%s", node->gpa, node->credit, node->name);
        node->next = NULL;
        for(tail=head;tail->next!=NULL;tail=tail->next);
        tail->next = node;
     }
    free(node);

     return head.next;
}
 void Output(FILE* fpo)
 {
	 fprintf(fpo,"%1.1f %d %s\n",array[i].gpa,array[i].credit,array[i].name);
         }

 }


int main(int argc, char *argv[])
{
    SRec* node;
    FILE *fpi, *fpo;
    //int (*func)(const void*,const void*);

    if (argc != 4)//コマンドライン数がたりてるか?
    {
        fprintf(stderr, "Illegal number of argument.\n");
        return (-1);
    }
    if ((fpi = fopen(argv[2], "r")) == NULL)
    {
        fprintf(stderr, "Can't open input file <%s>.\n", argv[2]);
        return (-1);
    }
    if ((fpo = fopen(argv[3], "w")) == NULL)
    {
        fprintf(stderr, "Can't open output file <%s>.\n", argv[3]);
        return (-1);
    }
    node=Input(fpi);
/*
    if (strcmp(argv[1], "gpa") == 0)
        func=compare_float;//&はどちらでもいい
    else if (strcmp(argv[1], "credit") == 0)
        func=compare_int;
    else if (strcmp(argv[1], "name") == 0)
        func=compare_char;*/

   // simple_sort(node, n, func);
    Output(node,fpo);
    fclose(fpi);
    fclose(fpo);
    return 0;
}


かずまさんのやサイトを参考にちょっと書き換えましたが、エラーもでてるしいまいち何やってるかわかりません。エラーがでてるからわからないのかもしれませんが

85行目に - format argument is not a pointer (arg 4)
- format argument is not a pointer (arg 3)
87行目に incompatible types in assignment
がでてます
tail nodeはSRec型のポインタなので->でいいとおもうのですが・・・
問題はそこじゃないんですかね?

謎が謎をよんで今深みにはまってます><

かずま

Re: 宿題でつまずいてます

#88

投稿記事 by かずま » 13年前

エラーが出ないようにしてみました。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
typedef struct school_record SRec;
struct school_record {
    float gpa;
    int credit;
    char name[200];
    SRec *next;
};

SRec head; // head.next がリストの先頭要素を指す
 
SRec* Input(FILE* fpi)
{
    SRec *node;
    SRec *tail;
    head.next = NULL;
    tail = &head;
    while (1) {
        node = (SRec *) malloc(sizeof(SRec));
        if (node == NULL) {
            fprintf(stderr,"メモリ不足");
            return NULL;
        }
        if (fscanf(fpi, "%f%d%s", &node->gpa, &node->credit, node->name) != 3) {
            break;  // 読み込みに失敗したら EOF (feof は使わない)
        }
        node->next = NULL;  // この node を末尾要素とする
        // 現在のリストの末尾要素を探す
        for (tail = &head; tail->next != NULL; tail = tail->next) ;
        tail->next = node;  // 見つかった末尾要素に node を追加する。
    }
    free(node);
    return head.next;  // リストの先頭要素へのポインタを返す。
}

void Output(SRec *p, FILE* fpo)
{
    for (; p != NULL; p = p->next) {
        fprintf(fpo,"%3.1f %d %s\n", p->gpa, p->credit, p->name);
    }
}
 
int main(int argc, char *argv[])
{
    SRec* node;
    FILE *fpi, *fpo;
    //int (*func)(const void*,const void*);
 
    if (argc != 4) { //コマンドライン数がたりてるか?
        fprintf(stderr, "Illegal number of argument.\n");
        return (-1);
    }
    if ((fpi = fopen(argv[2], "r")) == NULL) {
        fprintf(stderr, "Can't open input file <%s>.\n", argv[2]);
        return (-1);
    }
    if ((fpo = fopen(argv[3], "w")) == NULL) {
        fprintf(stderr, "Can't open output file <%s>.\n", argv[3]);
        return (-1);
    }
    node = Input(fpi);
    if (node == NULL) return 1;
    Output(node, fpo);
    fclose(fpi);
    fclose(fpo);
    return 0;
}
理解できますか?
これは、リストの末尾を探して、読み込んだ node をそこに追加するものです
末尾を探す代わりに、適当な挿入場所を探せば、ソートができます。

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#89

投稿記事 by れお » 13年前

すみません。自分としてもできるだけ答えをおしえてもらわずにやりたいのですが、どうも苦手で修正版などの違う形をみても自分の形に応用することができません・・・

mallocをちゃんと理解していませんでした。=配列とおもいこんでいました・・・
今回提示してくださったものはなんとなくは理解できますが、疑問点もいくつかあります・・・
19行目:なぜわざわざ=NULLにするのかわかりません。これの行は別になくてもいいんですよね?
21行目:なぜwhile( )のところを (!=feof) にしてはいけないんですか?(fpi!=EOF)ならいいんですかね??たしかに(1)にするとずっとループするのでそれでいけるのはわかるのですが。
27行目:!=3というのは「要素数?が3つでないなら」っていう認識でいいのですか?こんな書き方できるのですね。はじめてしりました。でも今回ファイルの中身はちゃんとgpa credit nameが書いてあることが前提なので、やはりfeofをつかってもいいような気がしますが・・・
65行目:これは何をしているのですか?

何個もありすみません。。。

かずま

Re: 宿題でつまずいてます

#90

投稿記事 by かずま » 13年前

れお さんが書きました:19行目:なぜわざわざ=NULLにするのかわかりません。これの行は別になくてもいいんですよね?
head.next は何のためにあるのでしょうか?
リストの先頭のノード(SRec型)を指すためです。
これが NULL だと、リストにはまだ 1つもノードがないことを表します。
これが NULL でないと、リストに最低 1つはノードがあることになります。
実際にはまだリストは空っぽですよね。だから NULL にします。
今回の場合、head はグローバル変数ですから、実は head.next は NULL になっています。
そういう意味ではこの行はなくてもいいんですが、上記のことをちゃんと理解していましたか?
れお さんが書きました:21行目:なぜwhile( )のところを (!=feof) にしてはいけないんですか?(fpi!=EOF)ならいいんですかね??たしかに(1)にするとずっとループするのでそれでいけるのはわかるのですが。
input.txt という名前のファイルがあったとします。内容は次の通り。

コード:

3.5 27 jiro
2.7 24 taro
3.7 30 saburo
3行目の最後にも改行文字があるものとします。

次のプログラムを実行してみてください。

コード:

#include <stdio.h>

int main(void)
{
    float gpa;
    int credit;
    char name[200];
    int n = 0;

    FILE *fp = fopen("input.txt", "r");
    if (!fp) return 1;
    while (!feof(fp)) {
        fscanf(fp, "%f%d%s", &gpa, &credit, name);
        printf("gpa=%.1f, credit=%d, name=%s\n", gpa, credit, name);
        n++;
    }
    printf("n=%d\n", n);
    return 0;
}
実行結果

コード:

gpa=3.5, credit=27, name=jiro
gpa=2.7, credit=24, name=taro
gpa=3.7, credit=30, name=saburo
gpa=3.7, credit=30, name=saburo
n=4
3行目が 2つ出ていますよね。なぜだかわかりますか?
fscanf が 3行目のデータを読み込んでも、まだ入力には改行文字が残っていますから、
feof(fp) は 0 のままです。
while (!feof(fp)) は ループを続け、4回目の fscanf を呼び出します。
fscanf が失敗したかどうかを見ていませんから 4行目を読み込んだと勘違いして
n は 4 になります。

コード:

#include <stdio.h>

int main(void)
{
    char buf[200];
    int n = 0;

    FILE *fp = fopen("input.txt", "r");
    if (!fp) return 1;
    while (!feof(fp)) {
        fgets(buf, sizeof(buf), fp);
        fputs(buf, stdout);
        n++;
    }
    printf("n=%d\n", n);
    return 0;
}
このプログラムでは 3行目の改行文字まで読み込んでしまいますが、fgets はそこで
読み込みをやめてしまうので、まだ EOF にぶつからず feof(fp) は 0 のままです。

feof() はそれ以前の入力関数が EOF に達したかどうかを示すもので、これが 0 だから
といって、次の入力関数が必ず成功することを保証するものではありません。
ファイルの終わりのチェックは、入力関数の返す値をみて行うものです。
れお さんが書きました:65行目:これは何をしているのですか?
Input の中で malloc が失敗した場合 NULL が返ってきますから、それをチェックしています。

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#91

投稿記事 by れお » 13年前

27行目:!=3というのは「要素数?が3つでないなら」っていうので大丈夫ですよね?

前半:なるほどそういうことだったのですね!!理解できてませんでした・・・学校でもその説明はなく当たり前かのように進んでたのでそのまま進んでしまってました・・・ありがとうございます!

中半:一回よみこんだものをまた読み取るとかあるんですね^^;今回はファイルの中身が3つずつと固定だったから無限ループ(breakでとびだすが)でいけましたが、固定じゃなかった場合などはfeofはつかっていいのでしょうか?後半部分のfgetsですが、fgetsは
ファイルポインタfpから1行、またはlenバイト読み込んでその先頭アドレスを返す。
全行を読み込んだ場合、又はエラー時にNULL(\0)を返す。
ものですよね?3行目の改行文字まできたら読み込みを一度やめて、feof(fp)が0なので次の行をよもうとするが、fgetsがなにも読み込まないのでNULLをかえしてファイル終端に達するのでちゃんと機能するように思えるのですが・・・
あと入力関数の返す値をみて行うというのが具体的にどういうのかイメージできないです。
後半:なるほど・・・そういうのもちゃんとチェックしないといけないですよね。。。教えてもらえれば納得できますが、自分では気づきもしないと思います・・・><これからそういうのに慣れていければいいんですが・・・

ほんとにありがとうございました。結局頼り切った結果になってしまってかたじけないですが今後もどうかよろしくお願いします><
今は急いでないので暇なときによければ返信お願いしますm(__)m

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#92

投稿記事 by れお » 13年前

今度は↑でやったものをソートして出力したいです。
ソート方法は、ソート前のリスト:L, ソート後のリスト:S
1. Lが空なら終了
2. Lの中の最大要素Mを探索
3. MをLから削除
4. MをSに挿入( 挿入はSの先頭に)
5. 1. へ
というかんじです。
今回は結構自分で考えてやってみたのですが、出力ファイルに何も表示されません。。。
どなたか力をかしてくださいお願いしますm(__)m
下にコードをはります。不明な点などあれば言ってください。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct school_record SRec;
struct school_record {
    float gpa;
    int credit;
    char name[200];
    SRec *next;
};
SRec head;                					 // head.next がリストの先頭要素を指す

SRec* listsort(SRec *node,int (*func)(const void *,const void *))
{
    SRec top;        						//top.nextがソート後のリストの先頭要素へのポインタ
    SRec *save1,*save2,*p,*list,*last;    		    //topの末尾がlast
											//listはソート後のmalloc
    top.next=NULL;
    node=top.next;
    last=&top;
    while(p->next!=NULL)
    {
        p=&head;
        list = (SRec *) malloc(sizeof(SRec));
        list->next=NULL;
        if(list==NULL)
        {
            fprintf(stderr,"メモリ不足");
            return NULL;
        }
        while(p->next!=NULL)
        {
        	if(func(p->next,p)==1)        //最大のものを検索
        	{
        		save1=p;                   //削除するために最大のものの1つ手前をsave1として覚える
        		save2=p->next;			  //最大のものをsave2
        	p=p->next;
        	}
        }
        save1->next=save1->next->next;      //リストの削除
        list=save2;
        list->next=top.next;
        top.next=list;

    }
    free(list);
    return top.next;

}

int compare_float(const void * a, const void * b)
{
    SRec* tmp1 = (SRec*) a;
    SRec* tmp2 = (SRec*) b;
    if (tmp1->gpa == tmp2->gpa)
        return 0;
    else if (tmp1->gpa > tmp2->gpa)
        return 1;
    else
        return -1;
}
int compare_int(const void* a, const void* b)
{
    SRec* tmp1 = (SRec*) a;
    SRec* tmp2 = (SRec*) b;
    if (tmp1->credit == tmp2->credit)
        return 0;
    else if (tmp1->credit > tmp2->credit)
        return 1;
    else
        return -1;
}
int compare_char(const void * a, const void * b)
{
    SRec* tmp1 = (SRec*) a;
    SRec* tmp2 = (SRec*) b;
    if (strcmp(tmp1->name, tmp2->name) == 0)
        return 0;
    else if (strcmp(tmp1->name, tmp2->name) == 1)
        return 1;
    else
        return -1;
}
SRec* Input(FILE* fpi)
{
    SRec *node;
    SRec *tail;
    head.next = NULL;/*これが NULL だとリストにはまだ 1つもノードがないことを表す。
                       これが NULL でないとリストに最低 1つはノードがあることになる。
                       実際にはまだリストは空っぽだから NULL する。*/
    tail = &head;
    while (1)
    {
        node = (SRec *) malloc(sizeof(SRec));//これは配列ではない
        if (node == NULL)
        {
            fprintf(stderr,"メモリ不足");
            return NULL;
        }
        if (fscanf(fpi, "%f%d%s", &node->gpa, &node->credit, node->name) != 3)
        {
            break;  // 読み込みに失敗したら EOF (feof は使わないほうがよい)
        }
        node->next = NULL;  // この node を末尾要素とする
        for (tail = &head; tail->next != NULL; tail = tail->next) ;// 現在のリストの末尾要素を探す
        tail->next = node;  // 見つかった末尾要素に node を追加する。
    }
    free(node);
    return head.next;  // リストの先頭要素へのポインタを返す。
}
void Output(SRec *node, FILE* fpo)
{
    for (; node != NULL; node = node->next)
    {
        fprintf(fpo,"%3.1f %d %s\n", node->gpa, node->credit, node->name);
    }
}
int main(int argc, char *argv[])
{
    SRec* node;
    FILE *fpi, *fpo;
    int (*func)(const void*,const void*);
    if (argc != 4)
    {
        fprintf(stderr, "Illegal number of argument.\n");
        return (-1);
    }
    if ((fpi = fopen(argv[2], "r")) == NULL)
    {
        fprintf(stderr, "Can't open input file <%s>.\n", argv[2]);
        return (-1);
    }
    if ((fpo = fopen(argv[3], "w")) == NULL)
    {
        fprintf(stderr, "Can't open output file <%s>.\n", argv[3]);
        return (-1);
    }
    node = Input(fpi);
    if (strcmp(argv[1], "gpa") == 0)
        func=compare_float;//&はどちらでもいい
    else if (strcmp(argv[1], "credit") == 0)
        func=compare_int;
    else if (strcmp(argv[1], "name") == 0)
        func=compare_char;
    listsort(node,func);
    if (node == NULL) return 1;
    Output(node, fpo);
    fclose(fpi);
    fclose(fpo);
    return 0;
}

かずま

Re: 宿題でつまずいてます

#93

投稿記事 by かずま » 13年前

一つの問題が解決したら、「解決!」にするのがこの掲示板のルールです。
「宿題でつまずいています」という不適切なタイトルでこれ以上続けるのはやめましょう。
本当は、次のようなタイトルをつけてほしかった。
「成績データのソート(qsort を使用)」 No.1~No.28
「成績データのソート(自前のソート)」 No.29~No.80
「成績データのソート(連結リスト)」 No.80~No.91

次のタイトルで新規に始めませんか?
「成績データのソート(連結リスト・その2) No.92~

れお
記事: 113
登録日時: 13年前

Re: 宿題でつまずいてます

#94

投稿記事 by れお » 13年前

自分でもそれは思ってたのですが・・・
同じ範囲といえば同じ範囲だしどうすればいいかわからず、前ちょっと指摘されたのでこのままつづけてました。
新しくたてますね^^;

閉鎖

“C言語何でも質問掲示板” へ戻る