演習問題

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

演習問題

#1

投稿記事 by うり » 9年前

新・明解C言語 入門編という本の演習問題でどうしてもわからないところがありましたので、質問を投稿させていただきます。

問題は...
構造体を要素型とする配列を使用して登録された学生のデータ(名前、身長、体重、奨学金)を、身長もしくは名前の昇順でソートするプログラムを作成せよ、なお、名前や身長などのデータは初期化子として与えず、キーボードから読み込むこと。
というものです。

試行錯誤した結果、以下のようなコードになりました。

コード:

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

#define NUMBER 2 /*-学生の人数-*/
#define NAME_LEN 64 /*-名前の文字数-*/

/*---学生を表す構造体---*/
typedef struct{
	char name[NAME_LEN];
	int height;
	float weight;
	long schols;
}Student;

/*---xおよびyが指す学生を交換---*/
void swap_Student(Student *x, Student *y)
{
	Student temp = *x;
	*x = *y;
	*y = temp;
}

/*---学生の配列aの先頭n個の要素を身長の昇順にソート*/
void sort_by_height(Student a[], int n)
{
	int i, j;
	for (i = 0; i < n; i++){
		for (j = n; j >= i; j--){
			if (a[j - 1].height > a[j].height){
			swap_Student(&a[j - 1], &a[j]);
			}
		}
	}
}

/*---名前の昇順にソート---*/
void sort_by_name(Student a[], int n)
{
	int i, j;
	for (i = 0; i < n; i++){
		for (j = n; j >= i; j--){
			if (strcmp(a[j].name, a[j - 1].name)>0){
			swap_Student(&a[j - 1], &a[j]);
			}
		}
	}
}

int main(void)
{
	int i, j = 1;
	int c;
	Student std[NUMBER];

	for (i = 0; i < NUMBER; i++){
		printf("%d人目\n名前:", j); scanf("%s", std[i].name);
		printf("身長:"); scanf("%d", &std[i].height);
		printf("体重:"); scanf("%f", &std[i].weight);
		printf("奨学金:"); scanf("%ld", &std[i].schols);
		j = j + 1;
	}


	for (i = 0; i < NUMBER; i++){
		printf("%-8s %6d %6.1f %7ld\n",
		std[i].name, std[i].height, std[i].weight, std[i].schols);
	}
		printf("身長昇順でソート:[0]入力\n名前順でソート:[1]入力\n");
		scanf("%d", &c);
	if (c == 0){
	sort_by_height(std, NUMBER);
	puts("\nソートした\n");

	for (i = 0; i < NUMBER; i++){
		printf("%-8s %6d %6.1f %7ld\n",
		std[i].name, std[i].height, std[i].weight, std[i].schols);
	}
	}else if (c == 1){
	sort_by_name(std, NUMBER);
	puts("\nソートした\n");

	for (i = 0; i < NUMBER; i++){
		printf("%-8s %6d %6.1f %7ld\n",
		std[i].name, std[i].height, std[i].weight, std[i].schols);
	}
	}else{
		printf("ソートしません\n");
	}
	return 0;
}
しかし、このソースコードでは、学生のデータ(今回は2人としています)を入力し、
"身長昇順でソート:[0]入力\n名前順でソート:[1]入力"というところで、0,1どちらを入力しても、
Stack around the variable 'std' was corrupted.
というエラーが出てしまいます。

このエラーについてや、その他おかしい箇所がありましたらご指摘やご教授をいただければ幸いです。

長文失礼しましたm(__)m

アバター
amehirune
記事: 181
登録日時: 11年前
住所: どっか
連絡を取る:

Re: 演習問題

#2

投稿記事 by amehirune » 9年前

うり さんが書きました:試行錯誤した結果、以下のようなコードになりました。

コード:

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

#define NUMBER 2 /*-学生の人数-*/
#define NAME_LEN 64 /*-名前の文字数-*/

/*---学生を表す構造体---*/
typedef struct{
	char name[NAME_LEN];
	int height;
	float weight;
	long schols;
}Student;

/*---xおよびyが指す学生を交換---*/
void swap_Student(Student *x, Student *y)
{
	Student temp = *x;
	*x = *y;
	*y = temp;
}

/*---学生の配列aの先頭n個の要素を身長の昇順にソート*/
void sort_by_height(Student a[], int n)
{
	int i, j;
	for (i = 0; i < n; i++){
		for (j = n; j >= i; j--){
			if (a[j - 1].height > a[j].height){
			swap_Student(&a[j - 1], &a[j]);
			}
		}
	}
}

/*---名前の昇順にソート---*/
void sort_by_name(Student a[], int n)
{
	int i, j;
	for (i = 0; i < n; i++){
		for (j = n; j >= i; j--){
			if (strcmp(a[j].name, a[j - 1].name)>0){
			swap_Student(&a[j - 1], &a[j]);
			}
		}
	}
}

int main(void)
{
	int i, j = 1;
	int c;
	Student std[NUMBER];

	for (i = 0; i < NUMBER; i++){
		printf("%d人目\n名前:", j); scanf("%s", std[i].name);
		printf("身長:"); scanf("%d", &std[i].height);
		printf("体重:"); scanf("%f", &std[i].weight);
		printf("奨学金:"); scanf("%ld", &std[i].schols);
		j = j + 1;
	}


	for (i = 0; i < NUMBER; i++){
		printf("%-8s %6d %6.1f %7ld\n",
		std[i].name, std[i].height, std[i].weight, std[i].schols);
	}
		printf("身長昇順でソート:[0]入力\n名前順でソート:[1]入力\n");
		scanf("%d", &c);
	if (c == 0){
	sort_by_height(std, NUMBER);
	puts("\nソートした\n");

	for (i = 0; i < NUMBER; i++){
		printf("%-8s %6d %6.1f %7ld\n",
		std[i].name, std[i].height, std[i].weight, std[i].schols);
	}
	}else if (c == 1){
	sort_by_name(std, NUMBER);
	puts("\nソートした\n");

	for (i = 0; i < NUMBER; i++){
		printf("%-8s %6d %6.1f %7ld\n",
		std[i].name, std[i].height, std[i].weight, std[i].schols);
	}
	}else{
		printf("ソートしません\n");
	}
	return 0;
}
ざっと見させていただきましたが、コード29,30行目及び42,43行目にて、要素数を超える配列へアクセスしています。
もうちょっと具体的に言いますと、各関数における引数int nにはNUMBER、つまり2が渡されています。
この時点で宣言されている構造体はstd[0]、std[1]の2つだけです。
しかし、j = n(=2)で初期化した後にa[j]としてしまっています。ご確認ください。
ほら、来いよ!! 誤字や矛盾を指摘したい奴から、前に出てこいよぉおおおおおおおッ!!!
※都合により、不定期でしか現れません。即返などはできませんのでご了承ください※

うり

Re: 演習問題

#3

投稿記事 by うり » 9年前

ご指摘いただいた関数のa[j-1]>a[j]という部分(29,30,42,43行目)をa[j-2]>a[j-1]にすることで正常に動作することを確認できました。

非常にお早い返答、ありがとうございました!

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

Re: 演習問題

#4

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

うり さんが書きました:ご指摘いただいた関数のa[j-1]>a[j]という部分(29,30,42,43行目)をa[j-2]>a[j-1]にすることで正常に動作することを確認できました。
運が良かった(悪かった?)ですね。
jは0になるので、a[j-2]やa[j-1]は範囲外のことがあります。
範囲外にアクセス(読み書き)してはいけません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

超初級者
記事: 56
登録日時: 10年前

Re: 演習問題

#5

投稿記事 by 超初級者 » 9年前

そもそも、2人分のデータをソートしても
何もおもしろくないでしょう。

閉鎖

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