0

Я создал структуру, которая имеет два члена (int и int**), и я возвращаю указатель на эту структуру от одной функции до main(). Достаточно получить доступ к значению int в структуре. Однако в main() у меня возникла ошибка сегментации: 11, когда я попытался получить доступ к элементу 2D-массива.Ошибка сегментации при доступе к двумерному массиву в структуре, указатель которой возвращается из функции

#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, так что теперь у меня нет подсказок.

Может кто-нибудь объяснить причину этой ошибки сегментации? Благодаря!

+0

Square * generate(); не имеет смысла для моих глаз –

+1

@SaeidYazdani Я только что объявил функцию до 'main()'. –

+1

Вы возвращаете адрес локальной переменной. Эта переменная больше не существует, когда основная функция хочет ее использовать. – mch

ответ

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

Как указал Джонатан Леффлер, для небольшой структуры, такой как это, возвращение по значению не слишком дорого. Получение структура на куче может быть достигнуто таким же образом, как возвращение любого другого типа:

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

Идея заключается в том, что вы будете использовать локальную переменную в функции generate создать новый квадрат, инициализировать поля , а затем верните его. Потому что в C все передано значением, это по существу означает, что функция назначит значение локальной переменной из функции генерации в переменную sq вызывающего. Для небольших структур, таких как это, это прекрасно.

Более того, для компиляторов достаточно просто оптимизировать эти функции в эквиваленте второго примера, который я опубликовал: по существу, ваша функция будет создавать новый объект Sqaure в стеке памяти вызывающего. Это может произошло, это не значит, что это будет. Это зависит от уровней оптимизации, используемых при компиляции, и от размера возвращаемой структуры.

В принципе, если вы хотите, чтобы код был как можно ближе к тому, что у вас есть, вероятно, проще всего придерживаться первой версии (возвращая указатель кучи).

Более гибкий подход - второй (поскольку он позволяет использовать стек и кучу в зависимости от того, как вы вызываете функцию).

На данный момент, используя третий подход, это прекрасно: компилятор, скорее всего, оптимизирует код, чтобы все это имело смысл.

+1

'is when' ->' теряется когда'? 'P' ->' {'? Вы хотите, чтобы вы хотели вернуть квадрат * в примере 2? – 4386427

+0

В примере 2 не все пути управления возвращают значение. –

+0

Упс, я вижу, что это ** ** специально для примера 2 возвращает указатель. – 4386427

-1

Попробуйте это:

#include<stdio.h> 
#include<string.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 */ 
    int i,j; 
    for (i = 0; i < 3; i++){ 
     for (j = 0; j < 3 ; j++){ 
      printf("%d ", *(*((sqrptr -> array) + i) + j)); 
     } 
     printf("\n"); 
    } 
    /* It gives segmentation fault */ 

    return 0; 
} 

Square * generate(){ 
    Square* mySquare = (Square*) malloc(sizeof(Square)); //c++ compiler 
    //Square* mySquare = (void*) malloc(sizeof(Square)); //c compiler 
    mySquare->value = 1; 
    mySquare->array = malloc(sizeof(int*) * 3); 

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

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

Не отбрасывайте возврат 'malloc' & co в C –

+0

Я скомпилировал с g ++, но да, это должно быть' (void *) 'с компилятором c –

+1

Не должно было НИКАКОГО CAST вообще. Указатели каста в C [считаются вредными] (http://stackoverflow.com/a/605858/1230836) –

Смежные вопросы