如何在C语言中读取无限字符

6

如何在不指定大小的情况下将无限字符读入char*变量中?

例如,假设我想要读取一个可能包含多行的员工地址。


2
下面的答案展示了问题的机制,我鼓励你去学习它们。一个常见的实现是 getline - dmckee --- ex-moderator kitten
你必须首先确保你的硬件内存是无限的! - theglauber
3个回答

8

首先你需要“猜测”所需的大小,然后使用malloc分配一个这么大的缓冲区。如果发现缓冲区太小,可以使用realloc来将缓冲区调整为更大的尺寸。示例代码:

char *buffer;
size_t num_read;
size_t buffer_size;

buffer_size = 100;
buffer = malloc(buffer_size);
num_read = 0;

while (!finished_reading()) {
    char c = getchar();
    if (num_read >= buffer_size) {
        char *new_buffer;

        buffer_size *= 2; // try a buffer that's twice as big as before
        new_buffer = realloc(buffer, buffer_size);
        if (new_buffer == NULL) {
            free(buffer);
            /* Abort - out of memory */
        }

        buffer = new_buffer;
    }
    buffer[num_read] = c;
    num_read++;
}

这只是我随意想到的,可能(读作:很有可能)包含错误,但应该能给您一个好的想法。


1
@Codeka - 你应该避免使用 x = realloc(x, newsize); 如果realloc失败,你将失去原始指针并且会造成内存泄漏。尽管如此,有一个例外是如果你的分配失败策略是结束进程,那么这样做是可以的。 - R Samuel Klatchko
但是要小心...如果realloc失败,您将泄漏先前的缓冲区指针。应该像这样做void *sav=ptr; if((ptr=realloc(ptr,newsiz))==null) { free(sav); } - Lawrence Dol
谢谢大家,没错。我会更新我的示例代码……已经有一段时间没有使用纯C语言了 :) - Dean Harding
pritviraj: 你可以跟进一个realloc(buffer, num_read)调用,将分配的缓冲区修剪到所需的确切大小。 - caf
以下代码是否正确:如有更改,请纠正。'int i = 0; char c; char *str = (char *)malloc(sizeof(char)); while((c = getchar()) != '\n') { str[i++] = c; if(i >= strlen(str)-1) str = (char *)realloc(str, strlen(str) + 2); } str[i] = '\0'; return str;' - PrithviRaj
显示剩余7条评论

1
刚刚回答了Ivor Horton的《Beginning C》第三版第330页上的Ex7.1问题。花了几周时间才解决。该程序允许输入浮点数,而不需要事先指定用户将输入多少个数字。它将数字存储在动态数组中,然后打印出这些数字和平均值。使用Ubuntu 11.04上的Code::Blocks。希望对你有所帮助。
/*realloc_for_averaging_value_of_floats_fri14Sept2012_16:30  */

#include <stdio.h>
#include <stdlib.h>
#define TRUE 1

int main(int argc, char ** argv[])
{
    float input = 0;
    int count=0, n = 0;
    float *numbers = NULL;
    float *more_numbers;
    float sum = 0.0;

    while (TRUE)
    {
        do
        {
            printf("Enter an floating point value (0 to end): ");
            scanf("%f", &input);
            count++;
            more_numbers = (float*) realloc(numbers, count * sizeof(float));
            if ( more_numbers != NULL )
            {
                numbers = more_numbers;
                numbers[count - 1] = input;
            }
            else
            {
                free(numbers);
                puts("Error (re)allocating memory");
                exit(TRUE);
            }
        } while ( input != 0 );

        printf("Numbers entered: ");
        while( n < count )
        {
            printf("%f ", numbers[n]);  /* n is always less than count.*/
            n++;
        }
        /*need n++ otherwise loops forever*/
        n = 0;
        while( n < count )
        {
            sum += numbers[n];      /*Add numbers together*/
            n++;
        }
        /* Divide sum / count = average.*/
        printf("\n Average of floats = %f \n", sum / (count - 1));
    }
    return 0;
}

/* Success Fri Sept 14 13:29 . That was hard work.*/
/* Always looks simple when working.*/
/* Next step is to use a function to work out the average.*/
/*Anonymous on July 04, 2012*/
/* http://www.careercup.com/question?id=14193663 */

不错的尝试!有几个性能建议 - 尽量避免频繁使用realloc,因为它们会涉及到复制所有内容。相反,可以通过2或4的因子进行realloc,并且要同时记录可用空间和已使用空间的数量。此外,平均值可以在运行时计算,而无需预先存储任何内容。 - qdot

0

你可以在栈上放置一个1KB缓冲区(或4KB),读取数据直到找到地址的结尾,然后分配正确大小的缓冲区并将数据复制到其中。一旦从函数返回,栈缓冲区就会消失,你只需要调用一次malloc


当地址大于栈上的1k或4k缓冲区时会发生什么? - Gabe
1
@gabe:你怎么在信封上写4KB的地址? - tomlogic
不知道输入字符串的大小并尝试将其读入固定大小的缓冲区是 C 代码中无数安全问题的根源。 - Gabe
@gabe:fgets有一个缓冲区大小的参数。标准C库中肯定有要避免使用的函数(如gets)。使用长度限制函数和固定大小缓冲区对我来说似乎非常安全。 - tomlogic
1
如果您使用具有缓冲区大小参数的I/O函数,则固定大小缓冲区是安全的。问题在于当您想要的数据不适合您的缓冲区时会发生什么。问题是“如何读取无限字符”。程序是否会失败,因为地址的一部分仍然留在输入流中? - Gabe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接