ページ 11

NULLを認識しません。

Posted: 2006年12月12日(火) 13:01
by hiro
はじめまして。
下記のプログラムでNULLを認識してプログラムが入力行数を出力して終わるようにしたいのですが、
NULLを認識せずいつまでもループになってしまいます。
どこがわるいのでしょうか?
#include <stdio.h>
main()
{
char a[81];
int n = 0;
while(gets(a) != NULL)
{
n++;
puts(a);
}
printf("\n lines = %d\n",n);
}

Re:NULLを認識しません。

Posted: 2006年12月12日(火) 13:22
by box
> NULLを認識せずいつまでもループになってしまいます。

Windowsをお使いでしたら、Ctrl+Z で入力を終了させてください。

Re:NULLを認識しません。

Posted: 2006年12月12日(火) 13:33
by hiro
boxさん
返答ありがとうございます。
こちらも、Ctrl+Zで止めていました。
プログラム的にはどうでしょうか?

Re:NULLを認識しません。

Posted: 2006年12月12日(火) 13:55
by hiro
先の返信でマークを雑談にいれていました。
どなたかプログラムの悪いところを教えてください。

Re:NULLを認識しません。

Posted: 2006年12月12日(火) 14:14
by Justy
どなたかプログラムの悪いところを教えてください。
 NULLを認識していないとのことでしたが、特に悪いところは見あたりません。
 正しく gets()の戻り値の NULLを認識しています。
 だから Ctrl+Zでループをぬけることができるわけで。

Re:NULLを認識しません。

Posted: 2006年12月12日(火) 14:26
by hiro
justyさん
返答ありがとう御座います。
てっきり、入力を何もせずにエンターキーを返せば終わるものと思っていました。
エンターキーで終わる方法はないのでしょうか?

Re:NULLを認識しません。

Posted: 2006年12月12日(火) 14:34
by Justy
 なるほど。ではこうして見てください。
[color=#d0d0ff" face="monospace] while(gets(a) != NULL) 
    {
        if(!strlen(a))
            break;
        n++; 
        puts(a); 
    }[/color]

Re:NULLを認識しません。

Posted: 2006年12月12日(火) 14:43
by GPGA
では私はこんなプログラムで。
char* p;
    while ((p = gets(a)) != NULL && *p != '\0')
    {
        n++; 
        puts(a); 
    }
 

Re:NULLを認識しません。

Posted: 2006年12月12日(火) 17:31
by hiro
justyさん
GPGAさん
いろいろと考えて頂きありがとうございます。
正常に動作致しました。

さらに、頂いた返事をもとに内容を考えてみました。

justyさんの回答では、NULLは無くても良いと分かりましたので下記のようにプログラムを変更しました。

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

main()
{
char a[81];
int n = 0;
while(!!strlen(gets(a)) != '\0')

{
n++;
puts(a);
}
printf("\n lines = %d\n",n);
}


また、GPGAさんに頂いた回答についても、同様にNULLの部分がいらないように思えたので下記のように変更してみました。

#include <stdio.h>

main()
{
char a[81];
int n = 0;
char* p;
while((p = gets(a)) && *p != '\0' )

{
n++;
puts(p);
}
printf("\n lines = %d\n",n);
}

結局、どちらについてもNULLは無くなってしまいました。
(プログラムの'\0'の部分をNULLにすると参照の型が違うと言うワーニングメッセージがでます。)

別に作ったデータファイルの内容を参照するプログラムではNULLは正常に動きましたが、キーボード入力ではなぜ正常に動かないのでしょうか?

NULLの扱い方についてさらに教えて頂ければ幸いです。

Re:NULLを認識しません。

Posted: 2006年12月12日(火) 17:45
by keichan
NULLの使い方というよりはgets関数の使い方をきちんと確認してください。

MSDNでは
> gets関数は、stdin標準入力ストリームから行を読み取り、bufferに格納します。行は最初の改行文字(\n)までのすべての文字で構成されています。
> その後、getsは、改行文字をnull文字(\0)に置換してから行を返します。

とあります。
NULLが必要なのはgetsではなくfgetsの方だと判断できますね^^

Re:NULLを認識しません。

Posted: 2006年12月12日(火) 17:51
by GPGA
> NULLの部分がいらないように思えたので
NULLチェックがなくなると Ctrl+Z で終了させることが
できなくなってしまいますが、いいのでしょうか?

> (プログラムの'\0'の部分をNULLにすると参照の型が違うと言うワーニングメッセージがでます。)
'\0'とNULLは別物です。

NULLは大抵の処理系では以下のように宣言されています。
#define NULL ((void *)0)

一方 \0 は文字列の終端コードです。
gets関数はエラーの場合はNULLを返しますが
正常終了したときは引数と同じポインタを指します。
つまり

p = gets(a);

が正常終了した場合、

p == a

が成り立ちます。
何も入力せずにENTERを押した場合、a[0]に 終端コードである '\0' が入ります。

a[0] == *(a + 0) == *a == *p

なので、whileのチェックで

*p != '\0'

の一文を入れているわけです。

> 別に作ったデータファイルの内容を参照するプログラムではNULLは正常に動きましたが、キーボード入力ではなぜ正常に動かないのでしょうか?
それは fgets関数を使用したプログラムですか?
そうである場合、fgets関数はファイルの終端に来た場合にNULLを返すからです。
キーボードからの場合、通常の入力では終端というものがありません。
Ctrl+Zが押されたときが、終端と考えてください。

Re:NULLを認識しません。

Posted: 2006年12月13日(水) 16:15
by 管理人
きっとhiroさんは終端コードを「ヌル文字」と習ったのでNULLと混合しているのではないでしょうか。
ヌル文字である\0は間違うようなら「終端コード」「終端記号」と呼ぶといいと思います。

http://www.bohyoh.com/CandCPP/C/Library/gets.html

この辺を見ると、関数の値が何が返ってくるのかよくわかります。

Re:NULLを認識しません。

Posted: 2006年12月13日(水) 19:49
by hiro
keichanさん
GPGAさん
管理人さん
なんとなく分かった気がしてきました。
どうも、NULLとNULL文字を同じものとして、使い方を誤解していたようですね。
いろいろとありがとうございました。
これからも宜しくお願い致します。