c - 由 C 代码制作的 mex 在循环中崩溃,但运行一次时不会崩溃

标签 c matlab memory mex calloc

我有一个用 C 编写的函数,我将其转换为 matlab 可执行文件(mex 文件)。当从 matlab 命令行调用一次时,C 函数工作正常,但是当在 for 循环中调用 1000 多次时,它会自发崩溃。即使我在 for 循环的每次迭代中为其提供相同的输入,也会发生这种情况。

我担心我有一个潜伏的 c-bug。重复内存分配的一些问题,但我不知道足够的 c 来修复它:(

我已将问题范围缩小到下面代码中的 WHILE 循环(如果在编译之前将整个 while 循环注释掉,问题就会消失)。请帮忙!

    #include "mex.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>

    int sum_array(double a[], int from ,int to);
    // to compile this code in matlab do: mex -v ranksort.c

   void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray  *prhs[]){
           #define B_OUT       plhs[0]
           #define A_IN        prhs[0]

           int i,j,count,M,N; //declare some integers
           double *list,*sort_list,*rank_idx,*sort_idx,*ranksOrigOrder;//declare some pointers to doubles which will be allocated dynamically
           int *rank_list,*tielocs,*orig_indices;

           //set values based on input:
           M=mxGetM(A_IN);//get input row num
           N=mxGetN(A_IN);//get input col num
           if (M>N)
                 count=M; //get dimensions of A (columns...data must always be in columns)
           else
                 count=N;

           list =mxGetPr(A_IN); //grab data from pointer to inputted data
           sort_list = calloc(count,sizeof(double)); //allocate size and fill w/zeros all my 'double' arrays
           rank_idx =calloc(count,sizeof(double));
           sort_idx=calloc(count,sizeof(double));
           ranksOrigOrder=calloc(count,sizeof(double));
           tielocs =calloc(count+2,sizeof(double));
           orig_indices=calloc(count,sizeof(int)); //allocate size and fill w/ zeros all my 'int' arrays
           rank_list =calloc(count,sizeof(int));

            if (sort_list==NULL||tielocs==NULL||rank_list==NULL||orig_indices==NULL||ranksOrigOrder==NULL||rank_idx==NULL||list==NULL){ puts ("Error (re)allocating memory"); exit (1); }

           B_OUT = mxCreateDoubleMatrix(M, N, mxREAL); //create a matlab-style struct for output...
           ranksOrigOrder = mxGetPr(B_OUT); // set in-code variable to its pointer

           /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CODE BODY STARTS HERE ~~~~~~~~~~~~~~~~~~~~*/
           /*Calculate the rank for each element in the arr_list*/
           for(i=0; i<count; i++){
                 for(j=0; j<i; j++){
                     if(list[i] >= list[j])
                           rank_list[i]++;
                     else
                           rank_list[j]++;
                  }
            }

           for(i=0; i<count; i++){
               sort_list[rank_list[i]] = list[i];
               orig_indices[rank_list[i]] =i;
               sort_idx[i]=i+1;
           }
           int tiesIdx=0; int *ties = NULL;
           for (i=0; i<count-1;i++){
                 if (sort_list[i]>= sort_list[i+1]){
                 ties = (int*) realloc (ties, (tiesIdx) *sizeof(int));       //reallocate size of array
                 if (ties==NULL){ puts ("Error (re)allocating memory"); exit (1); }
                  ties[tiesIdx]=i; //add location of tie to newly grown array  
                   tiesIdx++; //found a tie
                  }
           }
           // // append 2 after last element to ties
           ties = (int*) realloc (ties, (tiesIdx) * sizeof(int));         

           //reallocate size of array
           if (ties==NULL){ puts ("Error (re)allocating memory"); exit (1);           }
           ties[tiesIdx]=count+1;
           tiesIdx++;

           int tiecount=0; //step thru all the found ties

           // NO IN-LOOP CRASHING if this while loop is commented out....
           while (tiecount<tiesIdx){
                 int tiestart =ties[tiecount]; //grab this tie to check if it is one of a pair or a member of an island of consecutives
                 int ntied=2;

                 while (ties[tiecount+1] == ties[tiecount] + 1){                         //while it's a consecutive one...
                        tiecount++;
                        ntied++;
                 }
                 double mysum = (double)sum_array(sort_idx,tiestart,tiestart+ntied)/(double)ntied;        

                 for (int t=tiestart; t<tiestart+ntied;t++){
                       sort_idx[t]=mysum;
                  }
                 tiecount++;
           }

           for (i=0; i<count;i++){
                ranksOrigOrder[orig_indices[i]]=sort_idx[i];
           }

           free(sort_list);
           free(tielocs);
           free(rank_list);
           free(orig_indices);
           free(rank_idx);
           free(sort_idx);
           return;
   }
    int sum_array(double a[], int from ,int to){
        int i, sum=0;
        for (i=from; i<to; i++){
               sum = sum + (int)a[i];
         }
        return(sum);
     }    

最佳答案

看一下这段代码:

 // // append 2 after last element to ties
 ties = (int*) realloc (ties, (tiesIdx) * sizeof(int));

 //reallocate size of array
 if (ties==NULL){ puts ("Error (re)allocating memory"); exit (1);           }
 ties[tiesIdx]=count+1;
 tiesIdx++;

 int tiecount=0; //step thru all the found ties

 // NO IN-LOOP CRASHING if this while loop is commented out....
 while (tiecount<tiesIdx){

您正在为 tiesIdx 重新分配空间元素,在您想要访问 tiesIdx 之后不久ties 的位置大批。这是Undefined Behaviour因为你的数组必须从 0 到 tiesIdx-1 进行索引

之后您将包含 tiesIdx 1,然后对增加的 var 执行循环,这显然是 Undefined Behaviour因为您将索引数组越界。

此外,内部循环:

       while (ties[tiecount+1] == ties[tiecount] + 1){                         //while it's a consecutive one...
              tiecount++;
              ntied++;
       }

不检查数组边界:如果关系的所有元素都是连续的,您将索引数组越界。

注意:ranksOrigOrder 上存在内存泄漏它不是free() .

关于c - 由 C 代码制作的 mex 在循环中崩溃,但运行一次时不会崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36274913/

相关文章:

c - RISC-V汇编-堆栈布局-函数调用

arrays - 距Matlab中的线集合一定距离的表面积,类似于轮廓?

matlab - 什么是科学记数法中的小 "e"/Matlab中的 double

c++ - 为什么需要内存对齐?

ios - 我的应用程序内存问题警告,但应用程序不会消耗大量内存

c - 停止 fgetc 根据输入数 + 1 重复循环?

c - #Include 在编译 Linux 内核时如何工作

iOS 并不总是调用 didReceiveMemoryWarning

OpenACC 的 C/预处理器标准宏?

matlab - 使用 fft 和 ifft 改变频率不使用整数