【问题标题】:Dynamic deallocation of a 2D matrix crashing二维矩阵崩溃的动态解除分配
【发布时间】:2022-01-10 23:06:07
【问题描述】:

我有一个在开始时分配二维矩阵的函数和一个释放它的函数,我在最后使用它。

int** CreatMat(int N){
    int i,**T;
    T = (int**)malloc(sizeof(int*)*N);
    if(T!=NULL){
        for(i=0;i<N;i++){
            T[i]=(int*)malloc(sizeof(int)*N);
            if(T[i]==NULL){
                printf("\nCreatMat()::Allocation failed at block %d",i);
                for(i=i;i>=0;i--){
                    free(T[i]);
                    T[i]=NULL;
                }
                free(T);
                T=NULL;
                return T;
            }
        }
    }
    return T;
}

//Free a dynamic matrix.
void FreeMat(int** T,int N){
    int i;
    for(i=0;i<N;i++){
        free(T[i]);
        T[i]=NULL;
    }
    free(T);
    T = NULL;
}

不知何故,FreeMat() 崩溃了。有什么帮助吗?

完整代码here

~janky 修复代码here

【问题讨论】:

  • 之间分配和释放?
  • 其他在这些矩阵中编辑整数并打印它们的函数,我想在这里保持简短,如果你愿意,我可以添加它们。
  • 这段代码没问题。问题出在您没有向我们展示的代码中。大概你踩到了你不应该踩到的内存,所以通过 valgrind 运行你的代码来找到问题。
  • 欢迎您!请以文本形式发布Minimal Reproducible Example,这是显示故障的最短完整代码(使用运行时输入)。最好的方法是复制/粘贴,在您检查它确实表现出所描述的行为之后。
  • 啊哈,三星级程序员! 砰砰

标签: c function matrix malloc


【解决方案1】:

在函数main()this

int **T, **S;
if(Grids_Init(T, S) != 0)

不影响未初始化的局部变量ST 的值,然后您继续释放这些不确定的指针。

您可以使用函数来初始化其中一个,返回指针并将其分配给T。然后S 也一样。

这比使用三星级指针更可取:请参阅Triple pointers in C: is it a matter of style? 一个答案以

开头

使用三重指针会损害可读性和可维护性。

【讨论】:

    【解决方案2】:

    您不会创建 2D 数组,而只是创建一个指针数组。让您的生活更轻松,并找到一个真正的 2D 数组。另外,请使用正确的尺寸类型size_t

    void CreatMat(size_t N, int (**array)[N])
    {
        *array = malloc(N * sizeof(**array));
    }
    
    int main(void)
    {
        int (*array)[N];
        CreatMat(1000, &array);
    
        /* some code */
    
        free(array);
    }
    

    看看它有多容易。

    【讨论】:

    • 谢谢,这会让事情变得更简单,但是如果我们要定义一个array 类型,我们将如何定义它?我认为,还使用sizeof() 并将*******ptr 传递给它总是会返回8位。
    • @YacineMegrah 我不明白*******ptr。你的评论没有太大意义
    • 我的意思是任何指向sizeof()的指针都会返回8;
    • @YacineMegrah 你不明白我的代码是做什么的。先测试一下,不要假设什么
    • 如何在main() 中访问T[i][j]?是array[i][j]吗?
    【解决方案3】:
    • 将矩阵表示为指针数组是次优的:它会浪费内存和时间,并且引用的局部性会更差
    • 一旦你认为你需要的不仅仅是一个双指针,你应该重新考虑你的数据:使用一些结构来表示矩阵。

    一个简单的例子:


    #include <stdlib.h>
    
    struct matrix {
            unsigned nrow;
            unsigned ncol;
            // int flags;
            double *data;
            };
    
    /*****************************************************************/
    static size_t nrc2idx(unsigned ncol, unsigned irow, unsigned icol)
    {
    return (irow*ncol) + icol;
    }
    
    struct matrix *matrix_new(unsigned nrow, unsigned ncol)
    {
    struct matrix *mp;
    
    mp = malloc (sizeof *mp);
    if (!mp) return mp;
    mp->data = malloc (sizeof *mp->data * nrow * ncol);
    if ( !mp->data) {
            free (mp);
            return NULL;
            }
    mp->nrow = nrow;
    mp->ncol = ncol;
    
    return mp;
    }
    

    现在,使用这种结构将两个矩阵相乘有多难? 示例代码:


    struct matrix *matrix_mult(struct matrix *left, struct matrix *right)
    {
    struct matrix *result;
    unsigned ii,jj;
    
    if (!left || !right) return NULL;
    if (left->ncol != right->nrow) return NULL;
    
    result = matrix_new(left->nrow, right->ncol);
    if (!result) return NULL;
    
    for (ii=0; ii < result->nrow; ii++) {
            for (jj=0; jj < result->ncol; jj++) {
                    size_t uu;
                    unsigned kk;
                    double sum ;
                    sum = 0.0;
                    for (kk=0; kk < left->ncol; kk++) {
                            size_t aa, bb;
                            aa = nrc2idx(left->ncol, ii, kk);
                            bb = nrc2idx(right->ncol, kk, jj);
                            sum += left->data[aa] * right->data[bb];
                            }
                    uu = nrc2idx(result->ncol, ii, jj);
                    result->data[uu] = sum;
                    }
            }
    return result;
    }
    

    【讨论】:

    • 它也不是最理想的。对未签名的大小 (size_t) 使用正确的类型。退货过多容易出错(宁可使用正面检查而不是负面检查)
    • 如果沿着这条路走,你应该使用灵活的数组成员。否则,您还没有真正解决程序碎片化的 malloc 调用和无意义的间接级别。
    • 我说这是一个简化的例子。它只是为了展示“封装”的概念(顺便说一句:恕我直言,灵活的数组成员对 OP 来说太难了,因为他仍在与指针和数组作斗争)
    • 我明白你的意思,但是,我试图为我的项目保留T[i][j] 格式,并且在我实现它时也缺乏维护此代码完整性的技能,因为OP 只是 SDL2_project 的库。
    【解决方案4】:

    回复@0_______

    #include <stdlib.h>
    
    int main(){
        int i,j;
        int (*T)[7];
        //(*T)[7] = malloc(7*sizeof(&(*T))); is wrong
        T = malloc(7*sizeof(*T));
        for(i=0;i<7;i++){
            printf("\n");
            for(j=0;j<7;j++){
                printf("%d  ");
            }
        }
        free(T);
    
        return 0;
    }
    

    【讨论】:

    • 您可能会发现T = malloc( sizeof(int[7][7]) ); 不那么混乱且更易于阅读。
    • @Lundin 如果可以的话,我很想写,“它是否等同于(*T)[7] = malloc(7*sizeof(&amp;(*T)));?”是我的担心。
    • 不,这是错误的!!!如果你想要 7x7 T = malloc(7*sizeof(*T));
    • @Lundin 很容易出错。如果更改T 的定义,则需要更改所有sizeofs。这个想法是使用对象而不是 sizeof 类型的对象,以使您的代码不易出错
    • &amp;* 与不使用任一运算符相同,因此您最终会得到sizeof(T) 而不是预期的sizeof(*T)
    猜你喜欢
    • 2018-07-10
    • 2023-03-06
    • 2020-10-16
    • 2012-10-09
    • 1970-01-01
    • 2017-12-22
    • 2015-06-05
    • 2012-01-22
    • 2017-09-07
    相关资源
    最近更新 更多