連結リストの要素の挿入のプログラムについて

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

連結リストの要素の挿入のプログラムについて

#1

投稿記事 by Ken » 14年前

次のプログラムで、実行したら思っているように実行できません。どこを直せばよいか教えてください。

情報を追加・内容を表示・終了とうい項目が2連続で出てしまいます。
そこを直したいので教えてください。



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

typedef struct friend{
int ID;
struct friend *next;
}friend;
friend header;

void add(void)
{
struct friend* p, *q, *newcell;
int ID;

puts( "追加する要素の値を入力して下さい" );
scanf( "%d", &ID );

p = header.next; /* 先頭要素の次の要素のアドレス */
q = &header; /* 先頭要素のアドレス */
while( p != NULL && ID > p->ID )
{
q = p;
p = p->next;
}

newcell = malloc( sizeof(struct friend) );
if( newcell == NULL )
{
puts( "メモリ不足" );
return;
}

newcell->ID = ID;
newcell->next = p;
q->next = newcell;
}


/* 線形リストの内容を表示する */
void show(void)
{
struct friend *p;

for( p=header.next; p!=NULL; p=p->next )
{
printf( "%d\n", p->ID );
}
}


int main(void)
{
char command;

header.next = NULL;

do
{
puts( "情報を追加:1" );
puts( "内容を表示:2" );
puts( "終了:0" );
scanf( "%c", &command );

switch( command )
{
case '1': /* 追加 */
add();
break;
case '2': /* 表示 */
show();
break;
case '0': /* 終了 */
break;
}

puts( "" );
fflush( stdin );

}while( command != 'q' );

return 0;
}

Wings

Re:連結リストの要素の挿入のプログラムについて

#2

投稿記事 by Wings » 14年前

プログラムを見てみて、問題があるところは...

switch( command )
{
case '1': /* 追加 */
add();
break;
case '2': /* 表示 */
show();
break;
case '0': /* 終了 */
break;
}

このswitchの case '0': のときプログラムを終了させるつもりだったのでは
ないですか?

プログラムを終了させるのなら、case '0': で return をするとか、 exit を実行
するとかすれば良いと思います。

ゆーずぃ

Re:連結リストの要素の挿入のプログラムについて

#3

投稿記事 by ゆーずぃ » 14年前

色々と突っ込みどころはありますが・・・
どう動かしたくて何をやったら表示が2回出てしまったのかの情報をお願いします。
あと、<pre>で囲んで字下げもお願いします。

ところで0で終了とあるのに実際はqで終了というのは一体?
Wingsさんの言うように、return やexitでないと
breakではcase文から脱出するだけでwhileループからは脱出できません。
試しに以下のソースのaの値を1と2で変えて実行してみて下さい。1はwhileから抜けるつもりで書いたbreak文です。これでは抜けられないことが分かると思います。
int main(void){

    int a = 1;        //ここを変える
    while(1){
        switch (a){
            case 1 :
                break;            
            case 2 :    
                printf("即終了です %d",a);
                getchar(); 
                return 0;
        }
    printf("ループ脱出してないよ %d",a);
    getchar();
    }
    return 0;
}
ただループから抜けたいだけならif文でbreakしないとダメです。こんな感じで。
int main(void){

    int a = 2;
    while(1){
        if(a==2)break;    
    }
    puts("ループ脱出してます");
    getchar();
    return 0;
}

あとは何か意図があるのならいいのですが、
typedef struct{
    int ID;
    friend *next;
}friend;
とした方が分かりやすいし書きやすいし良いと思います。

初級者

Re:連結リストの要素の挿入のプログラムについて

#4

投稿記事 by 初級者 » 14年前

>ゆーずぃさん

>friend *next;

の時点で friend が何者であるかが解決できていないので、
まずいんじゃないですか?

アビゲイル

Re:連結リストの要素の挿入のプログラムについて

#5

投稿記事 by アビゲイル » 14年前

都市伝説と思ってたけど、未定義の動作に引っ掛かったとか。
こいつ→fflush( stdin );

それ消して、こうして見るとか
scanf( "%c%*s", &command );

ゆーずぃ

Re:連結リストの要素の挿入のプログラムについて

#6

投稿記事 by ゆーずぃ » 14年前

>初級者さん
その通りでした。自己参照ということを失念;申し訳ないです。下のではその辺の宣言も修正してます。

ところで私のvc++コンパイラだと引っかかりすぎて全くコンパイル出来なかったんですが、gccでも使ってコンパイルしてるんですか?(;´・ω・)あと、friendはC++の予約語なので移植性などを考えても余り使わない方がいいかも。んで、以下修正ソースです。
#include <stdio.h>
#include <stdlib.h>

typedef struct node sNode;

struct node{
    int ID;
    sNode *next;
};
sNode header;

void add(void)
{
    sNode *p, *q, *newcell;
    int ID;

    puts( "追加する要素の値を入力して下さい" );
    scanf( "%d", &ID );

    p = header.next; /* 先頭要素の次の要素のアドレス */
    q = &header; /* 先頭要素のアドレス */
    while( p != NULL && ID > p->ID )
    {
        q = p;
        p = p->next;
    }

    newcell = (sNode*)malloc( sizeof(sNode) );
    if( newcell == NULL )
    {
        puts( "メモリ不足" );
    return;
    }

newcell->ID = ID;
newcell->next = p;
q->next = newcell;
}


/* 線形リストの内容を表示する */
void show(void)
{
    sNode *p;

    for( p=header.next; p!=NULL; p=p->next )
    {
        printf( "%d\n", p->ID );
    }
}

int main(void)
{
    char command;

    header.next = NULL;

    do
    {
        puts( "情報を追加:1" );
        puts( "内容を表示:2" );
        puts( "終了:0" );
        scanf( "%c", &command );

        if(command == '0')
            break;

        switch( command )
        {
            case '1': /* 追加 */
                add();
                break;
            case '2': /* 表示 */
                show();
                break;
        }
        puts( "" );
        while(getchar() != '\n');    //バッファクリア
    }while(1);

return 0;
}
アビゲイルさんの言うようにfflushには都市伝説があるので使わない方向にしました。

Ken

Re:連結リストの要素の挿入のプログラムについて

#7

投稿記事 by Ken » 14年前

ありがとうございました。
もしここに新しい要素”age”を入れるのならば、どのように加えたらいいのしょうか?

ゆーずぃ

Re:連結リストの要素の挿入のプログラムについて

#8

投稿記事 by ゆーずぃ » 14年前

それは要素を残したままってことですよね?

あー、説明しようと思ったけどそっちの方がめんどくさいので作っちゃいましたw
前のプログラムと今回のプログラムを比べてどう違うのか確認して下さい。一応見るポイントとしては

1.構造体に年齢変数を作る
2.列挙体を利用してなんとなく分かりやすくしてみた
3.メイン関数内のスイッチ文に年齢を選ばれた時の処理を追加(でも使う関数はadd)
4.addに引数を持たせた。(スイッチの条件と同じ値)
5.その引数によってadd内の代入先を変更。これによって 3.が可能になる
5.5 代入先に選ばれなかった方には念の為0を代入
6.show関数にshowする内容を追加(年齢)
7.飽きた、ネル
#include <stdio.h>
#include <stdlib.h>

typedef struct node sNode;

typedef enum{
    END ,
    ELEMENT ,
    AGE ,
    SHOW ,
}eState;



struct node{
    int ID;
    int Age;
    sNode *next;
};
sNode header;


void add(int StateNo)
{
    sNode *p, *q, *newcell;
    int State;

    puts( "追加する要素の値を入力して下さい" );
    scanf( "%d", &State );

    p = header.next; /* 先頭要素の次の要素のアドレス */
    q = &header; /* 先頭要素のアドレス */
    while( p != NULL && State > p->ID )
    {
        q = p;
        p = p->next;
    }

    newcell = (sNode*)malloc( sizeof(sNode) );
    if( newcell == NULL )
    {
        puts( "メモリ不足" );
    return;
    }
    switch (StateNo){
        case ELEMENT:
            newcell->ID = State;
            newcell->Age = NULL;
            break;
        case AGE:
            newcell->Age = State;
            newcell->ID = NULL;
            break;
    }
newcell->next = p;
q->next = newcell;
}


/* 線形リストの内容を表示する */
void show(void)
{
    sNode *p;

    for( p=header.next; p!=NULL; p=p->next )
    {
        printf( "要素:%d 年齢:%d\n", p->ID, p->Age );
    }
}

int main(void)
{
    int command;

    header.next = NULL;

    do
    {
        puts( "情報を追加:1" );
        puts( "年齢を追加:2" );
        puts( "内容を表示:3" );
        puts( "終了:0" );
        scanf( "%d", &command );

        if(command == END)
            break;

        switch( command )
        {
            case ELEMENT: /* 追加 */
            case AGE:
                add(command);
                break;
            case SHOW : /* 表示 */
                show();
                break;
        }
        puts( "" );
        while(getchar() != '\n');    //バッファクリア
    }while(1);

return 0;
}
因みにメイン関数内のキーボード受付をintにしました。char型だと面倒だしcharにしておく必要も分からなかったので…
ただコピぺするだけじゃなくて理解してのコピぺにして下さいね。質問があれば質問出来るうちにした方がいいです。

Ken

Re:連結リストの要素の挿入のプログラムについて

#9

投稿記事 by Ken » 14年前

実行結果がうまくいきませんでした。
やりたいのは、”情報を追加”を選択すると、IDとAGEの両方の情報を同時に入力できるようにしたいです。

ゆーずぃ

Re:連結リストの要素の挿入のプログラムについて

#10

投稿記事 by ゆーずぃ » 14年前

実行結果が上手くいかなかったというのは、やりたいことができなかった、ということですか?それとも不具合がありました?それによって修正どころが変わってくるんで…

Ken

Re:連結リストの要素の挿入のプログラムについて

#11

投稿記事 by Ken » 14年前

やりたいことができませんでした。
よろしくお願いします。

ゆーずぃ

Re:連結リストの要素の挿入のプログラムについて

#12

投稿記事 by ゆーずぃ » 14年前

はてさてこんな感じでしょうか。
#include <stdio.h>
#include <stdlib.h>

typedef struct node sNode;

typedef enum{
    END ,
    ELEMENT ,
    SHOW ,
}eState;

struct node{
    int ID;
    int Age;
    sNode *next;
};
sNode header;

void add(int StateNo)
{
    sNode *p, *q, *newcell;
    int i,State[2];
    char *s        = "追加する要素の値を入力して下さい。";
    char *s2    = "年齢を入力して下さい。";
    char *StArray[2] = {s, s2};

    /*    要素の取得    */
     for(i=0; i<2;i++){
        puts(StArray);
        scanf( "%d", &State );
        while(getchar() !='\n');
    }

    p = header.next; /* 先頭要素の次の要素のアドレス */
    q = &header; /* 先頭要素のアドレス */
    while( p != NULL && State[0] > p->ID )
    {
        q = p;
        p = p->next;
    }

    newcell = (sNode*)malloc( sizeof(sNode) );
    if( newcell == NULL )
    {
        puts( "メモリ不足" );
    return;
    }
    newcell->ID = State[0];
    newcell->Age = State[1];

    newcell->next = p;
    q->next = newcell;
    puts("情報を登録しました");
}

/* 線形リストの内容を表示する */
void show(void)
{
    sNode *p;

    for( p=header.next; p!=NULL; p=p->next )
    {
        printf( "要素:%d 年齢:%d\n", p->ID, p->Age );
    }
}

int main(void)
{
    int command;

    header.next = NULL;

    do
    {
        puts( "情報を追加:1" );
        puts( "内容を表示:2" );
        puts( "終了:0" );
        scanf( "%d", &command );
        while(getchar() != '\n');    //バッファクリア

        if(command == END)
            break;

        switch( command )
        {
            case ELEMENT: /* 追加 */
                add(command);
                break;
            case SHOW : /* 表示 */
                show();
                break;
        }
        puts( "" );
    }while(1);
return 0;
}

Ken

Re:連結リストの要素の挿入のプログラムについて

#13

投稿記事 by Ken » 14年前

これを実行したところ、情報を追加を選んでもIDやAGEを入力できないんですが・・・

初級者

Re:連結リストの要素の挿入のプログラムについて

#14

投稿記事 by 初級者 » 14年前

「人に作ってもらったものを動かしてるだけ」状態になってますよ。

それでいいんですか?

ゆーずぃ

Re:連結リストの要素の挿入のプログラムについて

#15

投稿記事 by ゆーずぃ » 14年前

>初級者さん
それは仕方ないところはあります。なんせこの掲示板が宿題丸投げを許しているんですからw 期限が近く切羽詰まっていることもあるでしょう。教える側としてはやっぱりちゃんと身に付けて欲しいですけど、まぁそこは人次第ですから。

>Kenさん
多分新しいのをコンパイル出来てないんだと思います。私の環境ではちゃんと動くのでその対処はしようがないですねぇ(;^ω^)コンパイラは何を使ってます?ここまで出来てるので、VC++ならステップ実行でどこがおかしいのか分かると思いますよ。

初級者

Re:連結リストの要素の挿入のプログラムについて

#16

投稿記事 by 初級者 » 14年前

質問者さんの投稿には、「宿題」とか「期限」とかいう単語は出てきてません。

まあ、質問者さんが「自分のプログラミング能力がアップしなくていい」と
思っているんなら別にどうでもいいですが、
そうでないんなら、「まずは自分の脳みそをフル回転させてみては?」というのが
あたしの考え方です。

Ken

Re:連結リストの要素の挿入のプログラムについて

#17

投稿記事 by Ken » 14年前

すいません課題の提出の期限が月曜日までなので早く完成させなくてはいけないので丸投げさせてください。


僕がしたいことは、
struct node{
int ID;
int Age;
sNode *next;
};
という風に要素を1つ加えたらそのほかのところをどのように直したらいいのでしょうか?

ゆーずぃ

Re:連結リストの要素の挿入のプログラムについて

#18

投稿記事 by ゆーずぃ » 14年前

仕様によるのですが…
拡張性等を配慮してある程度動的に要素を追加できるように、というのであればソースは膨れ上がります。ですが、学校の宿題で要素が増える度に手でソースをいじればいい程度ならばadd関数に入っているStructの配列を増やし、その増やした配列の中身を新しい要素に割り当てるという処理を追加すればいいです。あと、show関数でその分の表示項目も増やしてください。今は携帯で見ているのでそれくらいしか。

ところで、私のソースで実行できないと言っていましたが、それはコンパイルできないのか、それとも思った動作をしないのかのどれでしょう?それによって、コンパイルできないならエラーメッセージを、思ったように動かないのならどこの表示までは出てどこがどうできないのかを教えてもらえれば書き換えも可能です。

Ken

Re:連結リストの要素の挿入のプログラムについて

#19

投稿記事 by Ken » 14年前

add関数に入っているStructの配列を増やし、その増やした配列の中身を新しい要素に割り当てるという処理を追加して、show関数でその分の表示項目も増やすのにどうすればいいのか分からないんです。

ゆーずぃさんのプログラムをコンパイルしたところコンパイルにエラーはないのですが、
思っている動作をしません。

情報を追加:1
内容を表示:2
終了:0   

というところで1を選んでも何も起きません。
そこからIDとAGEの値を入力したいのですが・・・

初級者

Re:連結リストの要素の挿入のプログラムについて

#20

投稿記事 by 初級者 » 14年前

まさかとは思いますが、1を選んだ後、Enterキーを押していない、というオチではないですよね?

ゆーずぃ

Re:連結リストの要素の挿入のプログラムについて

#21

投稿記事 by ゆーずぃ » 14年前

…まさか…それは無いと信じたい…(;^ω^)でも実際に貼り付けたソースをコピーしてコンパイルしても正常に動くのでそれが一番可能性高いかもしれませんね…wというわけでkenさん、1を入力した後エンター押してます?押していればそのあとどんな文字が出ますか?1、2、0、それぞれのボタンの動きを試してみて下さい。

閉鎖

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