【发布时间】:2020-04-06 06:08:45
【问题描述】:
这是一个查询,用于了解以下代码即使出现错误也能正常工作。
据我所知,如果我想重新分配/重新分配传递给函数的指针,则该指针需要作为双指针传递。错误地,我传递了一个指针,程序仍在运行。我猜它必须与指针作为字符串有关。
程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func2( char **x){
printf("befor func2 x = %u; *x = %u; **x = %s; x_size = %u\n", x, *x, *x, strlen(*x));
free(*x);
*x = (char *)malloc(20);
strcpy(*x, "zyxwvutsrqponmlkjih");
printf("\n\nafter func2 x = %u; *x = %u; **x = %s; x_size = %u\n", x, *x, *x, strlen(*x));
}
void func1( char *x){
printf("befor func1 &x = %u; x = %u; *x = %s; x_size = %u \n", &x, x, x, strlen(x));
func2(&x);
printf("after func1 &x = %u; x = %u; *x = %s; x_size = %u \n", &x, x, x, strlen(x));
}
int main(){
char *x;
x = (char *)malloc(10);
strcpy(x, "abcdefghi");
printf("befor main &x = %u; x = %u; x = %s; x_size = %u\n", &x, x, x, strlen(x));
func1(x);
printf("after main &x = %u; x = %u; x = %s; x_size = %u\n", &x, x, x, strlen(x));
free(x);
return 1;
}
输出:
befor main &x = 489275896; x = 20414480; x = abcdefghi; x_size = 9
befor func1 &x = 489275864; x = 20414480; *x = abcdefghi; x_size = 9
befor func2 x = 489275864; *x = 20414480; **x = abcdefghi; x_size = 9
after func2 x = 489275864; *x = 20414480; **x = zyxwvutsrqponmlkjih; x_size = 19
after func1 &x = 489275864; x = 20414480; *x = zyxwvutsrqponmlkjih; x_size = 19
after main &x = 489275896; x = 20414480; x = zyxwvutsrqponmlkjih; x_size = 19
直到func1,我都能理解输出。但是在func2 中修改后,大小和值如何返回到main?我没有将x 作为双指针从main 传递到func1。但不知何故,它仍然有效。
是因为是char *吗?
编辑 1:
在 cmets 中建议编辑后:
程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func2( char **x){
printf("befor func2 x = %p; *x = %p; **x = %s; x_size = %u\n", x, *x, *x, strlen(*x));
free(*x);
*x = (char *)malloc(20);
strcpy(*x, "zyxwvutsrqponmlkjih");
printf("\n\nafter func2 x = %p; *x = %p; **x = %s; x_size = %u\n", x, *x, *x, strlen(*x));
}
void func1( char *x){
printf("befor func1 &x = %p; x = %p; *x = %s; x_size = %u \n", &x, x, x, strlen(x));
func2(&x);
printf("after func1 &x = %p; x = %p; *x = %s; x_size = %u \n", &x, x, x, strlen(x));
}
int main(){
char *x, *y, *z;
x = (char *)malloc(10);
z = (char *)malloc(100);
y = (char *)malloc(100);
strcpy(x, "abcdefghi");
printf("befor main &x = %p; x = %p; x = %s; x_size = %u\n", &x, x, x, strlen(x));
func1(x);
printf("after main &x = %p; x = %p; x = %s; x_size = %u\n", &x, x, x, strlen(x));
free(x);
free(y);
free(z);
return 1;
}
输出:
befor main &x = 0x7fff78cb09c8; x = 0x1c7a010; x = abcdefghi; x_size = 9
befor func1 &x = 0x7fff78cb09a8; x = 0x1c7a010; *x = abcdefghi; x_size = 9
befor func2 x = 0x7fff78cb09a8; *x = 0x1c7a010; **x = abcdefghi; x_size = 9
after func2 x = 0x7fff78cb09a8; *x = 0x1c7a010; **x = zyxwvutsrqponmlkjih; x_size = 19
after func1 &x = 0x7fff78cb09a8; x = 0x1c7a010; *x = zyxwvutsrqponmlkjih; x_size = 19
after main &x = 0x7fff78cb09c8; x = 0x1c7a010; x = zyxwvutsrqponmlkjih; x_size = 19
引入多个 malloc 后程序仍然有效。
【问题讨论】:
-
在不相关的注释中,打印指针的正确
printf格式(更具体地说是void *,需要转换)是%p。格式说明符和参数类型不匹配(例如使用unsigned int格式%u打印指针)会导致未定义行为。 -
这可能是纯粹的巧合和运气,再加上您的程序具有非常简单的内存布局这一事实,让它发生。由于您总是在再次分配之前释放,因此 malloc 能够一遍又一遍地返回相同的指针。为了验证这一点,您可以通过在声明 x 之后立即添加
char *y = malloc(10);来“破坏”程序。然后,func2 的 malloc 将无法为其更大的缓冲区使用相同的 10 字节长的存储空间,并且应该返回其他地方……尽管它仍然依赖于实现。 (不是一个答案,因为没有经过验证也没有写好。) -
@Someprogrammerdude 我忘记了 %p。谢谢提醒。我最初使用的是
%02x。但这只有1个字符差异并且令人困惑。所以我选择了 %u。 -
@Alceste_ 我尝试了您的建议并根据调查结果更新了问题。
-
Tbh 我仍然倾向于坚持我的解释(一些程序员老兄的回答很好地增强了这一点。也许你的 malloc 实现在缓冲区之间有一个超过 100 字节的默认空间,这将简化 realloc 优化. 你可以通过为你的程序设置一个较小的整体内存来打破它,或者更容易地,使用兆字节缓冲区作为字符串。(如果需要的话,仍然先使用少数几个)
标签: c string pointers malloc double-pointer