Home > Back-end >  Get segmentation fault when manipulating with malloc in c
Get segmentation fault when manipulating with malloc in c

Time:12-18

I am implementing a program to divide all value in a array by 100 then store them in b array using malloc. The problem is I got segmentation fault when printing value of b in main.

This is my code

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

So what cause this problem and how to fix it?

Thanks in advance.

CodePudding user response:

You are passing the pointer b by value to the function divide

divide(a,5,b);

That is the function deals with a copy of the original pointer. Changing the copy does not influence on the original pointer.

You need either to pass the pointer by reference through a pointer to it or redesign the function such a way that it will return a pointer to the dynamically allocated memory within the function.

For example the function could be declared and defined the following way

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

And in main you can write

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

Otherwise the function can look like

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

And called like

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

CodePudding user response:

What the function divide receives is a copy of the pointer b. This means that the variable b in function main is unchanged after the call. A simpler example to illustrate this is

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

After f has been called, n is unchanged on the caller's side.

The simplest correction of your code is to make divide receive a pointer to the pointer b. The signature of divide would then be

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

However, it's better to allocate and free memory in the same function since it's easy to forget that divide allocates memory. When working with arrays I always use two convenient macro functions NEW_ARRAY and LEN which simplifies the code. Below is my suggestion. If the length of a is changed the rest of the code will follow nicely.

#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;
}
  • Related