Как initiliaze динамического 2D массива внутри структуры в C?

Обновить

February 2019

Просмотры

41 раз

2

Я хочу использовать для-структуры содержат некоторые данные и передавая их между различными функциями в моей программе, эта структура должна содержать динамический массив 2D (я нужна матрица) размеров изменяются в зависимости от аргументов программы. Так что это моя структура:

    struct mystruct {
        int **my2darray;

    }

У меня есть функция, читать номера из файла и должен назначить каждому из них в ячейку массива структуры.

Я пытался сделать это:

    FILE *fp = fopen(filename, "r");
    int rows;
    int columns;
    struct mystruct *result = malloc(sizeof(struct mystruct));
    result->my2darray = malloc(sizeof(int)*rows); 
    int tmp[rows][columns];
    for(int i = 0;i<rows;i++) {
        for(int j = 0;j<columns;j++) {
            fscanf(fp, "%d", &tmp[i][j]); 
        }
        result->my2darray[i]=malloc(sizeof(int)*columns);
        memcpy(result->my2darray[i],tmp[i],sizeof(tmp[i]));
    }

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

    result->my2darray = malloc(sizeof(int)*(rows+1)); 

она отлично работает. Теперь мой вопрос, почему это происходит?

Adl

2 ответы

0

In your provided code example, the variables rows and columns have not been initialized before use, so they can contain anything, but are likely to be equal to 0. Either way, as written, the results will always be unpredictable.

When a 2D array is needed in C, it is useful to encapsulate the memory allocation, and freeing of memory into functions to simplify the task, and improve readability. For example, in your code the following line will create an array of 5 pointers, each pointing to 20 int storage locations: (creating 100 index addressable int locations.)

int main(void)
{
    struct mystruct result = {0}; 

    result.my2darray = Create2D(5, 20);

    if(result.my2darray)
    {
        // use result.my2darray                           
        // then free result.my2darray
        free2D(result.my2darray, 5);
    }
    return 0;
}

Using the following two functions:

int ** Create2D(int c, int r)
{   
    int **arr;
    int    y;

    arr   = calloc(c, sizeof(int *)); //create c pointers (columns)
    for(y=0;y<c;y++)
    {
        arr[y] = calloc(r, sizeof(int)); //create r int locations for each pointer (rows)
    }
    return arr;
}

void free2D(int **arr, int c)
{
    int i;
    if(!arr) return;
    for(i=0;i<c;i++)
    {
        if(arr[i]) 
        {
            free(arr[i]);
            arr[i] = NULL;
        }
    }
    free(arr);
    arr = NULL;
}

Keep in mind that what you have created using this technique is actually 5 different pointer locations each pointing to a set of 20 int locations. This is what facilitates the use of array like indexing, i.e. we can say result.my2darray[1][3] represents the second column, forth row element of a 5X20 array, when it is not really an array at all.

int some_array[5][20];

Is an example of an int array, also allowing access to each element via indexing. The location of elements in this array are stored in one contiguous location in memory.

0

Код выше никогда не устанавливает rowsи columns, таким образом , код не определено поведение от чтения этих значений.

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

result->my2darray = malloc(sizeof(int)*rows);

Вы на самом деле выделение места для массива intвместо массива int *. Если последнее больше (и это скорее всего) , то вы не выделили достаточно мест для массива , и вы снова вызвать неопределенное поведение, написав в конце прошлого выделенной памяти.

Можно выделить необходимое количество пространства, как это:

result->my2darray = malloc(sizeof(int *)*rows);

Или еще лучше, так как это не зависит от фактического типа:

result->my2darray = malloc(sizeof(*result->my2darray)*rows);

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

for(int i = 0;i<rows;i++) {
    result->my2darray[i]=malloc(sizeof(int)*columns);
    for(int j = 0;j<columns;j++) {
        fscanf(fp, "%d", &result->my2darray[i][j]); 
    }
}