在 c 中使用 malloc 进行操作时出现分段错误

Get segmentation fault when manipulating with malloc in c

我正在实施一个程序,将 a 数组中的所有值除以 100,然后使用 malloc 将它们存储在 b 数组中。问题是在 main.

中打印 b 的值时出现分段错误

这是我的代码

#include <stdio.h>
#include <stdlib.h>

void divide(int *a, int n, double *b){
    b=malloc(n*sizeof(double));
    
    for(int i=0; i<n; i++){
        b[i]=(double)a[i]/100.0;
    }

    //check: values still remain in b
    for (size_t i = 0; i < 5; i++)
    {
        printf("%.2f ", b[i]);
    }
}

int main(){
    int a[]={1,2,3,4,5};
    double *b;

    divide(a,5,b);
    
    //check: lost value and cause segmentation fault
    for (size_t i = 0; i < 5; i++)
    {
        printf("%.2f ", b[i]);
    }
    free(b);
    return 0;
}

那么是什么原因导致了这个问题以及如何解决它?

提前致谢。

您正在将指针 b 按值传递给函数 divide

divide(a,5,b);

即函数处理原始指针的副本。更改副本不会影响原始指针。

您需要通过指向它的指针按引用传递指针,或者重新设计函数,使其 return 指向函数内动态分配内存的指针。

例如,可以按以下方式声明和定义函数

double * divide( const int *a, size_t n )
{
    double *b = malloc( n * sizeof( double ) );

    if ( b != NULL )
    {
        for ( size_t i = 0; i < n; i++ )
        {
            b[i] = a[i] / 100.0;
        }

        //check: values still remain in b
        for ( size_t i = 0; i < n; i++ )
        {
            printf("%.2f ", b[i]);
        }
    }

    return b;
}

在主要部分你可以写

double *b = divide( a, sizeof( a ) / sizeof( *a ) );

否则函数看起来像

void divide( const int *a, size_t n, double **b )
{
    *b = malloc( n * sizeof( double ) );

    if ( *b != NULL )
    {
        for ( size_t i = 0; i < n; i++ )
        {
            ( *b )[i] = a[i] / 100.0;
        }

        //check: values still remain in b
        for ( size_t i = 0; i < n; i++ )
        {
            printf("%.2f ", ( *b )[i]);
        }
    }
}

并称​​赞

divide( a, sizeof( a ) / sizeof( *a ), &b );

函数divide接收的是指针b的副本。这意味着函数main中的变量b在调用后没有变化。一个更简单的例子来说明这一点是

void f(int n)
{
   n = 1;
}

调用f后,调用方n不变

最简单的代码更正是让 divide 接收指向指针 b 的指针。 divide 的签名将是

void divide(int *a, int n, double **b);

但是,最好在同一个函数中分配和释放内存,因为很容易忘记 divide 分配内存。在处理数组时,我总是使用两个方便的宏函数 NEW_ARRAY 和 LEN 来简化代码。下面是我的建议。如果更改 a 的长度,其余代码将很好地遵循。

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LEN(array) (sizeof (array) / sizeof (array)[0])

#define NEW_ARRAY(pointer, length) \
    { \
        (pointer) = malloc(((size_t) length) * sizeof (pointer)[0]); \
        if ((pointer) == NULL) { \
            fprintf(stderr, "Allocating memory with malloc failed: %s\n", strerror(errno)); \
            exit(EXIT_FAILURE); \
        } \
    }

void divide(int *a, int n, double *b)
{
    for (int i = 0; i < n; i++) {
        b[i] = a[i] / 100.0;
    }
}


int main(void)
{
    int a[] = {1, 2, 3, 4, 5};
    double *b;

    NEW_ARRAY(b, LEN(a));
    divide(a, LEN(a), b);
    for (size_t i = 0; i < LEN(a); i++) {
        printf("%.2f ", b[i]);
    }
    printf("\n");
    free(b);

    return 0;
}