C言語の課題・・・

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

C言語の課題・・・

#1

投稿記事 by 774 » 16年前

はじめまして、ここに始めて投稿するものです。

今日は学校からC言語の課題を出されたのですが・・・どうやってもうまくいきません。

C言語の課題の内容は連結リストを手入力で数値を入力して0を入力するまで入力し続けて、入力した順番から表示させるのですが。
「変数宣言」と「TO DOここに必要な処理を記述する」以外は変えてはいけない。
表示するループで最初に入力した数値を参照してポインタから次入力した数値につなげるようにするようにする。
最後入力したデータにNULLを入れるようにする。

下のソースが課題で貰ったソースを自分なりに作ったソースです
必要に応じて作った変数は
int型は「i」で、struct nodeは [*tow]です。
メモリをmallocで「starat」と「tow」の2つ作って
「start」を入力した後に「tow」を参照できるように最初に[tow]のメモリを作った後にstartを作れるようにして。
次に、最初に参照するstartをif文で囲って最初に参照するためだけなのでという条件にして[i++]をしてその後はif文を無視するようにしてtowだけで入力するようにしたのですが、実行すると最初に入力した数値が2回表示されて終わってします。

どうすれば入力した順に表示できるようにループを回らせるプログラムができるでしょうか・・・?
わがままな事を言いますが、できればこの形を残したままでできるようにしたいです・・・
C言語の知識はまだ約半年で、9月終わりごろに教科書として使っていたC言語の本を終わらせたばかりです。
よろしくお願いしますm( )m


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

/* 構造体の宣言 */
struct node
{
        int data;
        struct node *next;
};

int main(void)
{
        /* 変数宣言(必要に応じて増やす) */
        struct node *start, *p, *tow;
        int d, i = 0;

        /* リスト初期化 */
        start = NULL;

        /* データ入力 */
        printf("input Number : ");
        scanf("%d", &d);

        /* リスト作成 */
        while(d>  0)
        {


                /* TO DO ここに必要な処理を記述する */
                tow = malloc(sizeof(struct node));
                if(i==0)
                {
                        start = malloc(sizeof(struct node));
                        start->data = d;
                        start->next = tow;
			
			i++;
                }
               

                tow->data = d;
                tow->next = NULL;

		/* ここまで */

                /* データ入力 */
                printf("Input Number : ");
                scanf("%d", &d);
        }

        /* 出力 */
        printf("Result : ");
        for(p=start; p!=NULL; p=p->next)
        {
                printf("%d ", p->data);
        }
        printf("\n");

        return 0;
}

kazuoni

Re:C言語の課題・・・

#2

投稿記事 by kazuoni » 16年前

まずは原因から。
>実行すると最初に入力した数値が2回表示されて終わってします。
/* TO DO ここに必要な処理を記述する */
から見ていきます。

1、towで領域を構造体分確保
2、start(NULL)のアドレスをmallocで確保した領域のアドレスに変える
3、2で確保したstartの領域のdate,nextに値、アドレスをそれぞれ代入
4、1で確保したtowの領域のdate,nextに値、アドレスをそれぞれ代入
(3,4の代入するdateは同じもの)
5、「1と4」を0が入力されるまで繰り返す(iの条件より)

pを表示する時、どの順番に出力をしようとしているかわかりますか?
pはstartの先頭のアドレスを渡されているので
一番最初の2で確保したstart->dateから見に行きます。
次は一番最初の1で確保された「構造体のオブジェクト」を指しています。
おそらくここで構造体のメンバであるtow->dateを見に行ってほしいのですよね?
確かに次に見に行くのはtow->dateですが
次はtow->next
です。(おそらく)
tow->nextはNULLと定義していますのでこの時点で見に行くのを終了します。

kazuoni

Re:C言語の課題・・・

#3

投稿記事 by kazuoni » 16年前

解決策の一例です。
/* 変数宣言(必要に応じて増やす) */

struct node *start,        /*ノードをまとめるもの*/
            *p,            /*出力するにあたってのもの(?)*/
	   *num_last,     /*NULLの前のノードを指す*/
	   *ptr_num_last, /*NULLのノード指す*/
	   *ptr;          /*新しい領域のアドレスを指す*/
int d;

//省略

/* リスト作成 */

while(d>0)
{

/* TO DO ここに必要な処理を記述する */

if(start==NULL)//もし何もノードが入っていなかったら
{
	start = (node *)malloc(sizeof(struct node));
	start->data=d;//数値代入
	start->next=NULL;
}

else//一つでもノードが入っていたら

{				
	num_last = ptr_num_last = start;//まずstartの先頭のアドレスをそれぞれに渡す
	while(ptr_num_last!=NULL)   //このwhileでNULL一個前のノードのアドレスをnum_lastへ代入する
	{
		num_last = ptr_num_last;
		ptr_num_last = ptr_num_last->next;
	}
	ptr = num_last->next = (node *)malloc(sizeof(struct node));//新しく割り振られたアドレスをNULLの代わりに代入し、
                                                                    //そのアドレスをptrに代入
	ptr->data = d;//数値代入
	ptr->next = NULL;
	/*例えばA→B→NULLで新しく確保したものがC→NULLだったら
	A→B→C→NULLになります。
	出力する際はAからですので、古いものから出力されるようになります。*/
}

/* データ入力 */
printf("Input Number : ");
scanf("%d", &d);
}
//省略
省略部分は774さんのコードのままです。
やはり理解するには紙に書いてやってみるのが一番だと思います。
まずNULLから初めて、一回目の代入、二回目の代入と。
順に追っていけば理解できるはずです。

出力がp=startってのがやっかいですね。
普通の線形リストだと古いものはnextのほうに代入されて
出力は新しいもの順に出力されます。(本とかに乗ってるのは)

本来ならばこんなにややこしくしないでもいいかと。。
(効率の悪いプログラムの可能性大です。簡単にして使ってくださいw)

774

Re:C言語の課題・・・

#4

投稿記事 by 774 » 16年前

で・・できました。ありがとうございます!
紙に書く・・・いつも心がけるように心に刻みつけようと思います
tow->nextで止めていた・・・ということでいいのでしょうか?
まだまだ自分の未熟さをかみ締めます。
これからもがんばっていこうと思います。
ありがとうございました!

kazuoni

Re:C言語の課題・・・

#5

投稿記事 by kazuoni » 16年前

>tow->nextで止めていた・・・ということでいいのでしょうか?
結果はそうです。
774さんのコードでは
towは全くつながっておらず、バラバラの場所に領域を確保しているだけでした。
今回はstartを見たので最初のstartからtow->nextで終わりでした。

線形リストは自分で組んでみないとなかなか理解できないです。。
今回は末尾にノードを挿入していきました。
先頭にノードを挿入、ノードとノードの間にノードを挿入、配列を用いての線形リストなど
いろいろ工夫すると理解度が深まる気がします。

がんばってください。

kz

Re:C言語の課題・・・

#6

投稿記事 by kz » 16年前

私も作ってみました。
変数の変更を何もしない場合の例です。
    /* TO DO ここに必要な処理を記述する */
if(start==NULL){
	start = (node *)malloc(sizeof(struct node));	//スタートのメモリを確保
	start->data = d;
	tow =start;	//ループのポインタをスタートにする
}
else{
	tow->next= (node *)malloc(sizeof(struct node)); //移動先のメモリを確保
	tow=tow->next;				  //ポインタを移動
	tow->data = d;
	tow->next=NULL;
}
    /* ここまで */
towをどこで連結させるかが一番の重要な点ですね。
メモリを確保した場所へポインタを動かすのを意識すると良いと思います。
あとこれって学校の課題としてはまずいと思いますよ。
メモリの開放部分がベースで書かれてませんが、解放についての勉強は視野に入っていないのでしょうか

フリオ

Re:C言語の課題・・・

#7

投稿記事 by フリオ » 16年前

 
 "tow"と"i"は必要ないです。
if(!start){
	if(!(start = malloc(sizeof(struct node)))) exit(1);
	p = start;
}
else{
	if(!(p->next = malloc(sizeof(struct node)))) exit(1);
	p = p->next;
}
p->data = d;
p->next = NULL;
 

774

Re:C言語の課題・・・

#8

投稿記事 by 774 » 16年前

kazuoni様
towがバラバラ・・・最初から連結が途切れていたんですね・・・
線形リストを調べて見たら組み方が沢山在る事に気がつきました。
どんな状態の物でも組めるように少しずつ勉強して行こうと思います。

kz様
・・・こ、こんなに簡単に・・・
自分のプログラムの組み方に少し疑問が出てきました・・・
メモリとポインタの動かし方がコツ・・・と言うことですね。
えっとfree()ですよね・・・
これは学校の授業の時でも必ず付けろ言われました。
ですが・・・プリントとして配られた時 TO DO と変数を必要な時増やす以外ソースは書かれていてfree()が元々書いて在りませんでした。
whileの中でfree()を使うと今まで確保したメモリも消えてしまうと思うので・・・
多分、今回は数値を数回入力して入力順に表示すると言う課題なので、使うメモリを確保する量がが少なくて、プログラムを終了するとメモリも自動的に開放される(でしたっけ・・・?)のであえて先生はつけなかったのだと思います。
あと・・・メモリを確保する時に使う数は人によって違うからと言うこともありえると思います・・・
間違っている考えかもしれませんが・・・;
とりあえずfree()の事は学校で教わりました。

フリオ様
iもtowも使わないでできる・・・
こういう組み方が在るんですね・・!
えっと・・exit(1);やif(…)って言うのを使った事が無いのですが・・・
if(!(start = malloc(sizeof(struct node)))) exit(1);
はstartにメモリを確保した時にNULL以外の値の時に強制終了すると言うことでしょうか・・・?
あまりC言語の知識が無くてすみません・・・;

kazuoni

Re:C言語の課題・・・

#9

投稿記事 by kazuoni » 16年前

kzさんのおっしゃる通り、やはりメモリ解放は必要ですよね。
これからプログラムを書くときに忘れなければいいんですけどね^^;

>if(!(start = malloc(sizeof(struct node)))) exit(1);
>はstartにメモリを確保した時にNULL以外の値の時に強制終了すると言うことでしょうか・・・?

逆ですね。
mallocで確保したものをstartに代入する際に、もし確保に失敗したら
startにNULLが入り、論理否定演算子によって1になります。
ゆえに
メモリを確保する際、確保失敗なら異常終了する
だと思います。

閉鎖

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