0

昨日質問したのですが、まだ問題があります。ファイルポインタで渡すことができるファイルを処理する関数を持つプログラムを C で書きました。

void process_my_file(FILE *fptr, ...) {
    /* do work */
}

標準入力から入力を読み取って関数に渡す方法を尋ねたところ、 stdin を引数として関数を呼び出すことをお勧めしました。

my_process_file(stdin, ...);

これは機能しますが、私が本当にやりたいことは、EOF が検出されるまで stdin から読み取ってから、一度にすべての入力を function に渡すことです。引数として標準入力を渡すだけの問題は、ユーザーが入力行を入力して「Enter」を押すたびに、プログラムが対応する出力行を時期尚早に吐き出すことです。

ユーザーがEOF(Control-d)を言った後にのみ出力が出るように、入力と出力を明確に分離することを望んでいました。

よろしくお願いします。私はプログラミングを学んでいる初心者であり、あなたのヒントは大きな助けになります. このウェブサイトに本当に感謝しています。

-- ラリー

4

3 に答える 3

0

つまり、EOF が表示されるまで stdin を読み取り、1 つの長い文字列 (おそらく \n で区切られた行で構成される) を関数に渡します。または、プレバッファ読み取りルーチンは、割り当てられた行を指す char* の配列を割り当てることができます。または、プレバッファ ルーチンが stdin を解析し、前処理された情報を返します。その情報で何をしたいかによって異なります。

于 2009-09-27T22:59:10.190 に答える
0

あなたが今持っているのは「フィルター」です。フィルターはすばらしいプログラムですが、もちろん、すべての状況に適用できるわけではありません。とにかく、プログラムをフィルターとして機能させ続けることができるかどうかを確認してください。

処理する前に本当にすべての入力を読み取る必要がある場合は、入力をどこかに保存する必要があります。また、処理関数を a で呼び出しても意味がありませんFILE*(FILE* 内のすべてのデータは既に読み取られています)。すべての入力を char 配列に読み取り、その配列を関数に渡すことができます。

void process_data(char data[], size_t data_len) { /* do work */ }
于 2009-09-27T23:08:53.403 に答える
0

ファイルを開き、ファイル ハンドルを関数に渡すとします。関数内のコードは、その通常のファイルで EOF まで読み取る必要があります。さらに、ファイルを保存するのに十分なスペースを割り当て、短い読み取りを処理する必要があります。

これはすべて、stdin で対処しなければならない問題のセットとまったく同じです。唯一の違いは、端末からの stdin では入力の各行に対して短い読み取りが行われるのに対して、パイプからの各読み取りでは短い読み取りが行われることです。パイプ バッファのサイズを読み取る (またはバッファ サイズより小さいアトミック書き込み)。通常、プレーン ディスク ファイルでは、ファイルの最後のブロックで短い読み取りしかできません。関数はどのくらいのスペースが必要かを前もって知ることができないため (確かに、パイプまたは端末の入力用ではありません)、動的メモリ割り当てを処理する準備ができている必要がmalloc()ありrealloc()ます。

また、関数がすでに読み取られているデータを取得することを期待している場合、文字バッファーとその長さではなく、ファイルハンドル (FILE ポインター) が渡されるのはなぜですか? 関数がファイル ハンドルを使用する必要がある場合は、関数にファイル ハンドルを渡します。つまり、読み取り可能なハンドルから読み取るか、書き込み可能なハンドルに書き込みます (ハンドルが読み取りと書き込みのために開かれている場合は、まれに)。


これが実際のプログラム例です。ファイル全体をメモリに丸呑みし、処理し、何らかの答えを吐き出すために必要な何かを考え出さなければならなかったので、ファイルを文字でソートすることにしました。やや無意味ですが、何をすべきかを示しています。また、操作変数引数のエラー報告機能も備えています。

楽しむ!

/*
 * Demo code for StackOverflow question 1484693
 */

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

static char *arg0;

static void error(const char *fmt, ...)
{
    va_list args;
    int errnum = errno;  /* Catch errno before it changes */

    fprintf(stderr, "%s: ", arg0);
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    if (errnum != 0)
        fprintf(stderr, " (%d: %s)", errnum, strerror(errnum));
    fputc('\n', stderr);
    exit(1);
}

static int char_compare(const void *v1, const void *v2)
{
    char c1 = *(const char *)v1;
    char c2 = *(const char *)v2;
    if (c1 < c2)
        return -1;
    else if (c1 > c2)
        return +1;
    else
        return 0;
}

static void process_my_file(FILE *fp)
{
    char   *buffer;
    size_t  buflen = 1024;
    size_t  in_use = 0;
    ssize_t nbytes;

    if ((buffer = malloc(buflen)) == 0)
        error("out of memory - malloc()");

    while ((nbytes = fread(buffer + in_use, sizeof(char), buflen - in_use, fp)) > 0)
    {
        if (nbytes < 0)
            error("error from fread()");
        in_use += nbytes;
        if (in_use >= buflen)
        {
            char *newbuf;
            buflen += 1024;
            if ((newbuf = realloc(buffer, buflen)) == 0)
                error("out of memory - realloc()");
            buffer = newbuf;
        }
    }

    /* Consistency - number/size vs size/number! */
    qsort(buffer, in_use, sizeof(char), char_compare);
    fwrite(buffer, sizeof(char), in_use, stdout);
    putchar('\n');

    free(buffer);
}

int main(int argc, char **argv)
{
    arg0 = argv[0];

    if (argc > 1)
    {
        for (int i = 1; i < argc; i++)
        {
            FILE *fp;
            if ((fp = fopen(argv[i], "r")) == 0)
                error("failed to open file %s", argv[i]);
            process_my_file(fp);
            fclose(fp);
        }
    }
    else
        process_my_file(stdin);
    return(0);
}

1 つ以上のファイル名を引数としてこれを呼び出すことができます。各ファイル名は個別にソートされます。何かをパイプすることができます。標準入力から読み取らせることができます。私は失敗する可能性fwrite()を無視することにしました。fclose()でのオーバーフローの可能性も無視することにしbuflenましたprocess_my_file()。必要に応じてチェックできます。(各ファイルの出力には、入力よりも改行が 1 つ多いことに注意してください。)

読者のための演習:

  • 印刷できない文字を ''\xXX`' エスケープ シーケンスとして出力します。
  • 出力をそれぞれ 64 文字以下の行に分割します。
  • 各割り当てのスペースを 2 倍にするなど、別の割り当て戦略を考案または研究します (「プログラミングの実践」を参照) 。
于 2009-09-27T23:08:57.680 に答える