【问题标题】:Segmentation fault when copy a multidimensional array in C using pointers使用指针在 C 中复制多维数组时出现分段错误
【发布时间】:2017-10-12 21:25:13
【问题描述】:

我需要编写一个函数,该函数将使用指针在 C 中复制多维数组。我在 Gentoo 上使用 gcc 5.4.0 和 clang 3.9.1。我使用了一个事实,即使用数组的名称与引用它的第一个元素的地址相同,所以如果我们有二维数组,那么array_2d = &array_2d[0]*array_2d = *(&array_2d[0]) = array_2d[0]。这是我的代码:

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

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

并且在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

我不知道为什么我有内存泄漏以及我做错了什么,我得到了“分段错误”。谁能帮帮我?

【问题讨论】:

  • 我喜欢这个解决方案 printf("Array { { { 12.3, 55.1 }, { 33.6, 21.9, 90.8 } }\n");但是 ROWS 等于例如 10 呢?:)
  • 二维数组不是指向指针的指针。
  • 那些警告告诉你一些事情。 double[][] 与 double ** 不同。
  • 我投票决定将此问题作为题外话结束,因为 OP 只需要学习基本的东西——至少要了解双精度、整数、指针和数组之间的区别。类似的问题一直在这里被问到。零努力问题(即 OP 没有做任何事情来找到答案)
  • 修复this

标签: c arrays pointers multidimensional-array


【解决方案1】:

正如您正确提到的,在表达式中使用的数组指示符(极少例外)被转换为指向其第一个元素的指针。

所以如果你有一个声明为类似的数组

#define ROWS 2
#define COLS 3

//...

double array[ROWS][COLS];

然后作为参数传递给函数,例如

f( array );

它被转换为指向它的第一个元素的指针。

数组的元素有什么类型?

它的类型为double[COLS]。也就是说二维数组的元素是一维数组。

因此,指向double[COLS] 类型数组的指针将具有double ( * )[COLS] 类型。

所以对应的函数参数应该是同类型的。

您可以将函数参数声明为可变长度数组 (VLA) 或已知固定大小的数组。

这是一个使用两种方法的演示程序。

这个函数声明

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

使用(指向)可变长度数组作为参数,

这个函数声明

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

在编译时使用(指向)具有已知大小 COLS 的数组作为参数。

如果您的编译器不支持 VLA,那么只需删除使用 VLA 的函数的代码。

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

程序输出的样子

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 

【讨论】:

    【解决方案2】:

    试试这样的:

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

    你明白它是如何工作的吗?

    【讨论】:

    • 好吧,说句公道话,我读得很流利,而 并没有完全跟踪(尽管我会读足够多的时间)——情况往往如此带代码的答案。一些关于为什么这样做的技术解释将为答案增加价值。
    • 我的代码展示了如何使用二维数组来实现这些功能。在我的代码之前,函数接受 double ** 的参数,现在它们接受具有定义大小的 double src[][],就像提出这个问题的编码员使用的参数一样。如果这还不足以暗示下一步该做什么,而没有字面意思地说,我不知道是什么。我可以把它送人,但我从来没有那样学到任何东西。在这种情况下,我宁愿当老师,因为这个问题对 C 来说非常具体。对 C 来说非常具体。
    • 不,这是可以理解的。 (我以培训实习生为生,所以我完全理解您来自哪里。)但是,您还必须记住,(a)您正在为更多的人写答案,而不仅仅是 OP,并且(b)不同人们有不同的经验水平,所以对你来说显而易见的东西对他们来说可能并不明显。我发现提供解释并省略代码通常比提供代码并省略解释更有帮助。这样一来,他们就必须在根据您的解释自己编写代码中动脑筋。 OP 可以按原样 c/p。
    • TL;DR - “我听到了,我忘记了。我看到了,我记得了。我做了,我明白了。”如果他们必须写它,他们会学到更多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 1970-01-01
    • 1970-01-01
    • 2019-02-12
    • 1970-01-01
    • 2017-07-24
    • 1970-01-01
    相关资源
    最近更新 更多