ページ 11

fgets関数に関して

Posted: 2010年3月17日(水) 08:54
by sky
はじめましてskyです。fgets関数を用いてpgmファイルの始めの2行(添付ファイルの場合, P2, 304,322)をそれぞれ、変数header, width, heightに格納するプログラムを考えているのですがfgets関数は一行ずつ読み込む関数ですよね?304,322は同じ行にあるのにこれを別々の変数に格納する方法がよくわかりません。

サイトや参考書を見て以下までできました。これからどうしたら良いか行き詰ってます。
OS:UNIX,コンパイル:gcc

#include<stdio.h>
#define BUFFER_SIZE 200
void main(){
char buffer[BUFFER_SIZE];
FILE *fp;
fp = fopen("test_barbarar.pgm", "r");

// ファイルオープン失敗か?
if ( !fp ){
printf("ファイルオープンエラー\n");
return;
}

// 1行ずつ読み込んで表示する
while( fgets(buffer, BUFFER_SIZE, fp) ){
printf("%s", buffer);
}

// ファイルクローズ
fclose(fp);
}

添付ファイルtest_barbarar.のサイズが大きくて貼れなかったので、初めの4行は以下のようになってます。
P2
304 322
255
161 162 162 161 161 162 160 160 157 158 165 163 161 164 163 165 164 162


長々と失礼しました。どうかよろしくお願いします。

Re:fgets関数に関して

Posted: 2010年3月17日(水) 09:02
by バグ
fscanf関数を使用してはいかがでしょうか?

Re:fgets関数に関して

Posted: 2010年3月17日(水) 09:17
by バグ
#include<stdio.h>

#define BUFFER_SIZE 200
#define HEADER_SIZE 8

int main(void)
{
    char buffer[BUFFER_SIZE] = {0, };
    char header[HEADER_SIZE] = {0, };
    int width = 0, height = 0;
    FILE *fp;

    // ファイルオープン
    fp = fopen("test_barbarar.pgm", "r");

    // ファイルオープン失敗か?
    if (fp == NULL)
    {
        printf("ファイルオープンエラー\n");
        return;
    }

    // header, width, heightを読み込む
    fscanf(fp, "%s", header);
    fscanf(fp, "%d%d", &width, &height);

    // header, width, heightを表示する
    printf("header = %s\n", header);
    printf("width  = %d\n", width);
    printf("height = %d\n", height);

    // ファイルクローズ
    fclose(fp);

    return 0;
}

Re:fgets関数に関して

Posted: 2010年3月17日(水) 09:18
by バグ
おっと、ファイルオープンに失敗した際の戻り値を設定するのを忘れておりましたm(__)m
#include<stdio.h>

#define BUFFER_SIZE 200
#define HEADER_SIZE 8

int main(void)
{
    char buffer[BUFFER_SIZE] = {0, };
    char header[HEADER_SIZE] = {0, };
    int width = 0, height = 0;
    FILE *fp;

    // ファイルオープン
    fp = fopen("test_barbarar.pgm", "r");

    // ファイルオープン失敗か?
    if (fp == NULL)
    {
        printf("ファイルオープンエラー\n");
        return -1;
    }

    // header, width, heightを読み込む
    fscanf(fp, "%s", header);
    fscanf(fp, "%d%d", &width, &height);

    // header, width, heightを表示する
    printf("header = %s\n", header);
    printf("width  = %d\n", width);
    printf("height = %d\n", height);

    // ファイルクローズ
    fclose(fp);

    return 0;
}

Re:fgets関数に関して

Posted: 2010年3月17日(水) 12:14
by sky
バグさん、丁寧にご回答まことにありがとうございます。
一応課題でfgetsを使うことを指定されています。fgetsは一行ずつファイルから読み込む関数と解釈しているのですが添付ファイルの2行目が304 322となってるので これをそれぞれ違う変数に格納するやり方を教えて頂ければ幸いです。私の記述の仕方が悪かったです。本当にすみません。

Re:fgets関数に関して

Posted: 2010年3月17日(水) 12:18
by non
fgetsをした後で、sscanfを使う方法があります。

Re:fgets関数に関して

Posted: 2010年3月17日(水) 13:37
by たかぎ
ちがう変数とのことですが、どんな変数でしょうか?
例えば、文字列として扱えばよいのであれば、sscanfよりstrtokの方がむしろ楽です。
整数値として扱うのであれば、strtolやstrtoulを使うべきです(もちろん、strtollやstrtoimaxが使えるなら、それでもOK)。

Re:fgets関数に関して

Posted: 2010年3月17日(水) 14:13
by sky
nonさん>>
ありがとうございます。fgets関数で2行分だけ読み込みsscanfを用いるということでしょうか。
2行分だけ読み込むことは可能なんですかね?

たかぎさん>>
お手数おかけします。返答ありがとうございます。
304と322という整数をそれぞれ widthとheightに格納するということです。

問題がfgets関数を用いてpgmファイルの始めの2行(添付ファイルの場合, P2, 304,322)をそれぞれ、変数header, width, heightに格納するプログラムを作成せよ。
ってなっててstrtolやstrtoulはまだ習ってないです。ホントにすみません。 画像

Re:fgets関数に関して

Posted: 2010年3月17日(水) 14:39
by バグ
それならば、nonさんの言われるように、fgets関数でいったん文字列としてファイルの内容を取得しておいて、sscanf関数を使用して、文字列→数値へ変換してやればいいと思いますよ。
これらの手間を一度に行えるのがfscanf関数なので、結局同じことではあるのですが…(^_^;)

sscanf関数の使い方が分からなければ、下記URLを参照ください。
http://www.bohyoh.com/CandCPP/C/Library/sscanf.html

Re:fgets関数に関して

Posted: 2010年3月17日(水) 14:49
by sky
バグさん本当にありがとございます。
プログラム苦手なので考えるのに時間がかかりますけどやってみます。
また分からないことがあればよろしくお願いします。

Re:fgets関数に関して

Posted: 2010年3月17日(水) 15:41
by sky
今先生に確認をしたところfgetsのみでやりなさい(fscanfやsscanf使わないでやって)。と言われました汗
すみません。 画像

Re:fgets関数に関して

Posted: 2010年3月17日(水) 16:00
by Blue
トークン分割用:strtok
  数値変換用:strtolやatoi(はあまりよろしくないけど)

はつかってもよい?

そもそも
>304と322という整数をそれぞれ widthとheightに格納するということです。
widthとheightは何型?
char型の配列であれば、strtolとかは不要。
画像

Re:fgets関数に関して

Posted: 2010年3月17日(水) 16:09
by sky
Blueさん
strtokも使ってはいけないみたいです。widthとheightは何型か特に指定されていないです。 画像

Re:fgets関数に関して

Posted: 2010年3月17日(水) 16:18
by Blue
>widthとheightは何型か特に指定されていない
のであれば、char型配列にしてしまえばw

2行目は先頭から空白の手前までをwidthに、空白の後ろから改行もしくは終端までをheightに
入れるような処理を書けばよいですね。

未検証だけどこんな感じ?
char width[8] = ""; // サイズは適当
char height[8] = "";
char* p; // 検索用
int i;   // 格納用

i = 0;
for (p = buffer; *p != ' ' && *p != '\0'; ++p, ++i) {
    width = *p;
}
width = '\0';

if (*p != '\0')
{
    ++p;
    i = 0;
    for (; *p != '\0' && *p != '\n'; ++p, ++i) {
        height = *p;
    }
    height = '\0';
}

画像

Re:fgets関数に関して

Posted: 2010年3月18日(木) 08:22
by sky
Blueさん>>
ありがとうございます。すこしお尋ねしたいのですが…
width = *p;
}
width = '\0';←これはどういう意味ですかね?

Re:fgets関数に関して

Posted: 2010年3月18日(木) 08:43
by Blue
>width = '\0';←これはどういう意味ですかね? 
文字列の終端文字を格納しているだけです。

Re:fgets関数に関して

Posted: 2010年3月18日(木) 08:54
by sky
全体的なのがまだできてないのでもうすこし考えてみます。
丁寧にご回答ありがとうございました。

Re:fgets関数に関して

Posted: 2010年3月24日(水) 10:52
by sky
Blueさん>>
参考にさせてもらいました。以下のようにしたのですが…
#include <stdio.h>

#define BUFFER_SIZE 200

void main(){
char buffer[BUFFER_SIZE];
char header[10];
char width[10]="",height[10]="",space[10];//格納
char *p;
int i;

FILE *fp ;
FILE *new;

fp = fopen("test_barbarar.pgm", "r");

// ファイルオープン失敗か?
if ( !fp ){
printf("ファイルオープンエラー\n");
return;
}


fgets(header, BUFFER_SIZE, fp);
printf("header=%s", header);

fgets(buffer, BUFFER_SIZE, fp);
i = 0;
for (p = buffer; *p != ' ' && *p != '\0'; ++p, ++i) {
width = *p;
}
width = '\0';

if (*p != '\0')
{
++p;
i = 0;
for (; *p != '\0' && *p != '\n'; ++p, ++i) {
height = *p;
}
height = '\0';
}

printf("width=%s", width);
printf("height=%s", header);

// ファイルクローズ
fclose(fp);
}

実行結果
header=p2
width=(null)header=(null)
となってしまいます。何がいけなかったのでしょうか?何度もすみません。

Re:fgets関数に関して

Posted: 2010年3月24日(水) 13:26
by fatens
>fgets(header, BUFFER_SIZE, fp);
header[/url]のサイズは10なのに、関係のないBUFFER_SIZEを渡すのはどうかと。
10 または、sizeof(header) / sizeof(header[0]) にするほうが良いと思います。

>printf("width=%s", width);
>printf("height=%s", header);
printf 関数に渡すべきは文字列の先頭アドレスなのに、文字を渡しています。
また、このときのiは何を意図しているのでしょう?