简体   繁体   中英

Segmentation fault when copy a multidimensional array in C using pointers

I need writing a function that will copy a multidimensional array in C using pointers. I'm using gcc 5.4.0 and clang 3.9.1 on Gentoo. I'm using a fact that using name of array is the same of referencing to address to it first element, so if we have twodimensional array then array_2d = &array_2d[0] and *array_2d = *(&array_2d[0]) = array_2d[0] . This is my code:

#include <stdio.h>
#define ROWS 2
#define COLS 3

void copy_ptr(double *src, double *dest, int len);
void copy_ptr2d(double **src, double **dest, int rows, int cols);

int main() {
    double array[ROWS][COLS] = { { 12.3, 55.1 }, { 33.6, 21.9, 90.8 } };
    double array2[ROWS][COLS];
    printf("Array { { 12.3, 55.1 }, { 33.6, 21.9, 90.8 } }\n");
    printf("Array copy:\n");
    copy_ptr2d(array, array2, ROWS, COLS);
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            printf("array2[%d][%d]: %lf\n", i, j, array2[i][j]);
        }
        printf("\n");
    }
    return 0;
}

void copy_ptr2d(double **src, double **dest, int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        copy_ptr(*src, *dest, cols);
        src++;
        dest++;
    }
}

void copy_ptr(double *src, double *dest, int len) {
    for (int i = 0; i < len; i++) {
        *dest = *src;
        dest++;
        src++;
    }
}

The results of compilation code under gcc 5.4.0:

pecan@tux ~ $ gcc main.c 
main.c: In function ‘main’:
main.c:13:16: warning: passing argument 1 of ‘copy_ptr2d’ from incompatible pointer type [-Wincompatible-pointer-types]
     copy_ptr2d(array, array2, ROWS, COLS);
                ^
main.c:6:6: note: expected ‘double **’ but argument is of type ‘double (*)[3]’
 void copy_ptr2d(double **src, double **dest, int rows, int cols);
      ^
main.c:13:23: warning: passing argument 2 of ‘copy_ptr2d’ from incompatible pointer type [-Wincompatible-pointer-types]
     copy_ptr2d(array, array2, ROWS, COLS);
                       ^
main.c:6:6: note: expected ‘double **’ but argument is of type ‘double (*)[3]’
 void copy_ptr2d(double **src, double **dest, int rows, int cols);
      ^
pecan@tux ~ $ ./a.out 
Array { { 12.3, 55.1 }, { 33.6, 21.9, 90.8 } }
Array copy:
Segmentation fault

And under clang 3.9.1:

pecan@tux ~ $ clang main.c 
main.c:13:16: warning: incompatible pointer types passing 'double [2][3]' to parameter of type 'double **' [-Wincompatible-pointer-types]
    copy_ptr2d(array, array2, ROWS, COLS);
               ^~~~~
main.c:6:26: note: passing argument to parameter 'src' here
void copy_ptr2d(double **src, double **dest, int rows, int cols);
                         ^
main.c:13:23: warning: incompatible pointer types passing 'double [2][3]' to parameter of type 'double **' [-Wincompatible-pointer-types]
    copy_ptr2d(array, array2, ROWS, COLS);
                      ^~~~~~
main.c:6:40: note: passing argument to parameter 'dest' here
void copy_ptr2d(double **src, double **dest, int rows, int cols);
                                       ^
2 warnings generated.
pecan@tux ~ $ ./a.out 
Array { { 12.3, 55.1 }, { 33.6, 21.9, 90.8 } }
Array copy:
Segmentation fault

I don't know why I have leak of memory and what I'm doing wrong that I'm getting "Segmentation fault". Can anyone help me?

As you correctly mentioned an array designator used in expressions with rare exceptions is converted to pointer to its first element.

So if you have an array declared like

#define ROWS 2
#define COLS 3

//...

double array[ROWS][COLS];

then passed to a function as an argument as for example

f( array );

it is converted to pointer to its first element.

And what type does the element of the array have?

It has the type double[COLS] . That is elements of a two-dimensional array are one-dimensional arrays.

So a pointer to an array of the type double[COLS] will have type double ( * )[COLS] .

So the corresponding function parameter shall have the same type.

You can declare the function parameter as Variable Length Array (VLA) or as an array with known fixed size.

Here is a demonstrative program that uses two approaches.

This function declaration

    void copy_ptr2d( size_t, size_t, double [][*], double [][*] );

uses (pointers to) variable length arrays as parameters,

This function declaration

    void copy_ptr2d2( double [][COLS], double [][COLS], size_t );

uses (pointers to) arrays with known size COLS at compile time as parameters.

If your compiler does not support VLAs then just remove the code that uses the function with VLAs.

    #include <stdio.h>

    #define ROWS 2
    #define COLS 3

    void copy_ptr2d( size_t, size_t, double [][*], double [][*] );

    void copy_ptr2d2( double [][COLS], double [][COLS], size_t );

    void copy_ptr( double *, double *, size_t );

    int main( void ) 
    {
        double array[ROWS][COLS] = 
        { 
            { 12.3, 55.1 }, 
            { 33.6, 21.9, 90.8 } 
        };

        double array2[ROWS][COLS];

        puts( "array\n=====" );

        for ( size_t i = 0; i < ROWS; i++ )
        {
            for ( size_t j = 0; j < COLS; j++ ) printf( "%4.1f ", array[i][j] );
            putchar( '\n' );
        }

        putchar( '\n' );

        puts( "Array copying...\n" );

        copy_ptr2d( ROWS, COLS, array, array2 );

        puts( "array2\n======" );

        for ( size_t i = 0; i < ROWS; i++ )
        {
            for ( size_t j = 0; j < COLS; j++ ) printf( "%4.1f ", array2[i][j] );
            putchar( '\n' );
        }

        putchar( '\n' );

        puts( "Array copying...\n" );

        copy_ptr2d2( array, array2, ROWS );

        puts( "array2\n======" );

        for ( size_t i = 0; i < ROWS; i++ )
        {
            for ( size_t j = 0; j < COLS; j++ ) printf( "%4.1f ", array2[i][j] );
            putchar( '\n' );
        }

        putchar( '\n' );

        return 0;
    }

    void copy_ptr2d( size_t rows, size_t cols, double src[][cols], double dest[][cols] )
    {
        for ( size_t i = 0; i < rows; i++ )
        {
            copy_ptr( src[i], dest[i], cols );
        }
    }    

    void copy_ptr2d2( double src[][COLS], double dest[][COLS], size_t rows )
    {
        for ( size_t i = 0; i < rows; i++ )
        {
            copy_ptr( src[i], dest[i], COLS );
        }
    }    

    void copy_ptr( double *src, double *dest, size_t len ) 
    {
        while ( len-- ) *dest++ = *src++;
    }

The program output looks like

array
=====
12.3 55.1  0.0 
33.6 21.9 90.8 

Array copying...

array2
======
12.3 55.1  0.0 
33.6 21.9 90.8 

Array copying...

array2
======
12.3 55.1  0.0 
33.6 21.9 90.8 

Try something like this:

#include <stdio.h>
#define ROWS 2
#define COLS 3

void copy_ptr(double src[], double dest[], int len);
void copy_ptr2d(double src[ROWS][COLS], double dest[ROWS][COLS], int rows, int cols);

int main() {
    double array[ROWS][COLS] = { { 12.3, 55.1 }, { 33.6, 21.9, 90.8 } };
    double array2[ROWS][COLS];
    printf("Array { { 12.3, 55.1 }, { 33.6, 21.9, 90.8 } }\n");
    printf("Array copy:\n");
    copy_ptr2d(array, array2, ROWS, COLS);
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            printf("array2[%d][%d]: %lf\n", i, j, array2[i][j]);
        }
        printf("\n");
    }
    return 0;
}

void copy_ptr2d(double src[ROWS][COLS], double dest[ROWS][COLS], int rows, int cols)
{
    for (int i = 0; i < rows; i++) {
        copy_ptr(*src, *dest, cols);
        src++;
        dest++;
    }
}

void copy_ptr(double src[], double dest[], int len)
{
    for (int i = 0; i < len; i++) {
        *dest = *src;
        dest++;
        src++;
    }
}

Do you understand how that works?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM