【问题标题】:How to read unlimited characters in C如何在C中读取无限个字符
【发布时间】:2011-01-31 02:50:08
【问题描述】:

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

例如,假设我想读取可能也需要多行的员工的地址。

【问题讨论】:

  • 下面的答案展示了问题的机制,我鼓励您研究它们一种常见的实现是getline
  • 你必须首先确保你的硬件有无限的内存!

标签: c input dynamic-memory-allocation realloc


【解决方案1】:

您必须首先“猜测”您期望的大小,然后使用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++;
}

这只是我的想法,可能(阅读:可能)包含错误,但应该给你一个好主意。

【讨论】:

  • @Codeka - 你应该避免x = realloc(x, newsize); 如果 realloc 失败,你会丢失原始指针并且你会泄漏内存。也就是说,此规则的一个例外是,如果您的分配失败策略是结束进程,则可以。
  • 但是,请注意...如果重新分配失败,您已经泄漏了先前的缓冲区指针。应该做类似void *sav=ptr; if((ptr=realloc(ptr,newsiz))==null) { free(sav); }
  • 谢谢大家,这是正确的。我将更新我的示例...自从我使用直接 C 以来已经有一段时间了 :)
  • 如果可用,您可以继续在同一个分配的地址上使用 asprintf() 以自动增长,同时将刚刚读取的内容附加到已分配缓冲区中的内容。我没有将其发布为答案,因为它不是标准功能,但可以广泛使用。它通常“只处理”由 realloc() 失败引起的问题,至少 GNU 实现是这样。
  • 但是如果用户只输入了几个字符,比如说你分配了100个字节,但用户只输入了10个字节,剩下的就浪费了。
【解决方案2】:

只需要回答 Ivor Horton 第 3 版的《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 */

【讨论】:

  • 不错的尝试!几个性能建议 - 尽量避免许多重新分配,它们涉及复制周围的所有内容。而是重新分配 2 或 4 倍,并同时计算可用空间和已用空间。此外,可以在运行时计算平均值,而无需预先存储任何内容。
【解决方案3】:

在堆栈上放置一个 1KB 缓冲区(或 4KB),读取它直到找到地址的结尾,然后分配一个正确大小的缓冲区并将数据复制到它,怎么样?从函数返回后,堆栈缓冲区消失,您只需调用一次 malloc

【讨论】:

  • 当地址大于堆栈上的 1k 或 4k 缓冲区时会发生什么?
  • @gabe:你如何在信封上写一个 4KB 的地址?
  • 不知道输入字符串的大小并试图将其读入固定大小的缓冲区是 C 代码中无数安全问题的根源。
  • @gabe: fgets 有一个缓冲区大小参数。标准 C 库中肯定有要避免的函数(如 gets)。使用长度限制函数和固定大小的缓冲区对我来说似乎很安全。
  • 如果您使用具有缓冲区大小参数的 I/O 函数,则固定大小的缓冲区是安全的。问题是当您想要的数据不适合您的缓冲区时会发生什么。问题是“如何阅读 unlimited 个字符”。程序是否会因为部分地址仍留在输入流中而失败?
猜你喜欢
  • 1970-01-01
  • 2015-06-29
  • 1970-01-01
  • 1970-01-01
  • 2013-01-03
  • 1970-01-01
  • 2014-11-22
  • 2016-01-01
相关资源
最近更新 更多