Неожиданные данные / неожиданный segfault в динамически распределенном массиве (для двумерного использования) - PullRequest
1 голос
/ 13 октября 2011

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

Я решил распределить гигантский массив (я назвал его данными)и затем создайте массив указателей (я назвал его ячейкой), чтобы иметь возможность обращаться к данным в большом массиве таким образом, чтобы это имело смысл в двумерном контексте (как в матрице [x] [y] вместоданных [арифметика уродливых указателей каждый раз]. Я думал, что это было бы хорошей идеей, потому что она вызывает malloc только один раз, и поэтому было бы быстрее, кроме того, выделенная память находится в одном последовательном блоке, что я считаю (не слишкомзнающий здесь) - это действительно хорошая вещь в некоторых системах из-за накладных расходов на отслеживание выделенных блоков памяти.

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

typedef struct {
    unsigned int sizeX;
    unsigned int sizeY;
    int **cell;
    int *data; /* FOR INTERNAL USE ONLY */
} matrix;

matrix * matrix_malloc(unsigned int, unsigned int);
void matrix_free(matrix *);
void matrix_zero(matrix *);
void matrix_print(matrix *);

int
main(int argc, char *argv[])
{
    int y, x;
    matrix  *theMatrix = NULL;

    if (argc != 3) {
        fprintf(stderr, "usage: %s sizeX sizeY\n", argv[0]);
        return 1;
    }

    x = atoi(argv[1]);
    y = atoi(argv[2]);

    if (x < 10 || y < 10) {
        fprintf(stderr, "usage: sizeX and sizeY must be >= 10\n");
        return 1;
    }

    if ((theMatrix = matrix_malloc(x, y)) == NULL)
        return 1;

    matrix_zero(theMatrix);
    /* lots of modification of the contents of the matrix would happen here */
    matrix_print(theMatrix);

    matrix_free(theMatrix);

    return 0;
}

matrix *
matrix_malloc(unsigned int sizeX, unsigned int sizeY)
{
    int i;
    matrix  *mat;

    if ((mat = malloc(sizeof(matrix))) == NULL) {
        return NULL;
    }

    if ((mat->data = malloc(sizeX * sizeY * sizeof(int))) == NULL) {
        free(mat);
        mat = NULL;
        return NULL;
    }
    if ((mat->cell = malloc(sizeX * sizeof(int *))) == NULL) {
        free(mat->data);
        free(mat);
        mat = NULL;
        return NULL;
    }
    mat->sizeX = sizeX;
    mat->sizeY = sizeY;
    for (i = 0; i < sizeX; i++) {
        mat->cell[i] = mat->data + mat->sizeX * i;
    }

    return mat;
}

void
matrix_free(matrix *mat) {
    free(mat->cell);
    free(mat->data);
    free(mat);
    mat = NULL;
}

void
matrix_zero(matrix *mat)
{
    memset(mat->data, 0, mat->sizeX * mat->sizeY * sizeof(int));
}

void
matrix_print(matrix *mat)
{
    unsigned int    x, y;

    for (x = 0; x < mat->sizeX; x++) {
        for (y = 0; y < mat->sizeY; y++)
            printf("%d ", mat->cell[x][y]);
        printf("\n");
    }
}

Когда я запускаю вышеупомянутую программу как ./a.out 10 10, проблем не возникает, но когда я указываю30 20 вместо 10 10, я сталкиваюсь с некоторыми проблемами.

В MacOSX (10.6.7) я получаю:

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 540024880 540024880 540024880 540024880 540024880 808465461 943207474 875896880 875704368 540031032 
842216505 926168880 926425140 909719605 540031032 926234424 909325360 875896888 825438256 540160816 10 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 

и затем он корректно завершается.

На OpenBSD (4.7) Я получаю это далеко:

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 

, а затем это просто segfaults

Моя первоначальная мысль состояла в том, что при выделении достаточно больших блоков памяти, которые они пересекают страницу, возникла какая-то проблема.границы, но когда я использую 50 50 в качестве размера, он работает нормально.

Я сузил это до такой степени, и попытался Google (хотя я не совсем уверен, что именно я должен искать: |) и спросил несколько моих друзей, но это все их поставило в тупик.

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

Если кто-топожалуйста, укажите мне правильное направление, возможно, укажите проблему или укажите какую-нибудь соответствующую документацию, я был бы очень признателен.

Ответы [ 2 ]

4 голосов
/ 13 октября 2011
for (i = 0; i < sizeX; i++) {
        mat->cell[i] = mat->data + mat->sizeX * i;
    }

Один из этих SizeX должен иметь размер Y.

3 голосов
/ 13 октября 2011
for (i = 0; i < sizeX; i++) {
    mat->cell[i] = mat->data + mat->sizeX * i;
}

Представьте, что sizeX равен 100, а sizeY равен 2. Здесь вы выкладываете строки sizeX, 100 из них, каждое из sizeX целых, 100 из них. По электронной почте Ой.

То, что mat->sizeX должно быть mat->sizeY. У вас есть строки sizeX, каждая из которых содержит элементы sizeY. Поэтому вам нужно пропустить целые числа размера Y, чтобы перейти к следующей строке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...