realloc无法重新分配以前的malloc-ed指针

时间:2016-01-03 15:06:08

标签: c realloc getchar

我正在开发一个功能,使用stdinchar*读取整个行到getchar(),它主要起作用,但当我输入更长的字符串时,我得到< / p>

  

realloc():下一个大小无效:0x00000000007ca010

这是功能:

char *readCMDLine() {
    char *cmdline = malloc(sizeof(char));
    int counter = 0;
    char c;
    while (c != 10) {
        c = getchar();
        cmdline = realloc(cmdline, sizeof(cmdline) + sizeof(char));
        cmdline[counter] = c; 
        counter++;
    }
    return cmdline;
}

有没有办法解决这个问题,以便我可以用它读取更大的行?

4 个答案:

答案 0 :(得分:4)

使用sizeof(cmdline)并没有达到预期效果。当与指针一起使用时,它将返回指针的大小,而不是分配的内存。这对于在编译时定义的数组是不同的。

您可以使用counter变量来跟踪已分配的字节数。

也是一种风格的东西:sizeof(char)总是1,所以没必要。

在每个角色之后重新分配是不符合要求的。最好分配一个体积适中的缓冲区,当它完全分配一个更大的缓冲区时。

答案 1 :(得分:3)

这里的问题是,

 sizeof(cmdline)

不像你想象的那样工作。您无法使用指针上的sizeof来获取已分配内存的大小。你必须自己跟踪大小。

现在,要在错误上添加一点,

  

realloc():下一个大小无效:0x00000000007ca010

基本上会发生什么,

cmdline = realloc(cmdline, sizeof(cmdline) + sizeof(char));

实际上并没有按照您的想法调整分配的内存。因此,当counter值足够大以指向cmdline[counter]的情况下的超出内存时,您基本上会调用undefined behavior。因此,由于UB(以及随后的内存损坏),realloc()会发出错误并引发分段错误作为副作用。

另外,要添加

  • 第1点:

     pointer = realloc(pointer....)
    

    是一种非常糟糕的语法。如果realloc()失败,你最终也会失去实际的内存,因为它会被NULL取代。

  • 第2点:

    getchar()返回int,所有返回值可能不适合char(例如EOF)。将c的类型更改为int

  • 第3点:

    您可能希望在返回字符串之前将其终止,以使其可用于字符串操作函数,并且适用于%s中的printf()

  • 第4点:

    在使用返回的指针之前,您应该检查malloc()realloc()是否成功。

答案 2 :(得分:3)

您的代码存在多个问题:

  • 您测试while (c != 10),但第一次未初始化c,并且您不允许该文件在下一个'\n'之前结束。您还假设ASCII,某些系统仍然使用EBCDIC,其中'\n'不是10
  • 您使用sizeof(cmdline)代替counter重新分配。 sizeof(cmdline)是指针的大小,而不是当前分配的数组大小。
  • 您将getchar()存储到char变量中,EOF不是可以适合的值,128UCHAR_MAX之间的值也可能char {1}}已在您的平台上签名。请使用int
  • 您没有null终止分配的字符串。 malloc没有realloc初始化已分配的内存。
  • 您永远不会检查mallocrealloc失败。
  • 您应该在文件末尾返回NULL,否则无法从空行序列中判断文件结尾。
  • 您为每个字符重新分配缓冲区,效率很低,但可以在以后优化,先修复代码。

以下是更正后的版本:

#include <stdlib.h>

char *readCMDLine(void) {
    char *cmdline = malloc(1);
    size_t counter = 0, size = 1;
    int c;

    if (cmdline == NULL)
        return NULL;

    while ((c = getchar()) != EOF && c != '\n') {
        char *p = realloc(cmdline, counter + 2);
        if (p == NULL) {
            free(cmdline);
            return NULL;
        }
        cmdline = p;
        cmdline[counter++] = c;
    }
    cmdline[counter] = '\0';
    if (c == EOF && counter == 0) {
        free(cmdline);
        cmdline = NULL;
    }
    return cmdline;
}

这是一个优化版本,可以更少地调用realloc:

#include <stdlib.h>

#define ALLOCATE_INCREMENT  100
char *readCMDLine(void) {
    char *p, *cmdline = NULL;
    size_t counter = 0, size = 0;
    int c;

    while ((c = getchar()) != EOF && c != '\n') {
        if (counter > size - 2) {
            p = realloc(cmdline, size += ALLOCATE_INCREMENT);
            if (p == NULL) {
                free(cmdline);
                return NULL;
            }
            cmdline = p;
        }
        cmdline[counter++] = c;
    }
    if (counter == 0) {
        if (c == EOF || (cmdline = malloc(1)) == NULL)
            return NULL;
    } else {
        p = realloc(cmdline, counter + 1);
        if (p != NULL)
            cmdline = p;
    }
    cmdline[counter] = '\0';
    return cmdline;
} 

答案 3 :(得分:2)

结合所有建议:

#define BYTES_TO_ADD 80     /* a rather arbitrary number */

char * readCMDLine ( void ) {
    char * cmdline = NULL;
    size_t cmdSize = 0;
    size_t cmdLen = 0;
    int    c;

    while ((c = getchar()) != EOF) {
        if (cmdLen == cmdSize) {
            char * tmp = realloc(cmdline, (cmdSize += BYTES_TO_ADD));  
            if (tmp == NULL) { free(cmdline); return NULL; } 
            cmdline = tmp;
        }
        cmdline[cmdLen++] = (c == '\n') ? '\0' : c;
        if (c == '\n') return cmdline;
    }
    return NULL;   /* no newline */
}