我的指针错误在哪里?

Where's my pointer error?

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

以下代码时而有效,时而崩溃。我过去遇到过很多次这种情况,我通常都能找到问题所在,但这次我花了太长时间。

#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] = '[=10=]'; 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);
}

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

根据 C11 标准,章节 §7.22.3.5

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

The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size. [...]

realloc() 调整内存大小,returns 指向新内存的指针。老内存要free()d,考虑到realloc()是成功的。

所以,

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

    注意:请不要使用像p = realloc(p, newsize);这样的形式,因为如果realloc()失败,你将结束也失去了实际的指针。

  2. 如果realloc()成功,则一定不要free()old指针。在已经 free()-d 个内存上调用 free() 调用 undefined behavior.

之后,正如 by dbush中正确提到的,用法

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

也是错误的。您需要的 string*str 表示,而不是 str。根据 operator precedence,数组下标运算符 ([]) 比取消引用 (*) 运算符具有更高的优先级,因此基本上您的代码看起来像

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

这不是你想要的。所以,为了尊重operator precedence,你应该像

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

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

对于你最近的更新,你把括号放在了错误的地方。

这个:

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

应该是:

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