C程序调用malloc导致总线错误?

jtoj6r0c  于 2023-08-03  发布在  其他
关注(0)|答案(3)|浏览(77)

我写了这段代码来声明一个指针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));,则程序工作得非常好。为什么在前面的方法中使用它会导致总线错误?

mgdq6dx1

mgdq6dx11#

在函数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是否成功的习惯。

chhqkbe1

chhqkbe12#

因为要更改指针的值,所以需要传递指针的地址。否则,您只需拥有地址的副本。

#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);
}

字符串

w8biq8rn

w8biq8rn3#

在C中,参数通过值传递给函数。这意味着相对于你的程序,函数foo处理的是在main中声明的指针p的值的副本。
因此,函数内副本的任何更改都不会改变原始指针。
您可以按以下方式想象函数及其调用

foo(p);

//...

void foo( /*int *a */ ){
    int *a = p;
    a = (int*)malloc(sizeof(int));
}

字符串
正如您所看到的,在函数中声明的局部变量a被更改。原始指针p保持不变。函数参数是函数的局部变量。
因此,当指针p保持不变并且未被初始化时,则解引用指针,例如

*p = 6;


导致总线错误。
要在函数中更改对象(包括指针),需要通过引用传递它。
在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;
}


注意两个方面。
第一个是不带参数的函数main应声明为

int main( void )


第二个是在C中(与C++相反),你不需要转换从函数malloc返回的指针。那就是你可以写

*a = malloc(sizeof(int));


此外,在main中解引用之前,还应该检查在函数中更改的指针p是否不是空指针。另一方面,函数free可以被调用用于空指针。

相关问题