简体   繁体   English

使用指针在C中复制多维数组时出现分段错误

[英]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. 我需要编写一个函数,它将使用指针在C中复制多维数组。 I'm using gcc 5.4.0 and clang 3.9.1 on Gentoo. 我在Gentoo上使用gcc 5.4.0和clang 3.9.1。 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] . 我使用的事实是使用数组名称与引用第一个元素的引用相同,所以如果我们有二维数组,则array_2d = &array_2d[0]*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: 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: 根据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] . 它的类型为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] . 因此,指向double[COLS]类型数组的指针将具有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. 您可以将函数参数声明为可变长度数组(VLA)或具有已知固定大小的数组。

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. 在编译时使用(指针)具有已知大小COLS的数组作为参数。

If your compiler does not support VLAs then just remove the code that uses the function with VLAs. 如果您的编译器不支持VLA,那么只需删除使用VGA功能的代码。

    #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? 你明白这是怎么回事吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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