宿題でつまずいてます

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
れお
記事: 113
登録日時: 13年前

宿題でつまずいてます

#1

投稿記事 by れお » 13年前

何度か似たようなスレをたててしまい申し訳ありません。
これからは新しいのはたてずにこのスレですべて行っていきますので・・・

では本題に・・・;
成績データを読み込んでソートを行うプログラムを作成する。
1件の成績データは、累積GPA(Grade Point Average)、修得単位数、名前(氏のみ、英数字で199文字以内)、から構成されるものとする。入力ファイルには、まず、成績データの件数が記録されており、以降、成績データごとに、累積GPA、修得単位数、名前、の順で記録されているものとする。
成績データのどのフィールドでソートを行うかは、コマンドライン引数の第1引数で指定する。gpa なら累積GPA、credit なら修得単位数、name なら名前(辞書順)でソートする。第2引数には入力ファイル名、第3引数には出力ファイル名、をそれぞれ指定する。
なお、以下の条件を満たすこと。
a.成績データを記憶するための構造体を定義し、それを適当な名前で typedef せ よ(プログラム中では、以降、この typedef  した名前を用いること)。ただし、累積GPAは float型、修得単位数は int型、名前は文字配列で記憶するものとする。
b.複数件の成績データを格納するために、malloc で構造体配列の領域を確保せよ。
c.ソートの処理を自作でコーディングするアプローチも考えられるが、配列の場合 には、ソートを行うための汎用の関数 qsort () がライブラリに用意されている。 そこで、今回はこの qsort() を用いてプログラムを作成せよ。
d.qsortの第4引数に引数として渡す情報としては
 比較用関数へのポインタ
 比較のための関数(大小の定義関数)を作成して、その関数へのポインタを渡す。
 qsort() 内から、この比較用関数を呼び出す。
 比較用関数の戻り値で、qsort() は大きいか小さいかを知る。

という条件です。自分が途中まで書いたコードをいかに・・・(qsortなどが調べても実用できず、関数へのポインタもよくわからないのでまだそこは適当にかいてるだけです・・・ int (*func)(int, int)こういうのをどこにどうかけばいいのかわからないです。)

コード:

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

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

int compare_int(const void * a, const void * b) {
	/* 引数はvoid*型と規定されているのでint型にcastする */

	if (*(int *) a < *(int *) b)
		return -1;

}

int compare_float(const void * a, const void * b)
/* 引数はvoid*型と規定されているのでint型にcastする */

{

	if (*(int *) a < *(int *) b)
		return -1;

}

int compare_char(const void * a, const void * b)
/* 引数はvoid*型と規定されているのでint型にcastする */

{

	if (*(int *) a < *(int *) b)
		return -1;

}
int main(int argc, char *argv[]) {
	FILE *fpi, *fpo;
	SRec *array;//構造体をようい
	int i = 0, n = 0;

	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);
	}

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

	while (!feof(fpi)) {
		fscanf(fpi, "%f%d%s", &array[i].gpa, &array[i].credit, array[i].name);
		i++;
	}

	/*void * data:ソート対象データ(配列の先頭)
	 size_t data_cnt:ソート対象データ件数
	 size_t data_size:ソート対象データ1件当りのサイズ
	 int func:int型の比較関数(プログラマが作成する関数)*/
	if (strcmp(argv[1],"gpa")==0)
		qsort(array, n, sizeof(array), compare_float);
	if (strcmp(argv[1],"credit")==0)
		qsort(array, n, sizeof(array), compare_int);
	if (strcmp(argv[1],"name")==0)
		qsort(array, n, sizeof(array), compare_char);

	fclose(fpi);

	if ((fpo = fopen(argv[3], "w")) == NULL) {
		fprintf(stderr, "Can't open output file <%s>.\n", argv[3]);
		return (-1);
	}

	fclose(fpo);

	free(array);
	return 0;
}

色いろ調べてるんですが、ここから全然すすみません。。。どなたか教えてください。
qsortで構造体のデータをわたしてますが、これだと構造体のgpa,credit,nameのどれを渡してるのかわかりませんよね?どうやってソートするんでしょう・・・

box
記事: 2002
登録日時: 14年前

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

#2

投稿記事 by box » 13年前

れお さんが書きました: これからは新しいのはたてずにこのスレですべて行っていきますので・・・
それはそれであまりよろしくないような気がします。
話題が変われば新しいスレッドを立てるのはごく自然なことだと思います。
いろんな話題が1つのスレッドに固まってしまっている方がよほど不自然かと。

qsort()の使い方については、もしかするとこのサイトが参考になるかもしれません。
http://www.mm2d.net/c/c-17.shtml
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

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

#3

投稿記事 by れお » 13年前

そうですか。
では話題が大幅にかわればまたたてさせていただきます。
今日はもう遅いのでまた明日確認します^^

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

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

#4

投稿記事 by れお » 13年前

ん~
よんだんですが、うまくいかない・・・><

box
記事: 2002
登録日時: 14年前

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

#5

投稿記事 by box » 13年前

れお さんが書きました:ん~
よんだんですが、うまくいかない・・・><
的確なアドバイスを得ようとする場合、単に「うまくいかない」と書くよりも、
そのうまくいかないソースコードを載せる方がいいような気がします。

単に「うまくいかない」と書かれましても、こちらには何も伝わってきません。
何も言っていないのと同じことになっています。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

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

#6

投稿記事 by beatle » 13年前

れお さんが書きました:

コード:

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

int compare_int(const void * a, const void * b) {
	/* 引数はvoid*型と規定されているのでint型にcastする */

	if (*(int *) a < *(int *) b)
		return -1;

}

array = (SRec *) malloc(sizeof(int) * n);//並べ替えで使う SRec型
qsort(array, n, sizeof(array), compare_int);
色いろ調べてるんですが、ここから全然すすみません。。。どなたか教えてください。
qsortで構造体のデータをわたしてますが、これだと構造体のgpa,credit,nameのどれを渡してるのかわかりませんよね?どうやってソートするんでしょう・・・
必要なところだけ抜粋しましたので、コードのインデントなどは崩れています。
さて、qsortに渡す比較用関数は、int (const void*, const void*)という型ですね。voidポインタなのはなぜかというと、どんなデータ型(charやintなどの組み込み型、構造体など)でもソートできるようにするためです。
たぶん引数がvoid*型ということで、「これだと構造体のgpa,credit,nameのどれを渡してるのかわかりませんよね?」という疑問が出たのかと思うのです。

まずqsortの呼び出し部分を見てみましょう。

コード:

qsort(array, n, sizeof(array), compare_int);
qsortにはarrayへのポインタとsizeof(array)を渡していますが、sizeof(array)は間違いです。この部分はSRecのサイズを渡しましょう。
要するにqsortには、

ソートしたい要素が並んだ配列の先頭アドレス
要素の数
要素1個あたりの大きさ

を渡すのです。
そして、比較関数の引数a, bには、それぞれ配列のとある要素の先頭アドレスが来ますから、それをSReq*にキャストして使います。
引数a, bは

コード:

const void* a = (const void*)&array[i];
const void* b = (const void*)&array[j];
というようになっているんだと思えばいいでしょう。ですから、利用者側は

コード:

const SReq* a_ = (const SReq*)a;
const SReq* b_ = (const SReq*)b;
として使えばOKです。

(qsortは難しいですよね。僕も苦手です。)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

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

#7

投稿記事 by みけCAT » 13年前

beatle さんが書きました:(qsortは難しいですよね。僕も苦手です。)
競技プログラミングだと、ソートは非常によく使うので、qsortも山ほど使います。
std::sort?何それ?おいしいの?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

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

#8

投稿記事 by れお » 13年前

コード:

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

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

 int compare_int(const void* a, const void* b)//gpa
 {                          /* 引数はvoid*型と規定されているのでSRec型にcastする */
	 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_float(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 SRec * a, const SRec * 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 main(int argc, char *argv[]) {
	FILE *fpi, *fpo;
	SRec *array;//構造体をようい
	int i = 0, n = 0;

	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);
	}


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

	while (!feof(fpi)) {
		fscanf(fpi, "%f%d%s", &array[i].gpa, &array[i].credit, array[i].name);
		i++;
	}

	/*void * data:ソート対象データ(配列の先頭)
	 size_t data_cnt:ソート対象データ件数
	 size_t data_size:ソート対象データ1件当りのサイズ
	 int func:int型の比較関数(プログラマが作成する関数)*/
	if (strcmp(argv[1],"gpa")==0)
	{
		qsort(array, n, sizeof(SRec), compare_float);//gpa

	}
	if (strcmp(argv[1],"credit")==0)
		qsort(array, n, sizeof(SRec), compare_int);
	if (strcmp(argv[1],"name")==0)
		qsort(array, n, sizeof(SRec), compare_char);

	fclose(fpi);



	fclose(fpo);

	free(array);
	return 0;
}
すみません後で貼り付けようとおもっていました。
ちょっと教えてもらったことも理解できなくてどこをどう直していいかわからず適当にいろいろなサイトなどを参照してここまでやってみました><
サイトとかをみてると14行目などは

コード:

int a = *(int*)arg0;
とかなってるサイトなども見かけて、*がなんで2回もでてきているのかなどよくわかりません・・・
あと、今回の条件にもなっている関数へのポインタもどこでどう使用するかや、渡し方・引数のとりかた?などわからないことだらけです・・・
調べても自分と同じような内容のがなくて困ってます・・・
この時点では91行目だけエラーが出ています。その理由も調べましたがよくわかりません。。。ほかのgap creditと同じようにしてるのに・・・

box
記事: 2002
登録日時: 14年前

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

#9

投稿記事 by box » 13年前

れお さんが書きました:

コード:

	 float gpa;
	 int credit;

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

 int compare_float(const void * a, const void * b)
 {
	 if(tmp1->credit == tmp2->credit)
		 return 0;
メンバーgpaとcredirに関して、実際の型と比較用の関数とが逆転していませんか?
れお さんが書きました:

コード:

int a = *(int*)arg0;
とかなってるサイトなども見かけて、*がなんで2回もでてきているのかなどよくわかりません・・・
ポインター変数arg0を、いったんint型へのポインターとしてキャストしています。
キャスト後の結果から、int値を取り出すために * を先頭に付けています。
れお さんが書きました: この時点では91行目だけエラーが出ています。その理由も調べましたがよくわかりません。。。ほかのgap creditと同じようにしてるのに・・・
これまで、いろいろなところで何度かお願いしてきておりますが、
「エラーが出ています」だけでは、何も説明したことになっていません。
「どんな」エラーが出ているかを書いていただきたいです。問題を早く解決したければ。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

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

#10

投稿記事 by れお » 13年前

たしかに;
きづきませんでした。

今回の自分の課題ではその必要はないですかね??
難しくてよく意味がわからなくて・・・^^;


エラーというのは(警告でした)
passing arg 4 of `qsort' from incompatible pointer type
です。
最後に編集したユーザー れお on 2012年5月26日(土) 19:32 [ 編集 1 回目 ]

box
記事: 2002
登録日時: 14年前

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

#11

投稿記事 by box » 13年前

れお さんが書きました:

コード:

 int compare_int(const void* a, const void* b)//gpa
 int compare_float(const void * a, const void * b)
 int compare_char(const SRec * a, const SRec * b)
compare_charだけ、他の2個と比べて引数の並びが異なっているようです。
意図されているとおりのコードですか?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

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

#12

投稿記事 by れお » 13年前

コード:

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

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




 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)
 {                          /* 引数は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 main(int argc, char *argv[]) {
	FILE *fpi, *fpo;
	SRec *array;//構造体をようい
	int i = 0, n = 0;

	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);
	}


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

	while (!feof(fpi)) {
		fscanf(fpi, "%f%d%s", &array[i].gpa, &array[i].credit, array[i].name);
		i++;
	}

	/*void * data:ソート対象データ(配列の先頭)
	 size_t data_cnt:ソート対象データ件数
	 size_t data_size:ソート対象データ1件当りのサイズ
	 int func:int型の比較関数(プログラマが作成する関数)*/
	if (strcmp(argv[1],"gpa")==0)
	{
		qsort(array, n, sizeof(SRec), compare_float);//gpa

	}
	if (strcmp(argv[1],"credit")==0)
		qsort(array, n, sizeof(SRec), compare_int);
	if (strcmp(argv[1],"name")==0)
		qsort(array, n, sizeof(SRec), compare_char);

	for(i=0;i<n;i++)
	{
	fprintf(fpo,"%f %d %s\n",array[i].gpa,array[i].credit,array[i].name);
	}
	fclose(fpi);



	fclose(fpo);

	free(array);
	return 0;
}
という状態で↑でかいた警告はなくなりましたが、実行すると実行できず動作を停止しましたとなります。(プログラムが動かなくなる)


>boxさん 見落としてました・・・;qsortの比較関数の場合そこはいつでもvoidなんですかね?voidはなんでもいけるからSRecにしてみてたのですが・・・SRecにしたらだめなんですかね??・・・・

box
記事: 2002
登録日時: 14年前

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

#13

投稿記事 by box » 13年前

qsort関数の引数の並びは、下記のようになっています。

void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));

この関数は、ソートしたいデータの「型に関係なく」ソートできるようになっていなければなりません。
よって、第4引数に指定している「関数へのポインターで利用している2個の引数」は、
データがどんな型であってもいいように、void * になっています。

先ほど提示されていたソースでは、文字列を比較するために用意されていた関数の引数が、
「ある特定のデータ型だけに対応している」状態であったため、
qsort関数が想定している引数の並びと異なっていますよ、という意味の警告が出ていた、というわけです。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

box
記事: 2002
登録日時: 14年前

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

#14

投稿記事 by box » 13年前

れお さんが書きました:

コード:

	array = (SRec *) malloc(sizeof(int) * n);//並べ替えで使う SRec型
	if ((array = (SRec *) malloc(sizeof(int) * n)) == NULL) {
malloc関数を2回続けて実行している理由は、何ですか?
malloc関数の引数の記述が、sizeof(SRec) とかではなく sizeof(int) である理由は、何ですか?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

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

#15

投稿記事 by れお » 13年前

box さんが書きました:qsort関数の引数の並びは、下記のようになっています。

void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));

この関数は、ソートしたいデータの「型に関係なく」ソートできるようになっていなければなりません。
よって、第4引数に指定している「関数へのポインターで利用している2個の引数」は、
データがどんな型であってもいいように、void * になっています。

先ほど提示されていたソースでは、文字列を比較するために用意されていた関数の引数が、
「ある特定のデータ型だけに対応している」状態であったため、
qsort関数が想定している引数の並びと異なっていますよ、という意味の警告が出ていた、というわけです。
なるほど!!納得しました^^b


mallocのほうですが、確かにいわれたみればそうですね^^;

おっしゃるとおりに直せばプログラムがうまく作動しました。しかし疑問点がいくつかあります・・・

コード:

	 SRec* tmp1 = (SRec*)a;
	 SRec* tmp2 = (SRec*)b;
なんでこのような形にしないといけないのかがわかりません・・・
じゃあどうするつもりなの?と聞かれても特に思いつくわけでもないのですが、なんでこうしないといけないのでしょぅ・・・
左辺はわかるんですが、右辺がいまいちキャストとかいわれるとわからなくなります・・・さっきも書いたのですが*(SRec*)aとかじゃだめなのかとか理解できてません><

コード:

array = (SRec *) malloc(sizeof(SRec) * n);//並べ替えで使う SRec型
なぜsixeof(array)じゃだめなのでしょう?arrayはSRecと同じサイズ?だとおもうのですが・・・

同様に

コード:

	if (strcmp(argv[1],"gpa")==0)
	{
		qsort(array, n, sizeof(SRec), compare_float);//gpa

	}
	if (strcmp(argv[1],"credit")==0)
		qsort(array, n, sizeof(SRec), compare_int);
	if (strcmp(argv[1],"name")==0)
		qsort(array, n, sizeof(SRec), compare_char);
についてもsizeof(array)じゃだめなのでしょうか?_?


いかはおそらく今回の完成品です

コード:

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

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




 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 main(int argc, char *argv[]) {
	FILE *fpi, *fpo;
	SRec *array;//構造体をようい
	int i = 0, n = 0;

	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);
	}


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

	while (!feof(fpi)) {
		fscanf(fpi, "%f%d%s", &array[i].gpa, &array[i].credit, array[i].name);
		i++;
	}

	/*void * data:ソート対象データ(配列の先頭)
	 size_t data_cnt:ソート対象データ件数
	 size_t data_size:ソート対象データ1件当りのサイズ
	 int func:int型の比較関数(プログラマが作成する関数)*/
	if (strcmp(argv[1],"gpa")==0)
	{
		qsort(array, n, sizeof(SRec), compare_float);//gpa

	}
	if (strcmp(argv[1],"credit")==0)
		qsort(array, n, sizeof(SRec), compare_int);
	if (strcmp(argv[1],"name")==0)
		qsort(array, n, sizeof(SRec), compare_char);

	for(i=0;i<n;i++)
	{
	fprintf(fpo,"%1.1f %d %s\n",array[i].gpa,array[i].credit,array[i].name);
	}
	fclose(fpi);



	fclose(fpo);

	free(array);
	return 0;
}

box
記事: 2002
登録日時: 14年前

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

#16

投稿記事 by box » 13年前

れお さんが書きました:

コード:

array = (SRec *) malloc(sizeof(SRec) * n);//並べ替えで使う SRec型
なぜsixeof(array)じゃだめなのでしょう?arrayはSRecと同じサイズ?だとおもうのですが・・・
私の先ほどの回答をもう一度よくご覧ください。
malloc関数の引数の記述が sizeof(int) で本当にいいんですか?
とおたずねしています。
sizeof(array) でいいかどうか、については全く言及していません。

そもそも、SRecというのは実体であって、それを指す(はずの)arrayとは、
実体とポインターという観点からいって、サイズが同じであることはないです。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

box
記事: 2002
登録日時: 14年前

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

#17

投稿記事 by box » 13年前

れお さんが書きました:

コード:

 int compare_int(const void* a, const void* b)//gpa
 {                          /* 引数はvoid*型と規定されているのでSRec型にcastする */
	 SRec* tmp1 = (SRec*)a;
	 SRec* tmp2 = (SRec*)b;
	 if(tmp1->gpa == tmp2->gpa)
		 return 0;
このの記述に関しては、
tmp1やtmp2という変数を用いなくてもいいかもしれません。
例えば

コード:

    if((SRec*)a->gpa == (SRec*)b->gpa)
のように書けるかもしれません。試してはいないので、本当に動くかどうかはわかりません。
時間があれば、試してみてください。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

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

#18

投稿記事 by れお » 13年前

box さんが書きました:
れお さんが書きました:

コード:

array = (SRec *) malloc(sizeof(SRec) * n);//並べ替えで使う SRec型
なぜsixeof(array)じゃだめなのでしょう?arrayはSRecと同じサイズ?だとおもうのですが・・・
私の先ほどの回答をもう一度よくご覧ください。
malloc関数の引数の記述が sizeof(int) で本当にいいんですか?
とおたずねしています。
sizeof(array) でいいかどうか、については全く言及していません。

そもそも、SRecというのは実体であって、それを指す(はずの)arrayとは、
実体とポインターという観点からいって、サイズが同じであることはないです。

すみませんww
それには気づいてましたがただ疑問がのこっていたので聞いてみました^^;
なんとなくわかりました!ありがとうございます。

↑ためしてきます

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

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

#19

投稿記事 by れお » 13年前

box さんが書きました:
れお さんが書きました:

コード:

 int compare_int(const void* a, const void* b)//gpa
 {                          /* 引数はvoid*型と規定されているのでSRec型にcastする */
	 SRec* tmp1 = (SRec*)a;
	 SRec* tmp2 = (SRec*)b;
	 if(tmp1->gpa == tmp2->gpa)
		 return 0;
このの記述に関しては、
tmp1やtmp2という変数を用いなくてもいいかもしれません。
例えば

コード:

    if((SRec*)a->gpa == (SRec*)b->gpa)
のように書けるかもしれません。試してはいないので、本当に動くかどうかはわかりません。
時間があれば、試してみてください。

コード:

 int compare_float(const void * a, const void * b)
 {

	 if((SRec*)a->gpa == (SRec*)b->gpa)
		 return 0;
	 else if((SRec*)a->gpa > (SRec*)b->gpa)
		 return 1;
	 else
		 return -1;
 }
- request for member `gpa' in something not a
structure or union
- dereferencing `void *' pointer
となりました。

box
記事: 2002
登録日時: 14年前

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

#20

投稿記事 by box » 13年前

ああ、ということは、いったん一時的な変数に格納する必要がある、ということのようですね。
面倒かもしれませんが、そのようにしてください。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

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

#21

投稿記事 by れお » 13年前

なるほど。。。

またなにかあればお願いします^^

ほんと毎回ありがとうございます><

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

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

#22

投稿記事 by れお » 13年前

あっそいういえば、これって条件のdみたせてないですよね??
どうすればいいんでしょうか・・・?
関数へのポインタにするメリットもわかりませんが・・・

box
記事: 2002
登録日時: 14年前

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

#23

投稿記事 by box » 13年前

れお さんが書きました:あっそいういえば、これって条件のdみたせてないですよね??
満たしているように見えますけれど…。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

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

#24

投稿記事 by れお » 13年前

そうですかww

int (*func)(int, int)

こういう形のものがなかったのでつい・・・

box
記事: 2002
登録日時: 14年前

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

#25

投稿記事 by box » 13年前

れお さんが書きました: int (*func)(int, int)
qsortの第4引数で渡しているのが、
int (*func)(const void *, const void *)
という、「任意の型へのポインター(に後で変換できる)を2つ渡して、
比較結果によりint型の戻り値を返す関数へのポインター」
です。
compare_int, compare_float, compare_char の3つです。


条件d
d.qsortの第4引数に引数として渡す情報としては
 比較用関数へのポインタ
 比較のための関数(大小の定義関数)を作成して、その関数へのポインタを渡す。
 qsort() 内から、この比較用関数を呼び出す。
 比較用関数の戻り値で、qsort() は大きいか小さいかを知る。
をすべて満たしているように思います。


関数っていうのもメモリー上のどこかにあるわけですから、アドレスを持っているわけです。
関数名そのものが、その関数がメモリー上のどこにあるか、というアドレス値を持っています。
配列名が、その配列がメモリー上のどこにあるか、というアドレス値を持っていることと考え方は同じです。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

box
記事: 2002
登録日時: 14年前

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

#26

投稿記事 by box » 13年前

関数名がアドレス値であることの実験を行なうコードは、
例えばこんな感じです。func関数の中身はこの際どうでもいいので、からっぽにしてあります。

コード:

#include <stdio.h>

void func(void)
{
}

int main(void)
{
    printf("main:%p\n", main);
    printf("func:%p\n", func);
    return 0;
}
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

かずま

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

#27

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

box さんが書きました:ああ、ということは、いったん一時的な変数に格納する必要がある、ということのようですね。
面倒かもしれませんが、そのようにしてください。
if (((SRec*)a)->gpa == ((SRec*)b)->gpa)
と書けば一時変数に格納する必要はありません。

(SRec*)a->gap と書くと、a->gap を SRec* にキャストするという意味です。
a->gap を見ると、a は void* であって、構造体へのポインタではありませんから
- request for member `gpa' in something not a structure or union
(構造体または共用体でないものにおいて、メンバ 'gap' に対する(使用)要求)
というエラーメッセージが出るのです。

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

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

#28

投稿記事 by れお » 13年前

>boxさん 遅くなってすみません。この3週間テストやら課題やらで忙しくて・・・
       なるほど納得しました^^

>かずまさん なんかカッコがいくつもつくだけでもう自分はだめですwwいわれてみればそうだとわかりましたが・・・

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

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

#29

投稿記事 by れお » 13年前

今度は↑で完成したプログラムを
a.入力処理、出力処理、ソート処理をそれぞれ 1個の関数呼び出しで実現できるように作成する(それらの関数の中でさらに別の関数を呼び出してもいい)。
b.ソート処理関数の引数は 3個。すなわち、ソート対象の構造体配列へのポインタ、要素数、比較関数へのポインタ、の 3個。
c.入力処理関数、出力処理関数では、それぞれの関数内において外部変数にアクセスしてはいけない。構造体配列へのポインタやデータ件数は、引数や戻り値で授受すること。
d.出力ファイルの最初には、成績データの件数を記録すること。出力ファイルをそのまま入力ファイルとして使用できるように配慮すること。
(昇順にならべようとしてます)

という条件のもとで書き換えないといけないのですが、つまってます・・・
あとdの後半である出力ファイルをそのまま入力ファイルとして使用できるようにするというやり方がわかりません。
とりあえず、コマンドラインの第一引数をcreditにして、まだsimple_sortはcreditのときの分しかつくってません。
128 131 133行目に
passing arg 3 of `simple_sort' makes integer from pointer without a cast
という警告がでているのですが、どうしたら警告がなくなるのかわかりません・・・

コード:

#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 compare_int)
{
	int N = 0, i = 0, j = 0;
	for (i = 0; i < n; i++)
	{
		for (j = i + 1; j < n; j++)
		{
			if (compare_int==1)
			{
				N = array[i].credit;
				array[i].credit = array[j].credit;
				array[j].credit = 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;
}

void Number(FILE* fpi,int n)
{
	fscanf(fpi, "%d", &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(FILE* fpo,int n,SRec* array)
 {
     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 n = 0;

	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);
	}

	Number(fpi,n);

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

	Input(array,n,fpi);


	if (strcmp(argv[1], "gpa") == 0)
	{
		simple_sort(array, n, compare_float);
	}
	if (strcmp(argv[1], "credit") == 0)
		simple_sort(array, n, compare_int);
	if (strcmp(argv[1], "name") == 0)
		simple_sort(array, n, compare_char);

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

	free(array);
	return 0;
}

どなたか力をかしてください><

box
記事: 2002
登録日時: 14年前

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

#30

投稿記事 by box » 13年前

simple_sort関数の引数の意味を説明してください。
この関数を呼び出している箇所と見比べると、3つめの引数の意味が
全然違っているように見えます。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

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

#31

投稿記事 by れお » 13年前

box さんが書きました:
れお さんが書きました: int (*func)(int, int)
qsortの第4引数で渡しているのが、
int (*func)(const void *, const void *)
という、「任意の型へのポインター(に後で変換できる)を2つ渡して、
比較結果によりint型の戻り値を返す関数へのポインター」
です。
compare_int, compare_float, compare_char の3つです。

引数は順に
ソート対象の構造体配列へのポインタ、要素数、比較関数へのポインタ
のつもりなんですが・・・
第3引数については↑の3つだと思ったので・・・

box
記事: 2002
登録日時: 14年前

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

#32

投稿記事 by box » 13年前

では、おたずねします。
れお さんが書きました:

コード:

void simple_sort(SRec* array, int n, int compare_int)
この第3引数のどこに、関数へのポインターという意味の記述があるのでしょうか。
単なるint型、という記述でしかないように見えます。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

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

#33

投稿記事 by れお » 13年前

どうやったら関数へのポインタになるのか見当がつかないのですが・・・;

box
記事: 2002
登録日時: 14年前

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

#34

投稿記事 by box » 13年前

そもそもsimple_sort関数というのは本当に必要なんでしょうか。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

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

#35

投稿記事 by れお » 13年前

そういう課題なのでひつようです!!;

qsort()関数を自前のソート関数に置き換える。ただし、ソートアルゴリズムには、最大値抽出法を用いる。

box
記事: 2002
登録日時: 14年前

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

#36

投稿記事 by box » 13年前

れお さんが書きました: qsort()関数を自前のソート関数に置き換える。ただし、ソートアルゴリズムには、最大値抽出法を用いる。
この文言は、このスレッドのこれまでのやりとりにはなかったように見えます。課題の内容に変化があったのでしょうか。
最大値抽出法という用語が適切なのかどうかはよくわかりません。
とりあえず、「最大値選択法」あたりでググってみると、アルゴリズムの説明が見つかると思います。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

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

#37

投稿記事 by れお » 13年前

すみません。
そこは書かなくてももうできているのでいいと思ってました。
simple_sortの中身が最大値抽出法なのでそこはもうきにしなくていいのですが、(intなどの型は変える必要あるとおもいますが)警告をなくせないのでそこで詰まっています・・・

へにっくす

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

#38

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

れお さんが書きました:どうやったら関数へのポインタになるのか見当がつかないのですが・・・;
以下のような感じになるかと

コード:

void simple_sort(SRec* ap, int n, int (*func)(const void*, const void*))
{
	// 渡し方
	func(&ap[0], &ap[1]);
}
// 呼び出し方は
// int func(const void *a, const void *b)
// を渡すならば
// simple_sort(ap, n, func);
関数のポインタ変数の宣言の仕方:
通常のプロトタイプ宣言は以下です。

コード:

void func();
これをポインタ変数にするには、funcをかっこでくくり、その先頭に*をつけます。

コード:

void (*func)();
かっこでくくらないと、優先順位の関係で、ポインタ変数とはみなされなくなるので注意。
しかしこーゆー説明ってC教本には載ってないのよね・・・(^^;

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

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

#39

投稿記事 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*))
{
	int N = 0, i = 0, j = 0;
	for (i = 0; i < n; i++)
	{
		for (j = i + 1; j < n; j++)
		{
			if (func)
			{
				N = array[i].credit;
				array[i].credit = array[j].credit;
				array[j].credit = 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;
}

void Number(FILE* fpi,int n)
{
	fscanf(fpi, "%d", &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 n = 0;
	void (*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);
	}

	Number(fpi,n);

	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;
}
とりあえず関数へのポインタっぽくしてみましたが、いまいちよくわかりません・・・
今のところ128 130 132行目にassignment from incompatible pointer typeの警告
134行目にpassing arg 3 of `simple_sort' from incompatible pointer typeの警告がでてます。
なんとなく意味はわかるんですが自分なりになおしてもいっこうに警告きえないし・・・><


たしかに本にはのってませんよね;しかも学校で使ってるやつはポインタが最後の章でほんとに初歩的なことしかのっていないみたいで(完全に理解してるわけでもありませんが・・・)
だからネットで調べてやってるんですが、いろいろありすぎて自分はどのパターンのを使えばいいのかわかりません。自分の場合は比較関数などをつかったりしてて・・・
最後に編集したユーザー れお on 2012年6月02日(土) 15:40 [ 編集 1 回目 ]

へにっくす

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

#40

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

れお さんが書きました:とりあえず関数へのポインタっぽくしてみましたが、いまいちよくわかりません・・・
今のところ128 130 132行目にassignment from incompatible pointer typeの警告
134行目にpassing arg 3 of `simple_sort' from incompatible pointer typeの警告がでてます。
なんとなく意味はわかるんですが自分なりになおしてもいっこうに警告きえないし・・・><
ええっと、、
main関数で宣言している関数の戻り値の型と実際に渡している関数へのポインタの戻り値の型が違うのは分かってますか?
分かれば、その警告は出なくなるはずなので。
今回は、そのmain関数で宣言している戻り値の型をvoid→intにするだけだと思います。

・・・言えることは、
例をそのままもってこないでください。関数の宣言の型が違えば、警告やエラーが出るのは当たり前です。
ちゃんと考えてね

へにっくす

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

#41

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

へにっくす さんが書きました:・・・言えることは、
例をそのままもってこないでください。関数の宣言の型が違えば、警告やエラーが出るのは当たり前です。
ちゃんと考えてね
ごめんなさい
例をそのままではありませんでしたね
謝ります
m(__;)m

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

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

#42

投稿記事 by れお » 13年前

intになおしたらけいこくきえました^^

19行目のifの中ですが、func=compare_intなのでcompare_intで返している1をfunc==1みたいにしたのですが、どうやったらできるんでしょうか?
func==1にするとcomparison between pointer and integerという警告が出ます;
funcはポインタなのでなんとなくわかりますが、
*func==1としたら*funcはint型なのでいけるとおもったらむりでした・・・

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

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

#43

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

れお さんが書きました:intになおしたらけいこくきえました^^

19行目のifの中ですが、func=compare_intなのでcompare_intで返している1をfunc==1みたいにしたのですが、どうやったらできるんでしょうか?
func==1にするとcomparison between pointer and integerという警告が出ます;
funcはポインタなのでなんとなくわかりますが、
*func==1としたら*funcはint型なのでいけるとおもったらむりでした・・・
途中は全く見てませんが、funcはintを返す関数のポインタなので*funcだけならは文法的にエラーです。
関数と変数を同列に扱ってはいけません。
ざっとこれまでのやり取りを見る限り、関数やポインタの理解が不十分だと思いますので出来合いのパターンを引っ張ってくるんじゃなくて、ちゃんと理解して使わないと堂々めぐりすると思います。
動いてOK!じゃなくて、何故こうする必要があるのかを理解しましょう。

[補足]
まず、自分で分からないと思う文法レベルの疑問を書きだしてみてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

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

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

#44

投稿記事 by れお » 13年前

たしかにそうです;
ただその理解不十分なものを十分にするのが課題なのです・・・;
つまりこの課題を通して学べという感じなのだとおもいます。(授業でならわないので)

できるだけ自分の力で試行錯誤してやりたいのですが、力不足で自分でやっても全然正解にたどり着けないのです・・・

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

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

#45

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

れお さんが書きました:たしかにそうです;
ただその理解不十分なものを十分にするのが課題なのです・・・;
つまりこの課題を通して学べという感じなのだとおもいます。(授業でならわないので)

できるだけ自分の力で試行錯誤してやりたいのですが、力不足で自分でやっても全然正解にたどり着けないのです・・・
それでは鶏が先か卵が先か状態ですよ。
まずは、文法の理解。それをより確かなものにするために課題だと思います。
現状関数ポインタ以前に、関数そのものが理解できていないと感じます。
これって、習った部分ですよね?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

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

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

#46

投稿記事 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.credit = array[i].credit;
				array[i].credit = array[j].credit;
				array[j].credit = N.credit;
			}
		}
	}
	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;
}

void Number(FILE* fpi,int n)
{
	fscanf(fpi, "%d", &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 n = 0;
	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);
	}

	Number(fpi,n);

	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;
}
もうこれでいけたと思っていたのに・・・どこが悪いのか><

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

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

#47

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

経緯とかよく分かっていないので余計な口出しをしないほうが良さそうですね。
今まで関わってきた方にお任せします。

ちなみに
if (func(&array,&array[j])==1)
は間違いです。

「関数ポインタ」
http://wisdom.sakura.ne.jp/programming/c/c54.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

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

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

#48

投稿記事 by れお » 13年前

まじですか!?^^;

そのサイトもほかのサイトも最低10個はみたんですが・・・

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

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

#49

投稿記事 by ISLe » 13年前

softya(ソフト屋) さんが書きました:「関数ポインタ」
http://wisdom.sakura.ne.jp/programming/c/c54.html
このリンク先もそうですけど、この手の説明は関数名が関数へのポインタ(関数のアドレス)という点を知ってて当たり前みたいに流してますよね。

前段階として、関数名が関数へのポインタであることとか関数の型とかを理解しないとダメな気がします。

コード:

void foo(char c, int i) {
    // char,intを引数に持ち返却値がvoidである関数fooは、
    // char,intを引数に持ち返却値がvoidという関数型
}
void (*func)(char,int) = foo;
// char,intを引数に持ち返却値がvoidという関数型へのポインタ変数funcに代入(これは初期化だけど)できる
int main() {
    func = foo; // もちろんふつうに代入できる
}
最後に編集したユーザー ISLe on 2012年6月02日(土) 18:13 [ 編集 2 回目 ]

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

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

#50

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

れお さんが書きました:まじですか!?^^;

そのサイトもほかのサイトも最低10個はみたんですが・・・
ごめんなさい。
それでも通るんですが誤解招くので書き方はあまりしません。が正解です。
(*func)(引数)
が一般的です。

エラーの原因は別件ですが経緯を知らないので入力パラメータ等を私が把握していなので追試は出来ません。って事でよろしくお願いします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

へにっくす

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

#51

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

softya(ソフト屋) さんが書きました:それでも通るんですが誤解招くので書き方はあまりしません。
うーん
確かに紛らわしいかもね…

学ばせて頂きました (^^
れお さんが書きました:でも実行すると動作を停止しましたとなります。
入力ファイルの内容と、コマンドラインの掲示もしないで単に動作を停止と言っても、何も対策をアドバイスできませんよ?

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

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

#52

投稿記事 by れお » 13年前

ちょっと今ばたばたしてて目をとおせないのでへにっくすsのだけ返信します。


たしかにそうですね;
さっき書こうとしてたのですが、そのまま忘れてました・・・すみませn

入力ファイルが
3
3.5 27 jiro
2.7 24 taro
3.7 30 saburo
で最初のもじは人数です
(それをファイルからよみとって変数nに代入してます。)

コマンドラインは
credit a.txt b.txt
で、第一引数にはgpa credit nameの3通りがきます。
自分のコードはまだcreditのソースしかつくってないのでcreditしか反応しません。a.txt b.txtが順に入力ファイルと出力ファイルです

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

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

#53

投稿記事 by ISLe » 13年前

softya(ソフト屋) さんが書きました:それでも通るんですが誤解招くので書き方はあまりしません。が正解です。
(*func)(引数)
が一般的です。
1.関数へのポインタを間接参照すると関数指示子になります。
2.関数呼出しは呼び出す関数を指す式を評価して呼び出します。
3.そのとき関数指示子は評価されて関数へのポインタとして扱われます。

最終的な関数呼出しは関数へのポインタを使うので
func(変数)
で良い気がしますけど。

変数であることを強調したいとしても
(*func)(引数)
は関数指示子でやってもエラーにならないんですよね。

コード:

void foo(char c, int i) {
}
void (*func)(char,int) = foo;
int main() {
    func(1,2);
    foo(1,2);
    (*func)(1,2);
    (*foo)(1,2); // エラーにならない
    (****************func)(1,2); // ついでにこんなことしてもエラーにならない
}

かずま

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

#54

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

れお さんが書きました:もうこれでいけたと思っていたのに・・・どこが悪いのか><
1. SRec を交換すべきところで、.credit だけを交換している。
2. Number() の仕様では、main の n に値は返らない。

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

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

#55

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

動かすと、b.txtに0と言う値が入りました。

>でも実行すると動作を停止しましたとなります。
エラーは再現されておりませんが、動作は異常だと思います。
途中経過をデバッグ用にprintfしてみてはどうでしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

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

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

#56

投稿記事 by れお » 13年前

ISLe さんが書きました: 前段階として、関数名が関数へのポインタであることとか関数の型とかを理解しないとダメな気がします。

コード:

void foo(char c, int i) {
    // char,intを引数に持ち返却値がvoidである関数fooは、
    // char,intを引数に持ち返却値がvoidという関数型
}
void (*func)(char,int) = foo;
// char,intを引数に持ち返却値がvoidという関数型へのポインタ変数funcに代入(これは初期化だけど)できる
int main() {
    func = foo; // もちろんふつうに代入できる
}
これはなんとなく理解しました^^
なので宣言のとき、int (*func)(const void*,const void*)としました。
でfunc=compare_intとかしました^^

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

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

#57

投稿記事 by れお » 13年前

>かずまs 後半:void Numberをintにして return n; しました
        前半がどの部分かよくわからないのですが・・・
        むしろ20行目を

コード:

if (func(&array[i].credit,&array[j].credit)==1)//(*func)(..)でも可
かと思ったく        らいなんですが・・・;

>ソフト屋s そうですね。ところどころprintfしてみます。でもデバッグも実行もできない状態なので今のところ確認もできないです・・・

かずま

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

#58

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

れお さんが書きました: むしろ20行目を

コード:

if (func(&array[i].credit,&array[j].credit)==1)//(*func)(..)でも可
かと思ったく        らいなんですが・・・;
20行目は問題ありません。21~23行目です。
N = array; array = array[j]; array[j] = N;

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

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

#59

投稿記事 by れお » 13年前

[quote="かずま]20行目は問題ありません。21~23行目です。
N = array; array = array[j]; array[j] = N;[/quote]
そうなんですか?
こうしたら構造体のどれを比較してるかわからなくないですかね??

でもまだ動作を停止するんですね・・・^^;難しい・・・

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

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

#60

投稿記事 by beatle » 13年前

どこまで実行したら動作を停止するのか、それを突き止めてみましょう。

Visual C++ならば、図の赤丸の部分をダブルクリックするとブレークポイントを設定できます。
その状態で実行ボタン(青丸で囲んだ三角形)を押せば、そのブレークポイントで実行が止まります。
ブレークポイントの位置をちょっとずつ変えながら実行を繰り返せば、どこで実行がストップしているかが分かります。
visual_cpp_reo.png

へにっくす

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言語何でも質問掲示板” へ戻る