web-dev-qa-db-ja.com

fgetsを使用して未知の長さの入力を読み取る方法

fgets()を使用して長い入力を読み取るにはどうすればよいですか、よくわかりません。

私はこれを書いた

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

int main()
{
    char buffer[10];
    char *input;
    while (fgets(buffer,10,stdin)){
        input = malloc(strlen(buffer)*sizeof(char));
        strcpy(input,buffer);
    }
    printf("%s [%d]",input, (int)strlen(input));
    free(input);
    return 0;
}
8
lllook
_#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char buffer[10];
    char *input = 0;
    size_t cur_len = 0;
    while (fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        size_t buf_len = strlen(buffer);
        char *extra = realloc(input, buf_len + cur_len + 1);
        if (extra == 0)
            break;
        input = extra;
        strcpy(input + cur_len, buffer);
        cur_len += buf_len;
    }
    printf("%s [%d]", input, (int)strlen(input));
    free(input);
    return 0;
}
_

これは、入力の完全な行を提供する最小限の変更セットに関するものです。これにより、スペースが一度に最大9バイト増加します。これは最善の方法ではありませんが、より良い方法で行うための追加の簿記があります(割り当てられたスペースを倍増し、割り当てられた量と使用されている量の記録を保持します)。 _cur_len_は、端末nullを除いて、inputが指すスペースに文字列の長さを記録することに注意してください。また、extraを使用すると、割り当てに失敗したときのメモリリークが回避されることに注意してください。

strcpy()操作は合法的にmemmove(input + cur_len, buffer, buf_len + 1)に置き換えることができます(このコンテキストでは、memcpy()の代わりにmemmove()を使用できますが、そうではありません。 memmove()が常に機能している間は常に機能するとは限らないため、memmove()を使用する方が信頼性が高くなります。


長さを2倍にすると、_cur_max_変数は割り当てられたスペースの量を記録し、_cur_len_は使用中のスペースの量を記録します。

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

int main(void)
{
    char buffer[10];
    char *input = 0;
    size_t cur_len = 0;
    size_t cur_max = 0;
    while (fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        size_t buf_len = strlen(buffer);
        if (cur_len + buf_len + 1 > cur_max)
        {
            size_t new_len = cur_max * 2 + 1;
            if (buf_len + 1 > new_len)
                new_len = buf_len + 1;
            char *extra = realloc(input, new_len);
            if (extra == 0)
                break;
            input = extra;
            cur_max = new_len;
        }
        strcpy(input + cur_len, buffer);
        cur_len += buf_len;
    }
    printf("%s [%d]", input, (int)strlen(input));
    free(input);
    return 0;
}
_
6

より良いアプローチは、getline(またはscanf)などの入力メカニズムを使用することです。 (注:scanfはすべてのコンパイラに割り当てられるわけではありません。gcc/Linuxでは割り当てられますが、Windows/Codeblocks/gccでは割り当てられません)

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

int main()
{
    char *input;
    scanf ("%m[^\n]%*c", &input);
    printf("\n %s [%d]\n\n",input, (int)strlen(input));
    free(input);
    return 0;
}

出力:

$ ./bin/scanfinput
This is my longer string.

 This is my longer string. [25]

getlineの例

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

int main()
{
    char *input = NULL;     /* input buffer, NULL forces getline to allocate */
    size_t n = 0;           /* maximum characters to read (0 - no limit      */
    ssize_t nchr = 0;       /* number of characters actually read            */

    if ((nchr = getline (&input, &n, stdin)) != -1)
        input[--nchr] = 0;  /* strip newline */

    printf ("\n %s [%zd]\n\n", input, nchr);
    free(input);

    return 0;
}
3
David C. Rankin