从文件管道输入时,realloc无法扩展char数组

时间:2014-10-14 01:28:04

标签: c arrays string realloc

我写了下面的c函数来获取用户的字符串。它使用realloc动态更改char数组大小以适应未知的char数组长度。根据我的理解,它应该能够获取尽可能多的输入(或者有内存可用),但是,当我尝试从随机文本文件中管道文本时(使用“tr'\ n''' './random.txt“以确保我从文本文件中删除了任何换行符),我得到”无法分配内存来保存char数组。退出!“错误信息。为什么会这样?我的阵列是否能够容纳数千兆字节的数据,因为我有16 GB的RAM用于动态增长的方式?

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

void GetString(int*, int*);

int main(void)
{
    unsigned int strLength = 32;
    char *stringPtr = malloc(strLength);
    if (stringPtr == NULL)
    {
        fprintf(stderr, "Unable to allocate memory to hold char array. Exiting!\n");
        return 1;
    }
    printf("Enter some input: ");
    int c = EOF;
    unsigned int i = 0;
    while ((c = getchar()) != '\n' && c != EOF)
    {
        stringPtr[i++] = (char) c;
        if (i == strLength)
        {
            strLength *= strLength;
            if ((stringPtr = realloc(stringPtr, strLength)) == NULL)
            {
                fprintf(stderr, "Unable to expand memory to hold char array. Exiting!\n");
                return 2;
            }
        }
    }
    stringPtr[i] = '\0';
    if (sizeof(stringPtr) < strLength)
    {
        stringPtr = realloc(stringPtr, i);
    }
    printf("\n\nString value: %s\n\n\n", stringPtr);
    free(stringPtr);
    stringPtr = NULL;
}

1 个答案:

答案 0 :(得分:2)

我稍微修改了你的程序,以帮助弄清楚出了什么问题:

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

int main(void)
{
    unsigned int strLength = 32;
    char *stringPtr = malloc(strLength);
    if (!stringPtr)
    {
        fprintf(stderr, "failed to allocate %u bytes: %s\n",
                strLength, strerror(errno));
        return 1;
    }
    int c = EOF;
    unsigned int i = 0;
    while ((c = getchar()) != '\n' && c != EOF)
    {
        stringPtr[i++] = (char) c;
        if (i == strLength)
        {
            unsigned int nStrLength = strLength;
            nStrLength *= nStrLength;
            if (nStrLength <= strLength)
            {
                fprintf(stderr, "cannot grow string of %u bytes any more\n",
                        strLength);
                return 1;
            }
            if ((stringPtr = realloc(stringPtr, nStrLength)) == NULL)
            {
                fprintf(stderr,
                        "failed to enlarge string from %u to %u bytes: %s\n",
                        strLength, nStrLength, strerror(errno));
                return 1;
            }
            strLength = nStrLength;
        }
    }
    return 0;
}

当像你一样或多或少地运行时,这就是我得到的:

$ yes | tr -d '\n' | ./a.out 
cannot grow string of 1048576 bytes any more

1048576是1兆字节,但更重要的是,它是2 20 。 2 20 的平方为2 40 ,大于2 32 -1,这是可以表示的最大值。 unsigned int在此系统上。我预测您将在您的系统上获得相同的结果。

因此,我建议您进行三项更改:

  • 正如我已经提到的,所有这些unsigned int变量都应该是size_t
  • 正如chux已经提到的那样,将代码更改为只将strLength乘以2而不是单独使用。
  • 根据我在此处所做的工作,对溢出进行明确的检查。 或采用reallocarray,这可能不在您的C库中,但您可以从链接中删除。 [编辑: reallocarray仍然一般来说这是一个好主意,但它对这个类的数值溢出错误没有帮助,因为它是数组中溢出的项目数,而不是项目数和大小的乘积。的

此外,这次不是您的直接问题,但为了将来参考,strerror(errno)是您的朋友。当系统原语失败时,始终打印strerror(errno)