неправильный многомерный массив в функции

c pointers multidimensional-array malloc

7736 просмотра

7 ответа

4085 Репутация автора

Я пытаюсь выделить 2d массив в C-программе. Он отлично работает в основной функции, как это (как описано здесь ):

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

int main(int argc, char ** argv)
{
    int ** grid;
    int i, nrows=10, ncols=10;
    grid = malloc( sizeof(int *) * nrows);

    if (grid == NULL){
        printf("ERROR: out of memory\n");
        return 1;
    }

    for (i=0;i<nrows;i++){
        grid[i] = malloc( sizeof(int) * ncols);
        if (grid[i] == NULL){
            printf("ERROR: out of memory\n");
            return 1;
        }
    }
    printf("Allocated!\n");

    grid[5][6] = 15;
    printf("%d\n", grid[5][6]);
    return 0;
}

Но так как мне приходилось делать это несколько раз с разными массивами, я пытался переместить код в отдельную функцию.

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

int malloc2d(int ** grid, int nrows, int ncols){
    int i;
    grid = malloc( sizeof(int *) * nrows);

    if (grid == NULL){
        printf("ERROR: out of memory\n");
        return 1;
    }

    for (i=0;i<nrows;i++){
        grid[i] = malloc( sizeof(int) * ncols);
        if (grid[i] == NULL){
            printf("ERROR: out of memory\n");
            return 1;
        }
    }
    printf("Allocated!\n");
    return 0;
}

int main(int argc, char ** argv)
{
    int ** grid;

    malloc2d(grid, 10, 10);
    grid[5][6] = 15;
    printf("%d\n", grid[5][6]);
    return 0;
}

Однако, несмотря на то, что он не жалуется при распределении, я получаю ошибку сегментации при доступе к массиву. Я читаю разные посты на разложившихся массивах и похожих темах, но до сих пор не могу понять, как решить эту проблему. Я полагаю, что неправильно передаю 2d массив функции.

Большое спасибо.

Автор: gozzilli Источник Размещён: 01.05.2011 01:11

Ответы (7)


0 плюса

1442 Репутация автора

C на самом деле всегда передается по значению, поэтому, когда вы передаете 'grid', вы передаете значение, и функция модифицирует свою собственную локальную копию. Попробуйте вместо этого ввести '& grid' и соответствующим образом изменить malloc2d.

Автор: darth happyface Размещён: 01.05.2011 01:13

8 плюса

74632 Репутация автора

Решение

Это не многомерный массив; это одномерный массив, содержащий указатели на одномерные массивы. Многомерные массивы не содержат указателей; они единичные блоки памяти.

Ваша проблема здесь в том, что у вас есть указатель на указатель, и вы пытаетесь вернуть его из своей функции через параметр. Если вы собираетесь это сделать, вам понадобится указатель на указатель на указатель в качестве параметра, и вам придется передать адрес указателя на указатель на метод. Если вы этого не сделаете, вы не измените значение переменной gridв main- вы меняете значение, которое было скопировано в качестве параметра в malloc2dфункцию. Поскольку gridin mainостается неинициализированным, вы получаете неопределенное поведение.

Вот пример того, что я имею в виду как исправление:

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

int malloc2d(int *** grid, int nrows, int ncols){
    int i;
    *grid = malloc( sizeof(int *) * nrows);

    if (*grid == NULL){
        printf("ERROR: out of memory\n");
        return 1;
    }

    for (i=0;i<nrows;i++){
        (*grid)[i] = malloc( sizeof(int) * ncols);
        if ((*grid)[i] == NULL){
            printf("ERROR: out of memory\n");
            return 1;
        }
    }
    printf("Allocated!\n");
    return 0;
}

int main(int argc, char ** argv)
{
    int ** grid;

    malloc2d(&grid, 10, 10);
    grid[5][6] = 15;
    printf("%d\n", grid[5][6]);
    return 0;
}

Дополнительные примечания:

  • В случае сбоя одного выделения вы теряете выделение для первого массива, а также выделение для всех предыдущих строк. Вы должны позвонить freeна них, прежде чем вернуться.
  • Вы возвращаетесь через параметр, даже если вам это не нужно. Если бы я писал это, я бы сделал возврат метода int **и сообщил об ошибке, возвращая 0.
Автор: Billy ONeal Размещён: 01.05.2011 01:15

3 плюса

62504 Репутация автора

Вот ваша функция, исправлена:

int malloc2d(int *** grid, int nrows, int ncols){
    int i;
    *grid = (int**)malloc( sizeof(int *) * nrows);

    if (*grid == NULL){
        printf("ERROR: out of memory\n");
        return 1;
    }

    for (i=0;i<nrows;i++){

        (*grid)[i] = (int*)malloc( sizeof(int) * ncols);
        if ((*grid)[i] == NULL){
            printf("ERROR: out of memory\n");
            return 1;
        }
    }
    printf("Allocated!\n");
    return 0;
}

int main(int argc, char ** argv)
{
    int ** grid;

    malloc2d(&grid, 10, 10);
    grid[5][6] = 15;
    printf("%d\n", grid[5][6]);
    return 0;
}

Обратите внимание , что функция в настоящее время recieves int***и вы передаете адрес из вашей int**функции. Затем функция разыменовывает, int***чтобы поместить в нее адрес выделенного блока памяти.

Автор: Seth Carnegie Размещён: 01.05.2011 01:16

2 плюса

29018 Репутация автора

C это передать по значению. И чтобы подвести итог ошибки, которую вы делаете, этот пример должен быть полезен -

void foo( int *temp )
{
     temp = malloc(sizeof(int)) ;
     // temp is assigned to point to new location but the actual variable
     // passed from main do not point to the location temp is pointing to.

     *temp = 10 ;
}

int main()
{
     int *ptr ;
     foo( ptr ) ;

     // ptr is still unintialized
     *ptr = 5 ; // Segmentation fault or Undefined behavior

     return 0;
}

Итак, вместо этого вы должны сделать -

void foo( int **temp )
{
    *temp = malloc(sizeof (int) );
    // ...
}

А теперь вызовите функцию как foo(&ptr);в main()функции.

Автор: Mahesh Размещён: 01.05.2011 01:16

0 плюса

30095 Репутация автора

Это не ваша проблема с ошибкой сегментации, но вы должны рассмотреть возможность использования одного вызова malloc для распределения всей необходимой памяти в сетке.

grid = malloc (nrows * ncols * sizeof(int *))

Посмотрите на ответ Bill ONeary относительно указателя указателя указателя.

Автор: Heisenbug Размещён: 01.05.2011 01:16

1 плюс

40936 Репутация автора

Если вы все еще хотите malloc2dвернуть код состояния, параметр должен иметь тип int***:

int malloc2d(int *** grid, int nrows, int ncols){

И вам нужно использовать *gridдля ссылки на предоставленный буфер:

    int i;
    *grid = malloc( sizeof(int *) * nrows);

    if (*grid == NULL){
        printf("ERROR: out of memory\n");
        return 1;
    }

    for (i=0;i<nrows;i++){
        (*grid)[i] = malloc( sizeof(int) * ncols);
        if ((*grid)[i] == NULL){
            printf("ERROR: out of memory\n");
            return 1;
        }
    }
    printf("Allocated!\n");
    return 0;
}

Затем при вызове malloc2dпередайте ему адрес int**для заполнения:

int ** grid;

malloc2d(&grid, 10, 10);
Автор: Jon Purdy Размещён: 01.05.2011 01:16

0 плюса

3324 Репутация автора

Короче должно быть ниже со свободными (!) И инициализированными значениями для каждого элемента сетки:

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

#define NROWS 10
#define NCOLS 10

int main()
{
    int (* grid)[NCOLS] = calloc(NROWS,sizeof*grid);

    /* no more needed here malloc2d(grid, 10, 10); */
    grid[5][6] = 15;
    printf("%d\n", grid[5][6]);
    free(grid); /* every c/malloc need a free */
    return 0;
}
Автор: user411313 Размещён: 01.05.2011 08:04
Вопросы из категории :
32x32