ページ 1 / 1
リスト構造
Posted: 2016年12月19日(月) 22:34
by 桜並木
学校から出された課題がわからなかったので質問させていただきます。
課題は、「リストの要素(1~10)をランダムに並べ替えた、新たなリストを作るプログラムを作成せよという課題です。」
実行例 処理前:12345678910
処理後:83421097635 のような感じです。
自分なりに考えて見たのですが、プログラムを実行すると動作が停止してしまいます。
どこが間違っているのかを指摘していただけないでしょうか?
プログラミングをならって10ヶ月くらいになりますが得意ではないです。だから、変なプログラムだと思います。ごめんなさい。
コード:
#include < stdio.h >
#include < stdlib.h >
#include <time.h>
struct list
{
int data;
struct list *next;
};
// リスト構造の先頭に新しいデータを追加する関数
struct list *add_list(int x, struct list *head)
{
struct list *new_head;
new_head = (struct list *)malloc(sizeof(struct list));
new_head->data = x;
new_head->next = head;
return new_head;
}
// リスト構造を表示する関数
void show_list(struct list *head)
{
if (head == NULL) // NULLポインタだったら改行のみ表示
{
printf("\n\n");
}
else {
printf("%d", head->data);
show_list(head->next); //再帰呼び出し
}
}
void random(struct list *head1, struct list *head2) {
static int count;
int num;
srand((unsigned)time(NULL));
num = rand() % 10;
if ((head2 + num)->data == 0) {
random(head1, head2);
}
else
{
(head1 + count)->data = (head2 + num)->data;
(head2 + num)->data = 0;
count++;
}
}
void main()
{
int i;
struct list *head1;
struct list *head2;
int num;
// int num_2;
head1 = (struct list *)malloc(sizeof(struct list));
head2 = (struct list *)malloc(sizeof(struct list));
head1 = NULL;
head2 = NULL;
head1 = add_list(10, head1);
head1 = add_list(9, head1);
head1 = add_list(8, head1);
head1 = add_list(7, head1);
head1 = add_list(6, head1);
head1 = add_list(5, head1);
head1 = add_list(4, head1);
head1 = add_list(3, head1);
head1 = add_list(2, head1);
head1 = add_list(1, head1);
head2 = head1;
printf("処理前:");
show_list(head1);
printf("処理後 : ");
for (i = 0;i <= 10;i++) {
random(head1, head2);
}
show_list(head1);
}
Re: リスト構造
Posted: 2016年12月19日(月) 22:54
by みけCAT
桜並木 さんが書きました:コード:
void random(struct list *head1, struct list *head2) {
static int count;
int num;
srand((unsigned)time(NULL));
num = rand() % 10;
if ((head2 + num)->data == 0) {
random(head1, head2);
}
else
{
(head1 + count)->data = (head2 + num)->data;
(head2 + num)->data = 0;
count++;
}
}
1要素しか確保していないので、countやnumが1以上だと確保されていない場所にアクセスし、
未定義動作になってしまいます。
きちんとリストをたどることで目的の要素にアクセスしなければいけません。
また、head1とhead2が同じリストを指している場合、head1から始まるリストを直接書き換えてしまうのもいけません。
簡単なのは呼び出し元で出力用のリストを別に確保し、渡すことでしょう。
main関数の戻り値がint型でないのは、処理系依存です。
こう書かないとなぜか減点される、宗教上の理由などの特別な理由が無いのであれば、標準に含まれるint main(void)を用いるべきです。
桜並木 さんが書きました:コード:
head1 = (struct list *)malloc(sizeof(struct list));
head2 = (struct list *)malloc(sizeof(struct list));
head1 = NULL;
head2 = NULL;
せっかく確保したメモリへのアドレスをすぐに投げ捨て、メモリリークを起こしています。
どうせ使わないメモリは確保しなくていいでしょう。
Re: リスト構造
Posted: 2016年12月19日(月) 23:10
by 桜並木
ご指導していただきありがとうございます。
言われたことを自分なりに解釈したつもりだったのですが、またプログラムが停止してしまいました。
どこが間違っているのか教えていただけないでしょうか?
コード:
#include < stdio.h >
#include < stdlib.h >
#include <time.h>
struct list
{
int data;
struct list *next;
};
// リスト構造の先頭に新しいデータを追加する関数
struct list *add_list(int x, struct list *head)
{
struct list *new_head;
new_head = (struct list *)malloc(sizeof(struct list));
new_head->data = x;
new_head->next = head;
return new_head;
}
// リスト構造を表示する関数
void show_list(struct list *head)
{
if (head == NULL) // NULLポインタだったら改行のみ表示
{
printf("\n\n");
}
else {
printf("%d", head->data);
show_list(head->next); //再帰呼び出し
}
}
int random(struct list *head1) {
struct list *head2;
head2 = (struct list *)malloc(sizeof(struct list));
static int count;
int num;
srand((unsigned)time(NULL));
num = rand() % 10;
if ((head1 + num)->data == 0) {
return random(head1);
}
else
{
(head2 + count)->data = (head1 + num)->data;
(head1 + num)->data = 0;
count++;
return (head2 + count)->data;
}
}
int main(void)
{
int i;
struct list *head1;
struct list *head2;
// int num_2;
head1 = NULL;
head2 = NULL;
head1 = add_list(10, head1);
head1 = add_list(9, head1);
head1 = add_list(8, head1);
head1 = add_list(7, head1);
head1 = add_list(6, head1);
head1 = add_list(5, head1);
head1 = add_list(4, head1);
head1 = add_list(3, head1);
head1 = add_list(2, head1);
head1 = add_list(1, head1);
printf("処理前:");
show_list(head1);
printf("処理後 : ");
for (i = 0;i <= 10;i++) {
(head2 + i)->data = random(head1);
}
show_list(head2);
}
Re: リスト構造
Posted: 2016年12月19日(月) 23:17
by みけCAT
main関数の型とメモリリークは直したようですが、肝心の範囲外アクセスを修正しないどころか増やしてしまいましたね。
Re: リスト構造
Posted: 2016年12月19日(月) 23:28
by 桜並木
返信ありがとうございます。
自分の知識不足ということもあり、範囲外アクセスがよくわかりません。本当に申し訳ないのですが、範囲外アクセスについて教えていただけないでしょうか?
また前のご指導で1要素しか確保していないといわれたので、mallocで要素を確保すればいいと考えたのですが違うのでしょうか?その点も合わせて教えていただけないでしょうか?
Re: リスト構造
Posted: 2016年12月20日(火) 06:22
by metaphor
random関数の再帰でリストが壊れて落ちるようなのでrandom関数に詳しいコメントをお願い致します。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct list//リスト構造体:
{
int data; //リストのデータ
struct list *next;//次のデータへのポインタ:リスト・チェイン
};
// リスト構造の先頭に新しいデータを追加する関数
struct list *add_list(int x, struct list *head)//新データ:新次のデータへのポインタ
{
struct list *new_head; //次のデータへのポインタ
new_head = (struct list *)malloc(sizeof(struct list));//メモリー確保
//ポインタのつなぎ換え
new_head->data = x; //リストにデータを登録
new_head->next = head;// 今までの先頭ポインタを次ポインタに
return new_head; //新しい先頭ポインタ
}
// リスト構造を表示する関数
void show_list(struct list *head)
{
if (head == NULL) // NULLポインタだったら改行のみ表示
{
printf("\n\n");
}
else {
printf("%d", head->data);//データ表示
show_list(head->next); //再帰呼び出し
}
/* 同じこと
while (head != NULL) { // 次ポインタがNULLまで処理
printf("%d ", head->data);
head = head->next;
}
printf("\n\n"); */
}
/////////////////////////////////////////////////////////////////////////////
// ★何をするのか「コメントを各行に書いてください
static int count;//static グローバル変数
int num;void random(struct list *head1, struct list *head2) {//random関数
srand((unsigned)time(NULL));//乱数
num = rand() % 10;
if ((head2 + num)->data == 0) {//head2のポインターnum個進める:そのデータが0なら再帰
//random(head1, head2);//★再帰で落ちている???
}
else
{
(head1 + count)->data = (head2 + num)->data;
(head2 + num)->data = 0;
count++;
}
}
////////////////////////////////////////////////////////////////////////////
int main(void)
{
int i;
struct list *head1;//リスト1
struct list *head2;//リスト2
int num;
// int num_2;
head1 = NULL;
head2 = NULL;
head1 = add_list(10, head1);//次ポインタの移動
head1 = add_list(9, head1);
head1 = add_list(8, head1);
head1 = add_list(7, head1);
head1 = add_list(6, head1);
head1 = add_list(5, head1);
head1 = add_list(4, head1);
head1 = add_list(3, head1);
head1 = add_list(2, head1);
head1 = add_list(1, head1);
head2 = head1;//リスト2次ポインタをリスト1次ポインタにする
//リスト2=リスト1
printf("処理前:");
show_list(head1); //リスト1表示
printf("処理後: ");
//random(head1, head2);//random(関数の呼び出し:::Debug:::
for (i = 0; i <= 10; i++) {
random(head1, head2);//random(関数の呼び出し
}
show_list(head1); //リスト1表示
}
処理前:12345678910
処理後: 12345678910
続行するには何かキーを押してください . . .
Re: リスト構造
Posted: 2016年12月20日(火) 08:08
by みけCAT
random()が呼ばれるたびにsrand((unsigned)time(NULL));を呼んでいるのも良くなさそうですね。
(暗号などで決まった乱数列が欲しいのではなく)単に適当な乱数が欲しいのであれば、
srand()はプログラムの実行開始時に1度だけ呼び出すのがいいでしょう。
Re: リスト構造
Posted: 2016年12月20日(火) 10:46
by 桜並木
返信ありがとうございます。
randomの関数にコメントを足しました。
srand()は、どこに書けばよいのでしょうか?最初のほうに書くと「この宣言にはストレージ クラスまたは型指定子がありません」と表示されてしまったのですが
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct list//リスト構造体:
{
int data; //リストのデータ
struct list *next;//次のデータへのポインタ:リスト・チェイン
};
// リスト構造の先頭に新しいデータを追加する関数
struct list *add_list(int x, struct list *head)//新データ:新次のデータへのポインタ
{
struct list *new_head; //次のデータへのポインタ
new_head = (struct list *)malloc(sizeof(struct list));//メモリー確保
//ポインタのつなぎ換え
new_head->data = x; //リストにデータを登録
new_head->next = head;// 今までの先頭ポインタを次ポインタに
return new_head; //新しい先頭ポインタ
}
// リスト構造を表示する関数
void show_list(struct list *head)
{
if (head == NULL) // NULLポインタだったら改行のみ表示
{
printf("\n\n");
}
else {
printf("%d", head->data);//データ表示
show_list(head->next); //再帰呼び出し
}
/* 同じこと
while (head != NULL) { // 次ポインタがNULLまで処理
printf("%d ", head->data);
head = head->next;
}
printf("\n\n"); */
}
static int count;//static グローバル変数
int num;void random(struct list *head1, struct list *head2) {//random関数
srand((unsigned)time(NULL));//乱数
num = rand() % 10;//1~10までなので、10で割った余りをnumにいれてhead2+numのときに使う
if ((head2 + num)->data == 0) {//head2のポインターnum個進める:そのデータが0なら再帰
//random(head1, head2);//★再帰で落ちている???
}
else
{
(head1 + count)->data = (head2 + num)->data;//(head1+count)->dataに(head2+num)->dataを代入する
//countは1つずつ増えて、numはランダムな数になるからてきとうに並び変わると考えた
(head2 + num)->data = 0; //1回使用した(head2+num)->dataの値を0にして、if文の条件より同じ(head2+num)->data
//が使われなくなると考えた
count++; //countの数を1つ増やす
}
}
int main(void)
{
int i;
struct list *head1;//リスト1
struct list *head2;//リスト2
int num;
// int num_2;
head1 = NULL;
head2 = NULL;
head1 = add_list(10, head1);//次ポインタの移動
head1 = add_list(9, head1);
head1 = add_list(8, head1);
head1 = add_list(7, head1);
head1 = add_list(6, head1);
head1 = add_list(5, head1);
head1 = add_list(4, head1);
head1 = add_list(3, head1);
head1 = add_list(2, head1);
head1 = add_list(1, head1);
head2 = head1;//リスト2次ポインタをリスト1次ポインタにする
//リスト2=リスト1
printf("処理前:");
show_list(head1); //リスト1表示
printf("処理後: ");
//random(head1, head2);//random(関数の呼び出し:::Debug:::
for (i = 0; i <= 10; i++) {
random(head1, head2);//random(関数の呼び出し
}
show_list(head1); //リスト1表示
}
Re: リスト構造
Posted: 2016年12月20日(火) 12:53
by metaphor
アルゴリズムが間違っているようです。
コード:
printf("%d\n\n",head1->data);//可能
head1 = head1->next;//可能
printf("%d\n\n",head1->data);//可能
printf("%d\n\n",(head1+5)->data);//不可能:足し算は想定道理にならない
printf("%d\n\n",(head1+5)->data);//不可能
printf("%d\n\n",(head2+5)->data);//不可能
もう一度考え直さないとダメみたいですね。
Re: リスト構造
Posted: 2016年12月20日(火) 15:19
by 桜並木
返信ありがとうございます。
もう一度考え直して、違う書き方にしました。
プログラムを実行すると結果が、処理前:12345678910
処理後:-842150451
と表示されその後動作が停止してしまいます。どこが間違っているのか教えていただけないでしょうか?
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct list//リスト構造体:
{
int data; //リストのデータ
struct list *next;//次のデータへのポインタ:リスト・チェイン
};
// リスト構造の先頭に新しいデータを追加する関数
struct list *add_list(int x, struct list *head)//新データ:新次のデータへのポインタ
{
struct list *new_head; //次のデータへのポインタ
new_head = (struct list *)malloc(sizeof(struct list));//メモリー確保
//ポインタのつなぎ換え
new_head->data = x; //リストにデータを登録
new_head->next = head;// 今までの先頭ポインタを次ポインタに
return new_head; //新しい先頭ポインタ
}
// リスト構造を表示する関数
void show_list(struct list *head)
{
if (head == NULL) // NULLポインタだったら改行のみ表示
{
printf("\n\n");
}
else {
printf("%d", head->data);//データ表示
show_list(head->next); //再帰呼び出し
}
}
int main(void)
{
int i,j = 0,k = 0,count=0;
struct list *head1;//リスト1 処理前のリスト
struct list *head2;//リスト2 前と後の中間のリスト
struct list *head3;//リスト3 処理後のリスト
int num;
int a[10]; //ここに出てきた乱数を格納する
head1 = NULL;
head2 = NULL;
head3 = (struct list *)malloc(sizeof(struct list));
head1 = add_list(10, head1);//次ポインタの移動
head1 = add_list(9, head1);
head1 = add_list(8, head1);
head1 = add_list(7, head1);
head1 = add_list(6, head1);
head1 = add_list(5, head1);
head1 = add_list(4, head1);
head1 = add_list(3, head1);
head1 = add_list(2, head1);
head1 = add_list(1, head1);
head2 = head1;//リスト2次ポインタをリスト1次ポインタにする
//リスト2=リスト1
srand((unsigned)time(NULL)); //乱数
num = rand() % 10 + 1; //numに乱数を代入
//1~10までの数字なので10で割った余り+1
printf("処理前:");
show_list(head1); //リスト1表示
printf("処理後: ");
for (i = 0; i < 10; i++) { //10個のデータを扱うので10回する
for(j=0;j<=count;j++){ //一度使用した数字を使わないようにするためのfor文
if(num == a[j]){ //処理の条件:numと格納した数字が同じ場合
num = rand() % 10 + 1;//numにもう一度乱数を代入する
j=-10; //jを-1にしてもう一度チェックしなおす準備
count = 0; //countを0にしてもう一度チェックしなおす準備
}
}
add_list(num,head3); //head3にnum(乱数)をadd_listを使い追加する
a[k] = num; //使った数字をa[k]に格納する
k++; //kの値を増加させる
}
show_list(head3); //リスト3表示
}
Re: リスト構造
Posted: 2016年12月20日(火) 15:23
by 桜並木
コード:
for (i = 0; i < 10; i++) { //10個のデータを扱うので10回する
for(j=0;j<=count;j++){ //一度使用した数字を使わないようにするためのfor文
if(num == a[j]){ //処理の条件:numと格納した数字が同じ場合
num = rand() % 10 + 1;//numにもう一度乱数を代入する
j=-10; //jを-1にしてもう一度チェックしなおす準備
count = 0; //countを0にしてもう一度チェックしなおす準備
[/quote]
j = -10ではなくj=-1のうち間違いです。すいません。
結果は変わらず動きませんでした。
Re: リスト構造
Posted: 2016年12月20日(火) 15:45
by usao
オフトピック
64行目以降の処理で,大元のリスト(head1かな)が全く参照されてないように見えるけど,そういう方法で良いのだろうか?
Re: リスト構造
Posted: 2016年12月20日(火) 16:23
by 桜並木
返信ありがとうございます
問題には特に条件がなかったので、大丈夫かなっと思い作りました。
Re: リスト構造
Posted: 2016年12月20日(火) 16:35
by metaphor
取り敢えずこうなった。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct list//リスト構造体:
{
int data; //リストのデータ
struct list *next;//次のデータへのポインタ:リスト・チェイン
};
// リスト構造の先頭に新しいデータを追加する関数
struct list *add_list(int x, struct list *head)//新データ:新次のデータへのポインタ
{
struct list *new_head; //次のデータへのポインタ
new_head = (struct list *)malloc(sizeof(struct list));//メモリー確保
//ポインタのつなぎ換え
new_head->data = x; //リストにデータを登録
new_head->next = head;// 今までの先頭ポインタを次ポインタに
return new_head; //新しい先頭ポインタ
}
// リスト構造を表示する関数
void show_list(struct list *head)
{
if (head == NULL) // NULLポインタだったら改行のみ表示
{
printf("\n\n");
}
else {
printf("%d", head->data);//データ表示
show_list(head->next); //再帰呼び出し
}
}
int main(void)
{
int i,j = 0,k = 0,count=0;
struct list *head1;//リスト1 処理前のリスト
struct list *head2;//リスト2 前と後の中間のリスト
struct list *head3;//リスト3 処理後のリスト
int num;
int a[10]; //ここに出てきた乱数を格納する
head1 = NULL;
head2 = NULL;
head3 = NULL;//head2と同じ
//head3 = (struct list *)malloc(sizeof(struct list));
head1 = add_list(10, head1);//次ポインタの移動
head1 = add_list(9, head1);
head1 = add_list(8, head1);
head1 = add_list(7, head1);
head1 = add_list(6, head1);
head1 = add_list(5, head1);
head1 = add_list(4, head1);
head1 = add_list(3, head1);
head1 = add_list(2, head1);
head1 = add_list(1, head1);
head2 = head1;//リスト2次ポインタをリスト1次ポインタにする
//リスト2=リスト1
srand((unsigned)time(NULL)); //乱数
num = rand() % 10 + 1; //numに乱数を代入
//1~10までの数字なので10で割った余り+1
printf("処理前:");
show_list(head1); //リスト1表示
show_list(head2);//////////////////////////////////////////////////////////////////check
printf("処理後: ");
for (i = 0; i < 10; i++) { //10個のデータを扱うので10回する
for(j=0;j<=count;j++){ //一度使用した数字を使わないようにするためのfor文
if(num == a[j]){ //処理の条件:numと格納した数字が同じ場合
num = rand() % 10 + 1;//numにもう一度乱数を代入する
j=-1; //jを-1にしてもう一度チェックしなおす準備
count = 0; //countを0にしてもう一度チェックしなおす準備
}
}
//add_list(num,head3); //head3にnum(乱数)をadd_listを使い追加する
head3=add_list(num,head3);/////////////////////////////////////////////////////check
show_list(head3);//////////////////////////////////////////////////////////////////check
a[k] = num; //使った数字をa[k]に格納する
k++; //kの値を増加させる
}
show_list(head3); //リスト3表示
}
処理前:12345678910
12345678910
処理後: 8
48
448
4448
44448
444448
4444448
44444448
444444448
4444444448
4444444448
続行するには何かキーを押してください . . .
Re: リスト構造
Posted: 2016年12月20日(火) 21:37
by 桜並木
返信ありがとうございます。
コード:
for (i = 0; i < 10; i++) { //10個のデータを扱うので10回する
for (j = 0;j <= count;j++) { //一度使用した数字を使わないようにするためのfor文
if (num == a[j]) { //処理の条件:numと格納した数字が同じ場合
num = rand() % 10 + 1;//numにもう一度乱数を代入する
j = -1; //jを-1にしてもう一度チェックしなおす準備
count = 0; //countを0にしてもう一度チェックしなおす準備
}
}
head3 = add_list(num, head3);////head3にnum(乱数)をadd_listを使い追加する
show_list(head3);//////////////////////////////////////////////////////////////////check
a[k] = num; //使った数字をa[k]に格納する
k++; //kの値を増加させる
}
この部分のどこかに原因があるのは分かるのですが、どこが間違っているのかわかりません。
どの部分が、間違っているのかを教えてくれないでしょうか?
Re: リスト構造
Posted: 2016年12月20日(火) 21:42
by みけCAT
パッと見の印象では、countに0以外の値が入らないのは怪しいですね。
Re: リスト構造
Posted: 2016年12月20日(火) 21:51
by みけCAT
jのループの上限であるcountが0固定なので、a[0]との重複のみがチェックされ、しかも重複していない時はループ中でnumが更新されないので、「最初の要素」と「それ以外の要素」にそれぞれ同じ値、かつグループ間では異なる値が割り当てられるようですね。
オフトピック
リストの要素とは関係ない1~10を並べ替えている(?)ようだが、リストの要素も1~10であり、問題文にも書かれている1~10を配置しているので問題ないのかなあ…。
まあ、ここの改善は今の仕様(リストとは関係なく1~10を並べる)でうまく動くようになってからでもいいですよね。
Re: リスト構造
Posted: 2016年12月20日(火) 22:02
by 桜並木
返信ありがとうございます。
countの値を増やす処理を入れ忘れていました。
コード:
for (i = 0; i < 10; i++) { //10個のデータを扱うので10回する
for (j = 0;j <= count;j++) { //一度使用した数字を使わないようにするためのfor文
if (num == a[j]) { //処理の条件:numと格納した数字が同じ場合
num = rand() % 10 + 1;//numにもう一度乱数を代入する
j = -1; //jを-1にしてもう一度チェックしなおす準備
count = 0; //countを0にしてもう一度チェックしなおす準備
}
count++;
}
head3 = add_list(num, head3);////head3にnum(乱数)をadd_listを使い追加する
show_list(head3);//////////////////////////////////////////////////////////////////check
a[k] = num; //使った数字をa[k]に格納する
k++; //kの値を増加させる
}
countの増やす処理を入れてプログラムを実行すると、何も表示されませんでした。
他にはどこが間違っているのでしょうか?
Offtopic の改善は、うまく動けるようになったらにします。
Re: リスト構造
Posted: 2016年12月20日(火) 23:09
by みけCAT
桜並木 さんが書きました:countの増やす処理を入れてプログラムを実行すると、何も表示されませんでした。
それはcountとjが同じ速さで増えるので、countがオーバーフローして未定義動作になるまでj <= countが常に真だからですね。
(countがオーバーフローする前に、a[j]が範囲外になることで未定義動作になるでしょう)
kが格納された数字の数になっているので、j <= countをj < kにするとよさそうだと思います。
(k個格納されており、添字は0からなので、<=ではなく<です)
(条件の判定でkを使ったからといって、ループ内でkを0にリセットする処理を加えるなどの余計な変更をしてはいけません)
さらに、num = rand() % 10 + 1;をループの前ではなくfor (i = 0; i < 10; i++) {の直後に移動し、重複チェックの前にnumが更新されるようにするといいでしょう。
Re: リスト構造
Posted: 2016年12月20日(火) 23:18
by metaphor
これを試して何か気がつかない。どうもよく分からない?
コード:
show_list(head2);////////////////check表示
printf("処理後: \n");
for (i = 0; i < 10; i++) { //10個のデータを扱うので10回する
num = rand() % 10 + 1;
//for(j=0;j<=count;j++){ //一度使用した数字を使わないようにするためのfor文
//if(num == a[j]){ //処理の条件:numと格納した数字が同じ場合
//num = rand() % 10 + 1;//numにもう一度乱数を代入する
//j=-1; //jを-1にしてもう一度チェックしなおす準備
//count = 0; //countを0にしてもう一度チェックしなおす準備
//}
//count++;
//}
head3=add_list(num,head3);///////check表示
//show_list(head3);/////////////check表示
a[k] = num; //使った数字をa[k]に格納する
printf("i=%d a[k]=%d num=%d\n",i,a[k],num);
k++; //kの値を増加させる
}
printf("\n\n");
show_list(head3); //リスト3表示
}
Re: リスト構造
Posted: 2016年12月20日(火) 23:37
by metaphor
10回では無理な気がする。10個違う数がそろうまで繰り返すことが必要なのでは?
Re: リスト構造
Posted: 2016年12月20日(火) 23:50
by metaphor
あ、違うjループの判定がおかしいのかな?
Re: リスト構造
Posted: 2016年12月20日(火) 23:51
by 桜並木
返信ありがとうございます。
みけCATさんに指摘されたところを直し、一様プログラムを表示されました。
しかし、処理前:12345678910
処理後:10263921416
という結果になってしまいました。どこがいけないのでしょうか?
コード:
for (i = 0; i < 10; i++) { //10個のデータを扱うので10回する
for (j = 0;j <k;j++) { //一度使用した数字を使わないようにするためのfor文
num = rand() % 10 + 1;
if (num == a[j]) { //処理の条件:numと格納した数字が同じ場合
j = -1; //jを-1にしてもう一度チェックしなおす準備
}
}
head3 = add_list(num, head3);///////check表示
//show_list(head3);/////////////check表示
a[k] = num; //使った数字をa[k]に格納する
k++; //kの値を増加させる
}
show_list(head3); //リスト3表示
}
metaphorさんのプログラムを試して結果自分には、a[k]とnumの値が同じなことぐらいしかわかりませんでした。
コード:
for (j = 0;j <k;j++) { //一度使用した数字を使わないようにするためのfor文
num = rand() % 10 + 1;
if (num == a[j]) { //処理の条件:numと格納した数字が同じ場合
j = -1; //jを-1にしてもう一度チェックしなおす準備
}
}
を使うことで10個違う数がそろうと考えたのですが・・・
Re: リスト構造
Posted: 2016年12月21日(水) 00:20
by みけCAT
重複チェック中に毎回numの変えてしまっているのがダメですね。
num = rand() % 10 + 1;をfor (i = 0; i < 10; i++) {の直後に移動し、その1個の値がどのa[j]とも被っていないことを確認しなければいけません。
移動の対象はprintf("処理前:");の前にあるnum = rand() % 10 + 1;です。 (きちんと指定していませんでしたね、すみません)
前はきちんと重複チェック中は重複が見つかったときのみnumを変えていたのに、「余計な変更」をしてしまいましたね。
Re: リスト構造
Posted: 2016年12月21日(水) 00:30
by 桜並木
やっと正常に動作をすることが出来ました。ありがとうございます。
コード:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct list//リスト構造体:
{
int data; //リストのデータ
struct list *next;//次のデータへのポインタ:リスト・チェイン
};
// リスト構造の先頭に新しいデータを追加する関数
struct list *add_list(int x, struct list *head)//新データ:新次のデータへのポインタ
{
struct list *new_head; //次のデータへのポインタ
new_head = (struct list *)malloc(sizeof(struct list));//メモリー確保
//ポインタのつなぎ換え
new_head->data = x; //リストにデータを登録
new_head->next = head;// 今までの先頭ポインタを次ポインタに
return new_head; //新しい先頭ポインタ
}
// リスト構造を表示する関数
void show_list(struct list *head)
{
if (head == NULL) // NULLポインタだったら改行のみ表示
{
printf("\n\n");
}
else {
printf("%d", head->data);//データ表示
show_list(head->next); //再帰呼び出し
}
}
int main(void)
{
int i, j = 0, k = 0, count = -1;
struct list *head1;//リスト1 処理前のリスト
struct list *head2;//リスト2 前と後の中間のリスト
struct list *head3;//リスト3 処理後のリスト
int num;
int a[10]; //ここに出てきた乱数を格納する
head1 = NULL;
head2 = NULL;
head3 = NULL;//head2と同じ
head1 = add_list(10, head1);//次ポインタの移動
head1 = add_list(9, head1);
head1 = add_list(8, head1);
head1 = add_list(7, head1);
head1 = add_list(6, head1);
head1 = add_list(5, head1);
head1 = add_list(4, head1);
head1 = add_list(3, head1);
head1 = add_list(2, head1);
head1 = add_list(1, head1);
head2 = head1;//リスト2次ポインタをリスト1次ポインタにする
//リスト2=リスト1
srand((unsigned)time(NULL)); //乱数
//1~10までの数字なので10で割った余り+1
printf("処理前:");
show_list(head1); //リスト1表示
show_list(head2);////////////////check表示
printf("処理後:");
for (i = 0; i < 10; i++) { //10個のデータを扱うので10回する
num = rand() % 10 + 1;
for (j = 0;j <= k;j++) { //一度使用した数字を使わないようにするためのfor文
if (num == a[j]) { //処理の条件:numと格納した数字が同じ場合
num = rand() % 10 + 1;
j = -1; //jを-1にしてもう一度チェックしなおす準備
}
}
head3 = add_list(num, head3);///////check表示
//show_list(head3);/////////////check表示
a[k] = num; //使った数字をa[k]に格納する
k++; //kの値を増加させる
}
show_list(head3); //リスト3表示
}
Re: リスト構造
Posted: 2016年12月21日(水) 00:34
by みけCAT
桜並木 さんが書きました:やっと正常に動作をすることが出来ました。
運が悪かったですね。
せっかくj <kという正しい条件を書いていたのに、j <= kという間違った条件にする「余計な変更」が見られます。
その結果、初期化されていない自動変数の値(不定)を計算に使い、未定義動作を起こしてしまいます。
Re: リスト構造
Posted: 2016年12月21日(水) 00:45
by 桜並木
ご指導していただきありがとうございます。
言われるまで気づきませんでした。
コード:
for (i = 0; i < num_2; i++) { //10個のデータを扱うので10回する
num = rand() % num_2 + 1;
for (j = 0;j < k;j++) { //一度使用した数字を使わないようにするためのfor文
if (num == (p + j)) { //処理の条件:numと格納した数字が同じ場合
num = rand() % num_2 + 1;
j = -1; //jを-1にしてもう一度チェックしなおす準備
}
}
書き直しました。
Re: リスト構造
Posted: 2016年12月21日(水) 01:22
by みけCAT
num_2やpはもとのコードにはありません。どういうことでしょうか?
また、pがポインタまたは配列である場合、num == (p + j)という条件式は適切ではない可能性があります。
Re: リスト構造
Posted: 2016年12月21日(水) 08:37
by 桜並木
返信ありがとうございます。
仮に10個じゃなくて、リストの要素数をscanf入力する場合についてどうすればいいのかを考えていたので、誤ってそっちの方を送ってしまいました。
コード:
for (i = 0; i < 10; i++) { //10個のデータを扱うので10回する
num = rand() % 10 + 1;
for (j = 0;j < k;j++) { //一度使用した数字を使わないようにするためのfor文
if (num == a[j]) { //処理の条件:numと格納した数字が同じ場合
num = rand() % 10 + 1;
j = -1; //jを-1にしてもう一度チェックしなおす準備
}
}