访问从函数返回指针的结构中的2D数组时的分段错误

时间:2016-09-29 15:50:15

标签: c arrays pointers memory-management dynamic-memory-allocation

我创建了一个具有两个成员(intint**)的结构,并且我将指向此结构的指针从一个函数返回到main()。可以访问结构中的int值。但是,在main()中,当我尝试访问2D数组的元素时,我得到了分段错误:11。

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

typedef struct Square {
    int value;
    int **array;
} Square;

Square * generate();

int main(int argc, char *argv[]){
    Square *sqrptr = generate();

    printf("%d\n", sqrptr -> value);
    /* It prints 1 */

    /* Print out the 2D array */
    for (int i = 0; i < 3; i++){
        for (int j = 0; j < 3 ; j++){
            printf("%d ", *(*((sqrptr -> array) + i) + j));
        }
        printf("\n");
    }
    /* It gives segmentation fault */

    return 0;
}

Square * generate(){
    Square mySquare;
    mySquare.value = 1;
    mySquare.array = malloc(sizeof(int*) * 3);

    /* Initialize the 2D array */
    for (int i = 0; i < 3; i++){
        *(mySquare.array + i) = malloc(sizeof(int) * 3);
        for (int j = 0; j < 3; j++){
            *(*(mySquare.array + i) + j) = 0;
        }
    }

    /* Print out the 2D array */
    for (int i = 0; i < 3; i++){
        for (int j = 0; j < 3l ; j++){
            printf("%d ", *(*(mySquare.array + i) + j));
        }
        printf("\n");
    }
    /* I can see the complete 2D array here */

    Square *sqrptr = &mySquare;

    return sqrptr;    
}

我试图在Square中生成main(),并使用结构的一个指针来访问我的2D数组。它运行正常,所以当我使用从其他函数返回的指针时,我想我错过了一些东西。另一方面,我可以成功访问int value,所以我现在没有线索。

有人可以解释这个分段错误的根本原因吗?谢谢!

2 个答案:

答案 0 :(得分:1)

您正在返回指向局部变量(&mySquare)的指针。堆栈内存(本地变量所在的位置)是函数返回的时间,因此生成的指针指向无效的内存。分配结构,并将指针返回堆内存:

Square *my_square = malloc(sizeof *my_square);
//do stuff
return my_square;

或者将指针传递给堆栈变量作为参数:

Square * generate(Square *my_square)
{
    //in case pointer wasn't provided, allocate
    if (my_square == NULL) {
        my_square = malloc(sizeof *my_square);
        if (!my_square)
            return NULL; // or exit or whatever
    }
    //initialize members. To initialize array to 3x3 zero matrix, you can use:
    for (int i=0;i<3;++i)
        my_square.array[i] = calloc(3, sizeof *my_square->array[i]);
    //or even, if you change array member to type int*:
    my_square.array = calloc(3*3, sizeof *my_square->array);
    //at the end:
    return my_square;
}

后者可以说是最灵活的解决方案:如果你想在堆栈上工作,你可以像这样调用函数:

Square my_stack_square;
generate(&my_stack_square);

如果您需要使用堆内存,可以使用:

Square *my_heap_square = generate(NULL);

正如Jonathan Leffler指出的那样,对于像这样的小结构,按价值返回并不是太大的代价。在堆上获取结构可以像返回任何其他类型一样实现:

Square generate( void )
{
    Square my_square;
    //initialize
    return my_square;
}
//call like so:
Square sq = generate();

这里的想法是你将在generate函数中使用局部变量来创建一个新的正方形,初始化字段,然后返回它。因为在C中,所有内容都通过值传递,这实质上意味着函数会将局部变量的值从generate函数赋值给调用者的作用域sq变量。对于像这样的小结构,这非常好。

更重要的是,编译器要做的一件事是将这些类型的函数优化到我发布的第二个例子中:基本上你的函数将在堆栈内存上创建一个新的Sqaure对象。呼叫者。这个可以发生,这并不是说它会发生。它取决于编译时使用的优​​化级别,以及您要返回的结构的大小。

基本上,如果你想让代码保持与你现在的代码接近,那么最简单的方法就是坚持第一个版本(返回堆指针)。

更灵活的方法是第二个(因为它允许你使用堆栈和堆,具体取决于你如何调用函数)。

目前,使用第三种方法是完全没问题的:编译器很可能会将代码优化为最合理的代码。

答案 1 :(得分:-1)

试试这个:

query