リスト構造

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

リスト構造

#1

投稿記事 by 桜並木 » 8年前

学校から出された課題がわからなかったので質問させていただきます。
課題は、「リストの要素(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);
}

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

Re: リスト構造

#2

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

桜並木 さんが書きました:

コード:

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から始まるリストを直接書き換えてしまうのもいけません。
簡単なのは呼び出し元で出力用のリストを別に確保し、渡すことでしょう。
桜並木 さんが書きました:

コード:

void main()
main関数の戻り値がint型でないのは、処理系依存です。
こう書かないとなぜか減点される、宗教上の理由などの特別な理由が無いのであれば、標準に含まれるint main(void)を用いるべきです。
桜並木 さんが書きました:

コード:

	head1 = (struct list *)malloc(sizeof(struct list));
	head2 = (struct list *)malloc(sizeof(struct list));

	head1 = NULL;
	head2 = NULL;
せっかく確保したメモリへのアドレスをすぐに投げ捨て、メモリリークを起こしています。
どうせ使わないメモリは確保しなくていいでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

桜並木

Re: リスト構造

#3

投稿記事 by 桜並木 » 8年前

ご指導していただきありがとうございます。
言われたことを自分なりに解釈したつもりだったのですが、またプログラムが停止してしまいました。
どこが間違っているのか教えていただけないでしょうか?

コード:

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

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

Re: リスト構造

#4

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

main関数の型とメモリリークは直したようですが、肝心の範囲外アクセスを修正しないどころか増やしてしまいましたね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

桜並木

Re: リスト構造

#5

投稿記事 by 桜並木 » 8年前

返信ありがとうございます。
自分の知識不足ということもあり、範囲外アクセスがよくわかりません。本当に申し訳ないのですが、範囲外アクセスについて教えていただけないでしょうか?
また前のご指導で1要素しか確保していないといわれたので、mallocで要素を確保すればいいと考えたのですが違うのでしょうか?その点も合わせて教えていただけないでしょうか?

metaphor

Re: リスト構造

#6

投稿記事 by metaphor » 8年前

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

続行するには何かキーを押してください . . .

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

Re: リスト構造

#7

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

random()が呼ばれるたびにsrand((unsigned)time(NULL));を呼んでいるのも良くなさそうですね。
(暗号などで決まった乱数列が欲しいのではなく)単に適当な乱数が欲しいのであれば、
srand()はプログラムの実行開始時に1度だけ呼び出すのがいいでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

桜並木

Re: リスト構造

#8

投稿記事 by 桜並木 » 8年前

返信ありがとうございます。
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表示
}


metaphor

Re: リスト構造

#9

投稿記事 by metaphor » 8年前

アルゴリズムが間違っているようです。

コード:

	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: リスト構造

#10

投稿記事 by 桜並木 » 8年前

返信ありがとうございます。
もう一度考え直して、違う書き方にしました。
プログラムを実行すると結果が、処理前: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: リスト構造

#11

投稿記事 by 桜並木 » 8年前

コード:

	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のうち間違いです。すいません。
結果は変わらず動きませんでした。

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: リスト構造

#12

投稿記事 by usao » 8年前

オフトピック
64行目以降の処理で,大元のリスト(head1かな)が全く参照されてないように見えるけど,そういう方法で良いのだろうか?

桜並木

Re: リスト構造

#13

投稿記事 by 桜並木 » 8年前

返信ありがとうございます
問題には特に条件がなかったので、大丈夫かなっと思い作りました。

metaphor

Re: リスト構造

#14

投稿記事 by metaphor » 8年前

取り敢えずこうなった。

コード:

#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: リスト構造

#15

投稿記事 by 桜並木 » 8年前

返信ありがとうございます。

コード:

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の値を増加させる
	}
この部分のどこかに原因があるのは分かるのですが、どこが間違っているのかわかりません。
どの部分が、間違っているのかを教えてくれないでしょうか?

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

Re: リスト構造

#16

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

パッと見の印象では、countに0以外の値が入らないのは怪しいですね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: リスト構造

#17

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

jのループの上限であるcountが0固定なので、a[0]との重複のみがチェックされ、しかも重複していない時はループ中でnumが更新されないので、「最初の要素」と「それ以外の要素」にそれぞれ同じ値、かつグループ間では異なる値が割り当てられるようですね。
オフトピック
リストの要素とは関係ない1~10を並べ替えている(?)ようだが、リストの要素も1~10であり、問題文にも書かれている1~10を配置しているので問題ないのかなあ…。
まあ、ここの改善は今の仕様(リストとは関係なく1~10を並べる)でうまく動くようになってからでもいいですよね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

桜並木

Re: リスト構造

#18

投稿記事 by 桜並木 » 8年前

返信ありがとうございます。
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 の改善は、うまく動けるようになったらにします。

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

Re: リスト構造

#19

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

桜並木 さんが書きました: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が更新されるようにするといいでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

metaphor

Re: リスト構造

#20

投稿記事 by metaphor » 8年前

これを試して何か気がつかない。どうもよく分からない?

コード:

    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表示
}

metaphor

Re: リスト構造

#21

投稿記事 by metaphor » 8年前

10回では無理な気がする。10個違う数がそろうまで繰り返すことが必要なのでは?

metaphor

Re: リスト構造

#22

投稿記事 by metaphor » 8年前

あ、違うjループの判定がおかしいのかな?

桜並木

Re: リスト構造

#23

投稿記事 by 桜並木 » 8年前

返信ありがとうございます。
みけ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個違う数がそろうと考えたのですが・・・

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

Re: リスト構造

#24

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

重複チェック中に毎回numの変えてしまっているのがダメですね。
num = rand() % 10 + 1;をfor (i = 0; i < 10; i++) {の直後に移動し、その1個の値がどのa[j]とも被っていないことを確認しなければいけません。
移動の対象はprintf("処理前:");の前にあるnum = rand() % 10 + 1;です。 (きちんと指定していませんでしたね、すみません)
前はきちんと重複チェック中は重複が見つかったときのみnumを変えていたのに、「余計な変更」をしてしまいましたね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

桜並木

Re: リスト構造

#25

投稿記事 by 桜並木 » 8年前

やっと正常に動作をすることが出来ました。ありがとうございます。

コード:

#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表示
}

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

Re: リスト構造

#26

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

桜並木 さんが書きました:やっと正常に動作をすることが出来ました。
運が悪かったですね。
せっかくj <kという正しい条件を書いていたのに、j <= kという間違った条件にする「余計な変更」が見られます。
その結果、初期化されていない自動変数の値(不定)を計算に使い、未定義動作を起こしてしまいます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

桜並木

Re: リスト構造

#27

投稿記事 by 桜並木 » 8年前

ご指導していただきありがとうございます。
言われるまで気づきませんでした。

コード:

	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にしてもう一度チェックしなおす準備
			}
		}
書き直しました。

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

Re: リスト構造

#28

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

num_2やpはもとのコードにはありません。どういうことでしょうか?
また、pがポインタまたは配列である場合、num == (p + j)という条件式は適切ではない可能性があります。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

桜並木

Re: リスト構造

#29

投稿記事 by 桜並木 » 8年前

返信ありがとうございます。
仮に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にしてもう一度チェックしなおす準備
            }
        }

閉鎖

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