Генерация матрицы с помощью malloc и calloc, вызывающих непонятное поведение - PullRequest
1 голос
/ 02 октября 2019

Я работал над небольшим проектом, который имеет дело с матричными вычислениями на C.

Я проводил некоторые тесты на код, который я написал, и столкнулся с каким-то невероятно запутанным поведением.

Прежде чем я задам этот вопрос, вот некоторые соответствующие коды.

Определение матрицы:

typedef struct
{
    double **matrix;
    int rows;
    int cols;
    int dimensions[2];
    char *str_dims;
} Matrix;

Когда я инициализирую матрицуЯ выделяю память, используя malloc для количества строк, затем перебираю строки, выделяя память для всех столбцов, используя calloc, чтобы они были инициализированы 0.

void init_matrix(Matrix *x, int i, int j)
{
    x->matrix = malloc(x->rows * sizeof(double *));
    for (int i = 0; i < x->rows; i++)
        x->matrix[i] = calloc(x->cols, sizeof(double));
}

У меня также есть функциональность генерации случайной матрицы,

Matrix get_rand_matrix(int i, int j)
{
    Matrix x;
    init_matrix(&x, i, j);
    srand(time(NULL));
    for(int i = 0; i < x.rows; i++)
        for(int j = 0; j < x.cols; j++)
            x.matrix[i][j] = rand();
    return x;
}

Непонятное поведение

Помимо того, что код, скорее всего, был довольно ужасным по стандартам древних, я думал, что он работает правильно. Однако, к счастью, когда я проводил некоторое тестирование (печать матрицы), я бездумно увеличил цикл, отвечающий за итерации по столбцам матрицы, на 1, и это был результат, который я получил. (Отформатирован для вашего удовольствия от просмотра.)

+-------------+--------------+-----+
|739979002.00 | 1854570721.00| 0.00|                                                                                                                                                    
|130427701.00 | 402893063.00 | 0.00|                                                                                                                                                     
|1973118592.00| 135400441.00 | 0.00|                                                                                                                                                    
|1707001127.00| 1093842609.00| 0.00|
+----------------------------------+

Там, где ожидаемый результат был бы,

+-------------+--------------+
|739979002.00 | 1854570721.00|                                                                                                                                                    
|130427701.00 | 402893063.00 |                                                                                                                                                     
|1973118592.00| 135400441.00 |                                                                                                                                                    
|1707001127.00| 1093842609.00|
+----------------------------+

Код, который сгенерировал это только для того, чтобы держать вас в темноте,

Matrix m = get_rand_matrix(4, 2);
for(int i = 0; i < m.rows; i++)
{
    for(int j = 0; j < m.cols + 1; j++)
        printf("%.2lf ", m.matrix[i][j]);
    printf("\n");
}

Вопрос

Честно говоря, я понятия не имею, почему я не получаю segfault и у меня нет доступа к элементам с нулевой инициализацией за пределами (что я бы подумалбыть) границы памяти, которая была выделена. Я могу только предположить, что это ошибка с моей стороны, объединив malloc и calloc вместе, но опять же, я также не понимаю, почему это не сработает.

Кто-нибудь знает, что происходитпочему 0 инициализированных двойников за пределами выделенной памяти? Я довольно новичок в C и распределении памяти в целом, и это меня совершенно поразило.

Интересное дополнение

Некоторые элементы повторяются при увеличении столбцаусловие выхода из цикла (генерируется с помощью j < m.cols + 5)

+-------------------------------------------------------------------------------+
|549092153.00 | 1317836633.00 | 0.00| 0.00 | 218607745.00 |1326282480.00 | 0.00 |                                                                                                               
|218607745.00 | 1326282480.00 | 0.00| 0.00 | 715372192.00 |976468777.00  | 0.00 |                                                                                                               
|715372192.00 | 976468777.00  | 0.00| 0.00 | 103851159.00 |363785358.00  | 0.00 |                                                                                                                
|103851159.00 | 363785358.00  | 0.00| 0.00 |     0.00     | 0.00         | 0.00 |
+-------------------------------------------------------------------------------+

Я увеличил приращение до +1000, и он все еще продолжает печатать 0,00 и повторяющиеся числа.

1 Ответ

0 голосов
/ 02 октября 2019

Если я правильно читаю, то вы просто читаете память вне выделенных массивов. Это может вызвать ошибку сегментации, но не всегда. Этот сайт дает несколько примеров: https://www.geeksforgeeks.org/accessing-array-bounds-ccpp/

В общем, когда вы просите C прочитать из памяти, вы даете ему физический адрес. Если этот адрес существует, и вам разрешено читать его, он вернет вам данные, хранящиеся там, независимо от того, находится ли он в вашем массиве. Это могут быть 0 значений или данные мусора из переменных, которые вы или другие программы написали там. В последнем примере, где вы видите повторяющиеся значения, это потому, что ваша программа выделяла память для матрицы [i] и матрицы [i + 1] последовательно. Поэтому, когда вы начинаете читать за пределами матрицы [i], вы начинаете читать память из матрицы [i + 1].

Кроме того, вы упомянули, что она хранит двойные значения за пределами границ,но это не совсем правильно. C не знает, какой тип данных должен был храниться там, он знает только, что нужно интерпретировать его как двойные, потому что вы сказали это. Если вы разыгрываете все как символы, он будет читать и печатать символы вместо двойных.

...