realloc()在尝试调整c中矩阵的大小时不能正确复制数据

mwngjboj  于 2023-01-16  发布在  其他
关注(0)|答案(2)|浏览(157)

我正在尝试在c中调整一个矩阵的大小(double**m),理论上realloc()应该把旧矩阵的数据复制到新的调整大小的矩阵中。然而,矩阵中的值没有或者随机复制到新版本中。调整大小本身工作正常,至少它打印了正确的行数和列数。

double **matrix_resize(double **m, int rows, int cols) 
{
    int i;
    double **safe;
    safe = realloc(m, rows * sizeof(double*));
    if (safe == NULL) return NULL;
    m = safe;
    for (i = 0; i < rows; ++i) {
        double *safe2 = realloc(m[i], cols * sizeof(double));
        if (safe2 == NULL) {
            free(safe2);
            free(safe);
            return NULL;
        }
        m[i] = safe2;
        free(safe2);
    }
    free(safe);
    return m;
}

我期望函数返回一个新矩阵,其中包含新的行数和列数,还包含复制到新矩阵中的旧数据。行数和列数是正确的,但它没有正确复制数据。
以下是输出:

old matrix:

-----0---1---2---
0: | 1 | 1 | 1 |
---------------
1: | 1 | 1 | 1 |
---------------
2: | 1 | 1 | 1 |
---------------

resized matrix:

-----0---1---2---3---4---
0: | 0 | 0 | 1 | 0 | 1 |
-------------------------
1: | 0 | 0 | 0 | 0 | 0 |
-------------------------
2: | 1 | 1 | 1 | 0 | 0 |
-------------------------
3: | 0 | 0 | 1 | 0 | 0 |
-------------------------
4: | 0 | 0 | 1 | 0 | 0 |
-------------------------
zf2sa74q

zf2sa74q1#

正如注解中提到的,函数需要新维度和旧维度来增加或减少内存分配。
不要释放realloc直接使用的临时指针(safesafe2)。这由realloc处理

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

double **free_matrix ( double **fm, int rows) {
    if ( fm) {
        while ( rows) {
            --rows;
            free ( fm[rows]);
        }
        free ( fm);
    }
    return NULL;
}

void matrix_show ( double **m, int rows, int cols) {
    for ( int r = 0; r < rows; ++r) {
        for ( int c = 0; c < cols; ++c) {
            printf ( "%6.1f ", m[r][c]);
        }
        printf ( "\n");
    }
}

double **matrix_resize ( double **m, int rows, int cols, int newrows, int newcols) {
    int i = 0;
    int temprows = 0;
    double **temp = NULL;
    double **safe = NULL;

    // shrinking - save pointers to free later
    if ( newrows < rows) {
        temprows = rows - newrows;
        if ( NULL != ( temp = malloc ( sizeof *temp * temprows))) {
            for ( int each = 0; each < temprows; ++each) {
                temp[each] = m[each + newrows];
            }
        } else {
            fprintf ( stderr, "problem malloc **temp");
            return m;
        }
    }
    if ( NULL == ( safe = realloc ( m, newrows * sizeof *m))) {
        fprintf ( stderr, "problem realloc safe");
        temp = free_matrix ( temp, temprows);
        return m;
    }
    m = safe;
    if ( rows < newrows) {
        int items = newrows - rows;
        for ( int each = 0; each < items; ++each) {
            m[each + rows] = NULL;
        }
    }
    for ( i = 0; i < newrows; ++i) {
        double *safe2 = realloc ( m[i], newcols * sizeof **m);
        if (safe2 == NULL) {
            fprintf ( stderr, "problem realloc safe2");
            temp = free_matrix ( temp, temprows);
            return m;
        }
        m[i] = safe2;
        if ( i >= rows) {
            // zero new row
            for ( int each = 0; each < newcols; ++each) {
                m[i][each] = 0;
            }
        } else {
            // zero new elements in row
            for ( int each = cols; each < newcols; ++each) {
                m[i][each] = 0;
            }
        }
    }
    temp = free_matrix ( temp, temprows);
    return m;
}

int main ( void) {
    double **mat = NULL;
    int oldrw = 0;
    int rw = 4;
    int oldcl = 0;
    int cl = 4;

    // 4 x 4
    mat = matrix_resize ( mat, oldrw, oldcl, rw, cl);
    for ( int r = 0; r < rw; ++r) {
        for ( int c = 0; c < cl; ++c) {
            mat[r][c] = r * cl + c + 1;
        }
    }
    matrix_show ( mat, rw, cl);
    printf ( "\n");

    // 6 x 6
    oldrw = rw;
    rw = 6;
    oldcl = cl;
    cl = 6;
    mat = matrix_resize ( mat, oldrw, oldcl, rw, cl);
    matrix_show ( mat, rw, cl);
    printf ( "\n");

    // 7 x 3
    oldrw = rw;
    rw = 7;
    oldcl = cl;
    cl = 3;
    mat = matrix_resize ( mat, oldrw, oldcl, rw, cl);
    matrix_show ( mat, rw, cl);
    printf ( "\n");

    // 2 x 2
    oldrw = rw;
    rw = 2;
    oldcl = cl;
    cl = 2;
    mat = matrix_resize ( mat, oldrw, oldcl, rw, cl);
    matrix_show ( mat, rw, cl);

    mat = free_matrix ( mat, rw);

    return 0;
}
wqnecbli

wqnecbli2#

因为realloc可能会失败,所以我建议分别改变行和列的大小。这样当realloc失败时,你就可以正确地处理它。我写了一个函数,可以调整矩阵的行大小。
如果mNULL,我们只返回calloc而不是realloc
如果m不是NULL,并且old_rows大于new_rows,则我们存储将由realloc丢失的指针以用于进一步的free
如果m不是NULL,并且old_rows小于或等于new_rows,我们只调用realloc并初始化m的新部分。

double **matrix_rerow(double **m, int old_rows, int new_rows)
{
    if (!m)
        return calloc(new_rows,sizeof(*m));
    else if(old_rows > new_rows){
        const int len = old_rows - new_rows;
        double **save = malloc(sizeof(*save)*len);
        if (!save)
            return NULL;
        memcpy(save,m+new_rows,sizeof(*save)*len);
        m = realloc(m,sizeof(*m)*new_rows);
        if (!m){
            free(save);
            return NULL;
        }
        for(int i = 0; i < len; ++i)
            free(save[i]);
        free(save);
        return m;
    }else{
        m = realloc(m,sizeof(*m)*new_rows);
        if (!m)
            return NULL;
        memset(m+old_rows,0,sizeof(*m)*(new_rows-old_rows));
        return m;
    }
}

对于改变列的大小,有matrix_recol。我们使用int**指针代替int。因为每一行调用realloc可能失败。当它失败时,调用者可以观察row以检查正确修改了多少行。

double** matrix_recol(double **m, int *rows, int cols)
{
    const int save = *rows;
    *rows = 0;
    if (!m){
        m = matrix_rerow(NULL, 0, *rows);
        if (!m)
            return NULL;
        for(int i = 0; i < save; ++i,(*rows)++){
            void *ptr = realloc(m[i],sizeof(**m)*cols);
            if (!ptr){
                free(m);
                return NULL;
            }
            m[i] = ptr;
        }
        return m;
    }
    for(int i = 0; i < save; ++i,(*rows)++){
        void *ptr = realloc(m[i],sizeof(**m)*cols);
        if (!ptr)
            return NULL;
        m[i] = ptr;
    }
    return m;
}

相关问题