C言語関係掲示板

過去ログ

No.1221 fscanfによる文字列読み込み

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

fscanfによる文字列読み込み
投稿者---kit(2004/08/11 12:26:56)


C言語の勉強をしているkitと申します.よろしくお願いします.
ファイルにある文字列データを読み込むプログラムを作成したいと
思い以下のプログラムを書きました.(抜粋)

(ソース)char c[20];

f=fopen("data.txt", "r");
fscanf(f, "%s", c);
fclose(f);

(data.txtの内容)
abcdefg

ここで,入力の受けてとなるchar型変数を配列の形(c[20])で
用意しておくと,文字列の長さによってはメモリが無駄になる
ことが多いと思い,次のように配列の受け手をポインタ変数に
したのですが,エラーが出て終了してしまいました.このような
書き方は間違っているのでしょうか.アドバイスよろしくお願いします.


(ソース)char *c;

f=fopen("data.txt", "r");
fscanf(f, "%s", c);
fclose(f);

printf("%s", c);

(data.txtの内容)
abcdefg

WinXp Home
Visual C++ 6.0



No.16154

Re:fscanfによる文字列読み込み
投稿者---tetrapod(2004/08/11 13:43:40)


誤りです。
ポインタは文字通り「指し示すもの」でしかありません。
char *c; とだけ記述したなら
指し示すものだけあっても、それが指し示す先、すなわち、
文字(列)を入れる器は存在しないのです。
char *c=malloc(20); のように、あるいは
char buf[20]; char *c=buf; のように、
文字を入れる器を正しく指し示してナンボのものです。

文字列に対して配列が無駄になる、というご意見はまさにそのとおりですが、
「読み込んでみなければ文字列の長さは判らない」
のですから、しかたがないことです。
むしろ、文字列のほうが配列より長い場合を考慮する必要があります。


No.16156

Re:fscanfによる文字列読み込み
投稿者---Sciggepy(2004/08/11 17:40:35)


>ここで,入力の受けてとなるchar型変数を配列の形(c[20])で
>用意しておくと,文字列の長さによってはメモリが無駄になる
>ことが多いと思い,
最近のコンピュータでは、メモリの無駄を気にする必要は特にありません。
mallocを使うにしても、確保するバイト数が20以下では、むしろ無駄にメモリを使うことになってしまう可能性が大です。
文字列の長さが20未満と判っているのならば、
char c[20]
で充分ではないでしょうか。


No.16163

Re:fscanfによる文字列読み込み
投稿者---kit(2004/08/12 14:19:22)


アドバイスありがとうございました.

配列でやるというのがよいようですね.

ただ,学生の情報などを管理するプログラムを想定
した場合,

・読み込む文字列の長さにばらつきがある
・読み込む文字列のデータが大量

という状況が考えられます.今のパソコンではメモリのことを
あまり気にする必要はないとはいえ,メモリの無駄をなくすよう
なアルゴリズムはあるにこしたことはないと思うのですが,
なにかよい方法はないでしょうか?


No.16164

Re:fscanfによる文字列読み込み
投稿者---かずま(2004/08/12 15:03:52)


次のプログラムで満足していただけますか?
それともまだこうして欲しいという点がありますか?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void check(void *p) { if (p == NULL) puts("out of memory"), exit(1); } 

int main(void)
{
    char **data = NULL, buf[512];
    int i, n, size = 0;

    for (n = 0; fscanf(stdin, "%511s", buf) == 1; n++) {
        if (n == size) {
            size = size ? size * 2 : 256;
            check(data = realloc(data, sizeof(char *) * size));
        }
        check(data[n] = strdup(buf));
    }
    puts("---");
    for (i = 0; i < n; i++)
        printf("%4d: %s\n", i+1, data[i]);
    return 0;
}



No.16165

Re:fscanfによる文字列読み込み
投稿者---かずま(2004/08/12 18:07:15)


>       if (n == size) {
>           size = size ? size * 2 : 256;
>           check(data = realloc(data, sizeof(char *) * size));
>       }

これでもメモリーが無駄だというのなら、次のようにすることもできます。

        check(data = realloc(data, sizeof(char *) * ++size));



No.16166

Re:fscanfによる文字列読み込み
投稿者---Sciggepy(2004/08/12 19:45:55)


処理速度を犠牲にするのならば、メモリに少しずつ読み込んで操作を行うという方法が考えられます。ただし、読み込むだけなら簡単でも、書き込むとなると大変です。
この方法が使えるのは、データを読み込んですぐに出力する(オーディオなど)場合や、リストにフィルタをかけて出力するなど、入力後すぐに出力できる場合です。