我的指针错误在哪里?
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()
是成功的。
所以,
您需要收集并检查 realloc()
的 return 值,并针对 NULL 进行测试以确保成功。然后,将其重新分配给 *str
.
注意:请不要使用像p = realloc(p, newsize);
这样的形式,因为如果realloc()
失败,你将结束也失去了实际的指针。
如果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
我已经遍历了以下代码,但找不到问题所在。函数 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 byptr
and returns a pointer to a new object that has the size specified bysize
. [...]
realloc()
调整内存大小,returns 指向新内存的指针。老内存要free()
d,考虑到realloc()
是成功的。
所以,
您需要收集并检查
realloc()
的 return 值,并针对 NULL 进行测试以确保成功。然后,将其重新分配给*str
.注意:请不要使用像
p = realloc(p, newsize);
这样的形式,因为如果realloc()
失败,你将结束也失去了实际的指针。如果
realloc()
成功,则一定不要free()
old指针。在已经free()
-d 个内存上调用free()
调用 undefined behavior.
之后,正如
{ *(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