C言語関係掲示板

過去ログ

No647 双方向リストの並べ替え

[戻る] [ホームページ]
No.7031

双方向リストの並べ替え
投稿者---レミ(2003/06/02 22:03:49)


双方向リストのバブルソートをしたいのですが
二つの文字列の入れ替えが特にわかりません
8文字の文字列を幾つか読み込んで、それをソートしたいのですがうまく行きません。
ただ単に読み込んで(ソートしない)出力はできました。
bsort関数で並べ替えが起こりません。アドレスを入れ替えているつもりなんですが、↓の方法だと入れ替わっていないのでしょうか?

例)文字列
zzzzzzzz   aaaaaaaa
aaaaaaaa   aaaabbbb
bbbbbbbb   bbbbbbbb
cccccccc -> cccccccc
yyyyyyyy   yyyyyyyy
aaaabbbb   zzzzzzzz

OS:WindowsXP Pro
開発環境:VisualC++6.0(SP5)

typedef struct field{
        char a_field[9];
        struct field *next;
        struct field *prev;
} Field;

void filein( FILE *fp)
{
        Field *new_line;
        Field *top =NULL;
        Field *last =NULL;
        int num=0;

        new_line = (Field*)malloc(sizeof(Field));

        // 8byte読み込む
        while( ( new_line=read_line(fp)) != NULL){

                if( top == NULL){
                        new_line->next = NULL;
                        new_line->prev = NULL;
                        top = last = new_line;
                }
                else{
                        new_line->next = NULL;
                        new_line->prev = last;
                        last->next = new_line;
                        last = new_line;
                }
                num++;
        }

        new_line=last;
        int i=1;
        for( int s=0; s<num-i; i++){
                int k = strcmp(new_line->a_field, new_line->prev->a_field);
                if( k<0){
                        // 文字列の入れ替え
                        bsort( &new_line->prev->prev, &new_line->prev, &new_line, &new_line->next);
                }
                new_line = new_line->prev;
                printf("num-i: %d\n", num-i);
        }

        output(top);    // 出力

        finalize(top);  // メモリの解放
}

void bsort( Field **data1, Field **data2, Field **data3, Field **data4)
{
        Field *tmp1, *tmp2, *tmp3;

        tmp1 = *data1;
        tmp2 = *data2;
        tmp3 = *data3;

        (*data1)->next = *data3;

        (*data3)->prev = tmp1;
        (*data3)->next = *data2;

        (*data2)->prev = tmp3;
        (*data2)->next = *data4;
        
        (*data4)->prev = tmp2;
}



No.7038

Re:双方向リストの並べ替え
投稿者---TDa(2003/06/02 23:01:31)


ソースを見ましたが謎な関数、謎な変数だらけですよ。ついでにCではエラーにな
る書き方が散在しています。

少なくともコンパイルできるもの、ついでに言えばテストドライバ用のmain位は
つけましょう。そうすることによって問題の絞り込みもできるわけですから。

ついでに要求仕様を満たすので有ればリスト自体はそのままで文字列のみを
入れ替えるのが楽です。

No.7041

Re:双方向リストの並べ替え
投稿者---とおりすがり(2003/06/02 23:15:22)


    for( int s=0; s<num-i; i++){
        int k = strcmp(new_line->a_field, new_line->prev->a_field);
        if( k<0){
            // 文字列の入れ替え
            bsort( &new_line->prev->prev, &new_line->prev, &new_line, &new_line->next);
        }
        new_line = new_line->prev;
        printf("num-i: %d\n", num-i);
    }

リストのつなぎ換えの部分はめんどくさかったので(ヾ(・・;)ォィォィ)見ていませ
んがforループが1回では一番小さな文字列が先頭に来るだけでは?
2番目以降の文字列も並べ替えるループが無ければ・・・

No.7042

Re:双方向リストの並べ替え
投稿者---レミ(2003/06/03 01:15:31)


TDaさん、とおりすがりさん、お返事ありがとうございます

>んがforループが1回では一番小さな文字列が先頭に来るだけでは?
>2番目以降の文字列も並べ替えるループが無ければ・・・

たしかに、勉強不足でした

↓がソース全部です。
コンパイルエラーは出ないはずですが、
実行すると無限ループになってしまいます。

>ついでに要求仕様を満たすので有ればリスト自体はそのままで文字列のみを
>入れ替えるのが楽です。

文字列の入れ替えは、アドレスの交換でしたいと思っています。
よろしくお願いします

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

#define LINE_SIZE 3

typedef struct field{
	char a_field[9];
	struct field *next;
	struct field *prev;
} Field;

void filein( FILE*);
Field* read_line( FILE*);
void finalize( Field*);
void output( Field*);
void bsort( Field**, Field**, Field**, Field**);

int main( int argc, char **argv)
{
	FILE *fp0;

	if( argc == 1){
		printf("入力ファイル名がありません\n");
		exit(0);
	}
	else{	// argc >= 2 (ファイル指定あり)

		//	入力ファイルを開く
		if( ( fp0 = fopen( argv[1], "r")) == NULL){
			printf("入力ファイル(%s)をオープンできませんでした.\n", argv[1]);
			exit(1);
		}
		printf("入力ファイル:  %s\n", argv[1]);

		if( argc == 2){
			filein( fp0);	// fileから読み込む
		}
		else{
			printf("引数が多すぎます\n");
			exit(1);
		}
	}

	fclose(fp0);

	return 0;
}

void filein( FILE *fp)
{
	Field *new_line;
	Field *top =NULL;
	Field *last =NULL;
	int num=0;

	new_line = (Field*)malloc(sizeof(Field));

	// 8byte読み込む
	while( ( new_line=read_line(fp)) != NULL){

		if( top == NULL){
			new_line->next = NULL;
			new_line->prev = NULL;
			top = last = new_line;
		}
		else{
			new_line->next = NULL;
			new_line->prev = last;
			last->next = new_line;
			last = new_line;
		}
		num++;
	}

	new_line = last;
	int i=1;
	for(i=0; i<num-1; i++){
        for(int j=0; j<num-i-1; j++){
            int k = strcmp(new_line->a_field, new_line->prev->a_field);
			if( k<0){
				// ソート
				bsort( &new_line->prev->prev, &new_line->prev, &new_line, &new_line->next);
			}
			new_line = new_line->prev;
	//			printf("num-i: %d\n", num-i);
        }
		new_line = last;
    }
	output(top);	// 出力

	finalize(top);	// メモリの解放
}

void bsort( Field **data1, Field **data2, Field **data3, Field **data4)
{
	Field *tmp1, *tmp2, *tmp3;

	tmp1 = *data1;
	tmp2 = *data2;
	tmp3 = *data3;

	(*data1)->next = *data3;

	(*data3)->prev = tmp1;
	(*data3)->next = *data2;

	(*data2)->prev = tmp3;
	(*data2)->next = *data4;
	
	(*data4)->prev = tmp2;
}

// 出力
void output( Field* data)
{
	while( data != NULL){
		printf("%s\n", data->a_field);

		data = data->next;	// 次のデータ
	}
}

// メモリを解放する
void finalize( Field *data)
{
	Field *temp;

	while( data->next != NULL){
		temp = data;
		data = data->next;
		free(temp);
	}
}

// 1行(30byte)読み込む
Field* read_line( FILE *fp)
{
	Field *st_line;
	st_line = (Field*)malloc(sizeof(Field));

	int i=0;
	char ch;
	while( ( ch=fgetc(fp)) != '\n'){
		if( feof(fp) != 0){	// EOFのとき
			if( i>0){	// EOFが行の先頭にないとき
				st_line->a_field[i] = '\0';
				break;
			}
			else{
				return NULL;
			}
		}

		// ファイルを格納
		if( i < 8){
			st_line->a_field[i] = ch;
			if( i == 7){
				st_line->a_field[i+1] = '\0';
			}
		}
		else{	// 最初の8byte読み込んだら, その行の終わり('\n')まで読み込みを続ける
			continue;
		}
		i++;
	} // while

	// 1行が30文字(byte)なかったとき
	if( i<8){
		while( i<8){	// 残りを、空白' 'で埋める
			st_line->a_field[i] = ' ';
			i++;
			if( i == 8){
				st_line->a_field[i] = '\0';
			}
		}
	}
	return st_line;
}


No.7045

Re:双方向リストの並べ替え
投稿者---とおりすがり(2003/06/03 03:57:42)


まず何点か気になった点を

void filein( FILE *fp)
{
・・・
    new_line = (Field*)malloc(sizeof(Field));

/////////////////////////////////////////////
これはread_line()で確保しているのでいりませんね。
/////////////////////////////////////////////

    // 8byte読み込む
    while( ( new_line=read_line(fp)) != NULL){

    new_line = last;
    int i=1;

/////////////////////////////////////////////
これも一目瞭然すぐ下で初期化しています。
/////////////////////////////////////////////

    for(i=0; i<num-1; i++){
・・・
                bsort( &new_line->prev->prev, &new_line->prev, &new_line, &new_line->next);
            }
            new_line = new_line->prev;
    //            printf("num-i: %d\n", num-i);
        }
・・・
}

// メモリを解放する
void finalize( Field *data)
{
    Field *temp;

    while( data->next != NULL){
        temp = data;
        data = data->next;
        free(temp);
    }

/////////////////////////////////////////////
これはデータが一個残りませんか?
/////////////////////////////////////////////

}

// 1行(30byte)読み込む
Field* read_line( FILE *fp)
{
    Field *st_line;
    st_line = (Field*)malloc(sizeof(Field));

・・・
            }
            else{
                return NULL;

////////////////////////////////////////////////////
ここでNULLでリターンしていますが確保したメモリの開放は?
////////////////////////////////////////////////////
            }
・・・
    return st_line;
}

で、問題の

>実行すると無限ループになってしまいます。

ですがoutput()でループするようですね。構造体のnextポインタが自分自身を差
すように設定されてしまったようです。
ですからbsort()でポインタを入れ換えている部分をよく見なおしてみたらいか
がでしょうか?
それとbsortかける際にtopとlastも条件によっては更新しなければならないこと
をお忘れなく。
また、bsort内では先頭のNULLポインタ終端のNULLポインタの処理も必要です。

No.7048

Re:双方向リストの並べ替え
投稿者---レミ(2003/06/03 08:53:52)


>それとbsortかける際にtopとlastも条件によっては更新しなければならないこと
>をお忘れなく。
>また、bsort内では先頭のNULLポインタ終端のNULLポインタの処理も必要です。

こ、こんなに問題があったのですね。少しショックです><
もう一度よく考えて書き直してみます。
どうもありがとうございました。

No.7050

Re:双方向リストの並べ替え
投稿者---とおりすがり(2003/06/03 09:51:36)


>>それとbsortかける際にtopとlastも条件によっては更新しなければならないこと
>>をお忘れなく。
>>また、bsort内では先頭のNULLポインタ終端のNULLポインタの処理も必要です。

先頭と2番目の構造体を入れ換える際に、先頭でなければ存在するであろう さ
らに前の構造体のnextポインタと2番目の構造体をつなぐ処理を2番目のprevポ
インタをNULLセットに切り変えなければなりません。

また同じ事が、終端とその手前の構造体を入れ換える際にも言えます。やはり終
端でなければ存在するであろう その次の構造体のprevポインタとつなぐ処理を
手前の構造体のnextにNULLセットする処理に切り変えなければなりません。

そして先頭、又は終端が入れ換えられた場合top及びlastポインタも更新しなけ
ればそれ以降の処理が崩れてしまいます。

ややこしいですがよく気をつけて見直してみてください。

No.7051

Re:双方向リストの並べ替え
投稿者---かずま(2003/06/03 11:15:44)


> 先頭と2番目の構造体を入れ換える際に、先頭でなければ存在するであろう さ
> らに前の構造体のnextポインタと2番目の構造体をつなぐ処理を2番目のprevポ
> インタをNULLセットに切り変えなければなりません。

双方向リストに 1個ダミーの要素を追加して環状にすると、
挿入や削除が簡単になりますよ。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct field Field;
struct field {
    char data[9];
    Field *next;
    Field *prev;
};

int get_data(Field *r, FILE *fp)
{
    Field *p;  int n;

    for (n = 0; fscanf(fp, "%8s%*[^\n]", r->data) == 1; n++) {
        p = malloc(sizeof(Field));
        if (p == NULL) puts("out of memory"), exit(1);
        strcpy(p->data, r->data);
        p->next = r;
        p->prev = r->prev;
        r->prev->next = p;
        r->prev = p;
    }
    return n;
}

void put_data(Field *r, FILE *fp)
{
    Field *p;

    for (p = r->next; p != r; p = p->next)
        fprintf(fp, "%s\n", p->data);
}

void bsort(Field *r, int n)
{
    Field *p, *q;  int i, k;

    for (--n; n > 0; n = k) {
        for (p = r->next, k = i = 0; i < n; i++, p = q) {
            q = p->next;
            if (strcmp(p->data, q->data) > 0) {
                k = i;
                p->prev->next = q;
                q->next->prev = p;
                p->next = q->next;
                q->prev = p->prev;
                p->prev = q;
                q->next = p;
                q = p;
            }
        }
    }
}

int main(void)
{
    Field a;  int n;

    a.next = a.prev = &a;
    n = get_data(&a, stdin);
    bsort(&a, n);
    puts("---");
    put_data(&a, stdout);
    return 0;
}


No.7053

Re:双方向リストの並べ替え
投稿者---とおりすがり(2003/06/03 11:58:37)


>双方向リストに 1個ダミーの要素を追加して環状にすると、
>挿入や削除が簡単になりますよ。

手は、いろいろ・・・

私はオリジナルを尊重してこんなもんで済ませましたが。

void bsort( Field *data )
{
    Field *tmp;

    tmp = data->prev;
    data->prev = tmp->prev;

    if( tmp->prev != NULL )
        tmp->prev->next = data;

    if( data->next != NULL )
        data->next->prev = tmp;

    tmp->next = data->next;
    data->next = tmp;
    tmp->prev = data;
}

少しは本人に考えさせてあげたら?

No.7069

Re:双方向リストの並べ替え
投稿者---レミ(2003/06/03 20:42:43)


かずまさん、とおりすがりさん お返事ありがとうございます
環状リストという方法の方が簡単そうですね。
双方向リストの後で挑戦してみます。

ソートするところを書き換えてみました。

filein関数の中で、
bsort( &new_line, &top, &last, num);
で、↓を呼び出すようにしました。
それで、bsort関数の中にある、ireka関数なんですが
とおりすがりさんのサンプルを利用してます。
この方法だと、上手くソートできました。ありがとうございます。
アドレスの入れ替えなんですが、書かれているのをみると
なんとなくわかるのですが、自分ではとても思いつきません。
といいますか、まったく思いつきませんでした。
どういう風に考えていけば、上手く答えを出せるのでしょうか?

あと、今までとは違う質問になるんですが、
関数にポインタを引数として渡した場合と、
ポインタのポインタを引数で渡した場合は、どう違うのでしょうか?
ポインタを引数だと、ポインタの値(ポインタが指しているアドレス)ですよね?
ポインタのポインタだと、ポインタ自身のアドレスを渡している?
であってるでしょうか?

bsort関数の引数で、(Field **data)ポインタのポインタを渡してますが、最初は単にポインタを渡してました。dataの値(dataが指しているアドレス)を渡せばbsort関数の中から参照されると考えたのですが、参照されませんでした。
なぜdata自身のアドレスを渡さないといけないのかわかりません。
dataの値(dataが指しているアドレス)を渡せば、アドレスがわかるので参照できるのではないのでしょうか?
‥‥意味わかりましたでしょうか?
すみません。説明が上手くできません。

irekae関数なんですが、
void irekae( Field **data)と、
void irekae( Field *data)では、
どちらが正しいのでしょうか?
実際の値を並べ替えるのだから、**dataの方でしょうか?
どちらも並べ替えが上手くいきます。

長々と申し訳ないんですが、
よろしくお願いします。

void bsort( Field **data, Field **top, Field **last,int num)
{
	for( int i=0; i<num-1; i++){
        for( int j=0; j<num-1-i; j++){
            int k = strcmp( (*data)->a_field, (*data)->prev->a_field);
			if( k < 0){
				// ソート
				irekae(*data);

				if( (*data)->next->next == NULL){
					*last = (*data)->next;
				}
				if( (*data)->prev == NULL){
					*top = *data;
				}
			}
			else{
				*data = (*data)->prev;
			}
        }
		*data = *last;
    }
}

void irekae( Field *data)
{
	Field *tmp;

	tmp = data->prev;
//	data->prev = tmp->prev;
	data->prev = (data)->prev->prev;

	if( tmp->prev != NULL )
//		tmp->prev->next = data;
		data->prev->next = data;

	if( data->next != NULL )
		data->next->prev = tmp;

	tmp->next = data->next;
	data->next = tmp;
	tmp->prev = data;
}


No.7070

Re:双方向リストの並べ替え
投稿者---とおりすがり(2003/06/03 21:28:38)


>アドレスの入れ替えなんですが、書かれているのをみると
>なんとなくわかるのですが、自分ではとても思いつきません。
>といいますか、まったく思いつきませんでした。
>どういう風に考えていけば、上手く答えを出せるのでしょうか?

考えていません。(^^ゞただ紙の上で絵を書いてみただけです。というかこういっ
たリストチェーンは誰しも昔経験しているからある程度体が覚えているんですけ
どね。ちなみに私は体がボケてて覚えていませんのでこういったパズル系の物は
力技で解くことにしています。それが紙の上の絵です。構造体の箱をポインタの
線でつないでそれを順番につなぎ換えてみただけです。順番を間違えると構造体
をたどれなくなるのがよく分かりますよ。

こんなややこしいもんモニタとにらめっこしてポインタ変数の中身を覗いていた
ってなかなか先には進めませんて。がっかりしました?ヽ(´▽`)/へへっ

>あと、今までとは違う質問になるんですが、
>関数にポインタを引数として渡した場合と、
>ポインタのポインタを引数で渡した場合は、どう違うのでしょうか?

ポインタと考えるから難しくなるのですよね。ポインタも普通の変数として考え
ればいいのでは?レミさんがご自身で言っている『ポインタのポインタ』という
言葉を『変数のポインタ』と言い換えてみたらどうですか。それなら理解しやす
くありませんか?ポインタだって他の変数と同じただのアドレス値を入れている
『変数』なのですから。

そうすればおのずと

>ポインタを引数だと、ポインタの値(ポインタが指しているアドレス)ですよね?
>ポインタのポインタだと、ポインタ自身のアドレスを渡している?

も答えは出てきますね。その通りです。ただ先程も書きました通りこれも『ポイ
ンタ変数のアドレスを渡している』と言い直せばどうですか?分かりやすくあり
ませんか?

>bsort関数の引数で、(Field **data)ポインタのポインタを渡してますが、最初は単にポインタを渡してました。dataの値(dataが指しているアドレス)を渡せばbsort関数の中から参照されると考えたのですが、参照されませんでした。
>なぜdata自身のアドレスを渡さないといけないのかわかりません。

渡さないといけないのかではなく渡したものをどう利用するか、又は利用したい
ものはなんなのかを判断して変数の値を渡すなり変数のアドレスを渡すなり決め
ればいいだけです。正解はありません。それは自分が決める仕様に則って作るだ
けです。

>‥‥意味わかりましたでしょうか?
>すみません。説明が上手くできません。

いや、ポインタで混乱しているのはよくわかります。(@_@;)

>void irekae( Field **data)と、
>void irekae( Field *data)では、
>どちらが正しいのでしょうか?

そうするとどちらが正しいのかは先程書いた通り自分が仕様で決める事ですので
動作さえ仕様通りならどちらでもいいです。先程の理屈に則ってご自分で決めて
みましょう。(値渡しとポインタ渡しの理屈は分かりましたか?)


>実際の値を並べ替えるのだから、**dataの方でしょうか?
>どちらも並べ替えが上手くいきます。

うまくいけばそれでいいのですよ。深く考える必要はありません。規則だの効率
だのはまずは2の次でいいと私は思います。完成した後で次の段階としてどこか
効率良く出来ないだろうかといろいろ見直してみたらいいだけです。まずは自分
で決めた仕様通りに動作するプログラムを作れるかどうかです。

リストは後でゆっくり目を通してみます。

No.7071

Re:双方向リストの並べ替え
投稿者---レミ(2003/06/03 23:02:00)


とおりすがりさん、返信ありがとうございます。

紙には書いてみたんですが‥‥
もう一度よく考えながら書いてみます

>うまくいけばそれでいいのですよ。深く考える必要はありません。規則だの効率
>だのはまずは2の次でいいと私は思います。完成した後で次の段階としてどこか
>効率良く出来ないだろうかといろいろ見直してみたらいいだけです。まずは自分
>で決めた仕様通りに動作するプログラムを作れるかどうかです。

なるほど、たしかに!
最初は仕様通りに動作するプログラムを作れるようにがんばります

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

No.7214

おかしなところ教えてください
投稿者---レミ(2003/06/09 12:02:38)


アドレスの入れ換えは、あれから何回か紙に書いていたら
わかるようになりました。考え方は間違ってなかったんですが、
紙への書き方が間違ってました><。
↓が一応完成したつもりなんですが、
どこかおかしい(直したほうがいい)ところがありましたら、
アドバイスを頂きたいです。
よろしくお願いします。
長々とすみません。


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

typedef struct field{
	char a_field[9];
	struct field *next;
	struct field *prev;
} Field;

void filein( FILE*);
void bsort( Field**, Field**, Field**, int);
void irekae( Field*);
void output( Field*);
void finalize( Field*);
Field* read_line( FILE*);

int main( int argc, char **argv)
{
	char *fname0=NULL;
	char fbuf[1024]={0};
	FILE *fp0;

	if( argc == 1){
		printf("入力ファイル名を入力して下さい: ");
		gets(fbuf);
		if( fbuf[0] == '\0'){	// ファイル名が入力されなかったとき
			printf("ファイル名が入力されていません.\n");
			exit(1);
		}
		fname0 = (char*)malloc( sizeof(char)*(strlen(fbuf)+1));
		strcpy( fname0, fbuf);
		if( ( fp0 = fopen( fname0, "r")) == NULL){
			printf("入力ファイル(%s)をオープンできませんでした.\n", fname0);
			exit(1);
		}
		printf("入力ファイル:  %s\n--------\n", fname0);

		filein(fp0);
	}
	else{	// argc >= 2 (ファイル指定あり)

		//	入力ファイルを開く
		if( ( fp0 = fopen( argv[1], "r")) == NULL){
			printf("入力ファイル(%s)をオープンできませんでした.\n", argv[1]);
			exit(1);
		}
		printf("入力ファイル:  %s\n", argv[1]);

		if( argc == 2){
			filein(fp0);	// fileから読み込む
		}
		else{
			printf("引数が多すぎます\n");
			exit(1);
		}
	}

	free(fname0);

	fclose(fp0);

	return 0;
}

void filein( FILE *fp)
{
	Field *new_line;
	Field *top=NULL;
	Field *last=NULL;
	int num=0;	// 読み込んだ文字列の数

	// 8byte読み込む
	while( ( new_line=read_line(fp)) != NULL){

		if( top == NULL){
			new_line->next = NULL;
			new_line->prev = NULL;
			top = last = new_line;
		}
		else{
			new_line->next = NULL;
			new_line->prev = last;
			last->next = new_line;
			last = new_line;
		}
		num++;	// 文字列の数
	}	// while-End

	new_line = last;
	// top/lastが参照しているアドレスに変更を加えるから、top/lastのアドレスを渡す
	bsort( &new_line, &top, &last, num);	// バブルソート

	output(top);	// 出力
	finalize(top);	// メモリの解放
}

// バブルソート
void bsort( Field **data, Field **top, Field **last,int num)
{
	for( int i=0; i<num-1; i++){
        for( int j=0; j<num-i-1; j++){
            int k = strcmp( (*data)->a_field, (*data)->prev->a_field);
			if( k < 0){
				// ソート
				irekae(*data);	// *dataの値(アドレス)を渡して、*dataの要素を変更する

				if( (*data)->next->next == NULL){
					*last = (*data)->next;	// lastが指しているアドレスを換える
				}
				if( (*data)->prev == NULL){
					*top = *data;	// topが指しているアドレスを換える
				}
			}
			else{
				*data = (*data)->prev;	// 次のデータ
			}
        }
		*data = *last;
    }
}

// *dataの要素の値を変更するので、Field構造体(*data)のアドレスを受け取る
void irekae( Field *data)
{
	Field *tmp;

	tmp = data->prev;
	data->prev = data->prev->prev;
	if( tmp->prev != NULL) data->prev->next = data;
	tmp->prev = data;
	tmp->next = tmp->next->next;
	if( tmp->next != NULL) tmp->next->prev = tmp;
	data->next = tmp;
}

// 出力
void output( Field *data)
{
	while( data != NULL){
		printf("%s\n", data->a_field);
		data = data->next;	// 次のデータ
	}
}

// メモリを解放する
void finalize( Field *data)
{
	Field *temp;

	while( data->next != NULL){
		temp = data;
		data = data->next;
		free(temp);
	}
	free(data);	// NULLの手前のdataを解放
}

// 1行(8byte)読み込む
Field* read_line( FILE *fp)
{
	Field *st_line;
	st_line = (Field*)malloc(sizeof(Field));

	int i=0;
	char ch;
	while( ( ch=fgetc(fp)) != '\n'){
		if( feof(fp) != 0){	// EOFのとき
			if( i>0){	// EOFが行の先頭にないとき
				st_line->a_field[i] = '\0';
				break;
			}
			else{
				free(st_line);	// メモリの解放
				return NULL;
			}
		}

		// ファイルを格納
		if( i < 8){
			st_line->a_field[i] = ch;
			if( i == 7){
				st_line->a_field[i+1] = '\0';
			}
		}
		else{	// 最初の8byte読み込んだら, その行の終わり('\n')まで読み込みを続ける
			continue;
		}
		i++;
	} // while

	// 1行が8文字(byte)なかったとき
	if( i<8){
		while( i<8){	// 残りを、空白' 'で埋める
			st_line->a_field[i] = ' ';
			i++;
			if( i == 8){
				st_line->a_field[i] = '\0';
			}
		}
	}
	return st_line;
}


No.7250

Re:おかしなところ教えてください
投稿者---こん!(2003/06/10 13:17:39)


>↓が一応完成したつもりなんですが、

動作の方はご自分で確認は済まれているのですよね。

>どこかおかしい(直したほうがいい)ところがありましたら、

ちょっとだけ気になったところを・・・

int main( int argc, char **argv)
{
・・・
    if( argc == 1){
        printf("入力ファイル名を入力して下さい: ");
        gets(fbuf);
        if( fbuf[0] == '\0'){    // ファイル名が入力されなかったとき
・・・
            exit(1);
        }
        fname0 = (char*)malloc( sizeof(char)*(strlen(fbuf)+1));
        strcpy( fname0, fbuf);
        if( ( fp0 = fopen( fname0, "r")) == NULL){
            printf("入力ファイル(%s)をオープンできませんでした.\n", fname0);


/* 確保したfname0が解放されていない */

            exit(1);
        }
・・・

// メモリを解放する
void finalize( Field *data)
{
    Field *temp;
         
         /* dataがNULLの場合nextがNULLとは限らず
            以降の処理の
        data = data->next;
            で、NULL番地にアクセスしてしまう可能性がある。*/

    while( data->next != NULL){
        temp = data;
        data = data->next;
        free(temp);
    }
    free(data);    // NULLの手前のdataを解放
}
作法レベルの問題ですかね。

No.7260

Re:おかしなところ教えてください
投稿者---レミ(2003/06/10 14:36:56)


こん!さん、返信ありがとうございます。

なるほどdataがNULLのときも考えないといけないんですね
まったく考えていませんでした><

参考になりました。
どうもありがとうございました。
また、よろしくお願いします。

No.7274

Re:おかしなところ教えてください
投稿者---こん!(2003/06/10 19:53:30)


>なるほどdataがNULLのときも考えないといけないんですね
>まったく考えていませんでした><

そうですね。無いとは思いますけどファイルは開けたけどデータが入って
いなかったとかね。
そんな時はtopがNULLのまま実行されてしまうような気がして・・・