我的指针错误在哪里?

时间:2016-02-11 16:00:12

标签: c realloc

我已经完成了以下代码,但我找不到什么问题。函数getsxnremem()使用len获取最多fgets()个字符的字符串,用空终止符覆盖换行符(如果有的话),然后重新调整内存大小以适应字符串。无论如何,这是个主意。

以下代码有时会起作用,有时会崩溃。我过去经常发生过这种情况,我经常发现问题,但这次我花了太长时间。

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

unsigned getsxnremem(char **str, unsigned len){
    unsigned l, flag = 1;
    free(*str);
    char *buff;
    if ((*str = malloc(len)) == NULL) return 0;
    if(fgets(*str, len, stdin) == NULL) { free(*str); return 0; }
    l = strlen(*str);
    if (l && ((*str)[l-1] == '\n')) { *(str)[l-1] = '\0'; flag = 0; }
    if ((buff = realloc(*str, l + flag)) == NULL){ free(*str); return 0; }
    *str = buff;
    return (l - 1);
}


int main(void){
    char *buff = NULL;
    unsigned l = getsxnremem(&buff, 256);
    printf("%s\n%u chars long.", buff, l);
}

2 个答案:

答案 0 :(得分:10)

问题是,您未能在那里收集realloc()的返回值。

根据C11标准,章节§7.22.3.5

  

#include <stdlib.h>
  void *realloc(void *ptr, size_t size);

     

realloc函数释放ptr指向的旧对象并返回一个   指向具有size指定大小的新对象的指针。 [...]

realloc()调整内存大小,返回指向新内存的指针。考虑到free()成功,旧记忆为realloc() d。

所以,

  1. 您需要收集并检查realloc()的返回值并对其进行测试以确保成功。然后,将其重新分配给*str

    注意:请不要使用p = realloc(p, newsize);之类的表单,因为如果realloc()失败,您最终也会丢失实际指针。

  2. 如果realloc()成功,则您不得free() 指针。在free() - d内存上调用free()会调用undefined behavior

  3. 之后,正如other answer dbush中正确提到的,用法

     { *(str)[l-1] = '\0'; flag = 0; }
    

    也错了。您所需的字符串*str表示,而不是str。根据{{​​3}},数组下标运算符([])优先于解除引用(*)运算符,所以基本上你的代码看起来像

    { * ((str)[l-1]) = '\0'; flag = 0; }
    

    这不是你想要的。因此,要尊重operator precedence,您应该像

    一样修改它
    { (*str)[l-1] = '\0'; flag = 0; }
    

    也就是说,在使用目标缓冲区之前,还应该检查fgets()的返回值以确保成功。当malloc()返回单位化内存时,如果fgets()失败,你最终会从单位化内存中读取,这将再次导致UB。

答案 1 :(得分:1)

对于您最近的更新,您的括号位于错误的位置。

此:

if (l && ((*str)[l-1] == '\n')) { *(str)[l-1] = '\0'; flag = 0; }

应该是:

if (l && ((*str)[l-1] == '\n')) { (*str)[l-1] = '\0'; flag = 0; }
                                   ^---- here