我编写了这段代码来声明一个指针
p
,然后为int类型动态分配4个字节的内存,然后在其中存储一些数据。 p
应指向保存 int 类型数据 6
的地址。然后程序应该使用 dereferencing operator
打印出指针变量中的数据。我还包含了 free()
函数来从堆中释放分配的内存。我不明白为什么我收到总线错误。相同的代码已由同行执行,并且运行得非常好。我正在使用 Mac M2 并在 vscode
上运行代码。什么可能导致此错误?
#include <stdio.h>
#include <stdlib.h>
void foo(int *a){
a = (int*)malloc(sizeof(int));
}
int main(){
int *p;
foo(p);
*p = 6;
printf("%d",*p);
free(p);
return(0);
}
这是错误消息:
zsh: bus error
请注意,如果我要删除
foo()
函数并用 p = (int*)malloc(sizeof(int));
替换调用行,那么程序就可以正常工作。为什么在之前的方法中使用它会导致总线错误?
在你的函数
foo
中,参数a
是一个局部变量。您将 malloc
的结果分配给它,但这对此函数调用之外的程序没有影响。
就目前而言,您正在取消引用未初始化的指针,从而导致未定义的行为。如果
malloc
成功,您还会遇到(在本例中是短暂的)内存泄漏,因为您以后无法释放该内存。
要完成此操作,您需要将指针传递给指针。
void foo(int **a) {
*a = malloc(sizeof(int));
}
int main(void) {
int *p;
foo(&p);
*p = 6;
printf("%d", *p);
free(p);
return 0;
}
您可能还想养成检查
malloc
是否成功的习惯。
因为要改变指针的值,所以需要传递指针的地址。否则,您只需拥有地址副本即可。
#include <stdio.h>
#include <stdlib.h>
void foo(int **a){
*a = malloc(sizeof(int));
}
int main(){
int *p;
foo(&p);
*p = 6;
printf("%d",*p); // 6
free(p);
return(0);
}
在 C 中,参数按值传递给函数。这意味着相对于您的程序,函数
foo
处理在 p
中声明的指针 main
的值的副本。
因此,函数内副本的任何更改都会使原始指针保持不变。
您可以按以下方式想象该函数及其调用
foo(p);`
//...
void foo( /*int *a */.){
int *a = p;
a = (int*)malloc(sizeof(int));
}
如您所见,它是在更改的函数内声明的局部变量
a
。原始指针p
保持不变。函数参数是函数的局部变量。
要更改函数内的对象(包括指针),您需要通过引用传递它。
在 C 中,通过引用传递意味着通过指向对象的指针间接传递对象。因此,取消引用传递的指针,您可以直接访问指针指向的对象并可以更改它。
所以你的程序应该如下所示
#include <stdio.h>
#include <stdlib.h>
void foo( int **a )
{
*a = malloc(sizeof(int));
}
int main( void )
{
int *p;
foo( &p );
if ( p != NULL )
{
*p = 6;
printf( "%d\n", *p );
}
free(p);
return 0;
}
注意两个方面。
第一个是不带参数的函数maon,应声明为
int main( void )
第二个是在 C 中你不需要转换从函数 malloc 返回的指针。那就是你可以写
*a = malloc(sizeof(int));
并且您还应该在
p
中取消引用之前检查函数内更改的指针 main
是否不是空指针。