Search code examples
cmatlabmex

Calling a .c file from MATLAB yields a segmentation violation


I want to run a two C programs called "hello1.c" and "hello2.c" from matlab.

My hello1.c code is as follows:

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


void funcc(double **f, double **x, long n, long b, double lambda, double theta)
{
    long i;
    long j;
    double u,v,y,z,w;
    y = theta*lambda;
    w = lambda*lambda;
    z = 0.5*(theta+1.0)*w;

    u = 0.0;
    for(i=0;i<n;i++)
    {
        for(j=0;j<b;j++)
        v = fabs(x[i][j]);
        if (v <= lambda)
            u += lambda*v;
        else if (v > y)
            u += z;
        else
            u += 0.5*(v*(2*y - v) - w)/(theta-1.0);
        }
    **f = u;
    return;
}


void mexFunction (int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
    /*set up input arguments */
    double **x       =            mxGetPr(prhs[0]);
    long     n      =      (long)mxGetScalar(prhs[1]);
    long     b      =      (long)mxGetScalar(prhs[2]);
    double  lambda  =            mxGetScalar(prhs[3]);
    double  theta   =            mxGetScalar(prhs[4]);
    int     type    =       (int)mxGetScalar(prhs[5]);

    double **f;


    /* set up output arguments */
    plhs[0] = mxCreateDoubleMatrix(1,1,mxREAL);

    f=mxGetPr(plhs[0]);

    funcc(f, x, n, b, lambda, theta);
    }

My hello2.c code is as follows:

long mymin(double *x, long n)
{
    long i, ind;
    double temp;
    temp = x[0];
    ind = 0;
    for (i=1;i<n;i++)
    {
        if (x[i] < temp)
        {
            ind = i;
            temp = x[i];
        }

    }
    return ind;
}


        void funnn(double *x, double *d, long n, long b, double lambda, double theta)
        {
            long i;
            long j;
            double u,z,w;
            double xtemp[3],ytemp[3];
            z = theta*lambda;
            w = lambda*lambda;
            for(i=0;i<n;i++)
            {
                for(j=0;j<b;j++)
                u = fabs(d[j*n + i]);
                xtemp[0] = min(lambda,max(0,u - lambda));
                xtemp[1] = min(z,max(lambda,(u*(theta-1.0)-z)/(theta-2.0)));
                xtemp[2] = max(z,u);

                ytemp[0] = 0.5*(xtemp[0] - u)*(xtemp[0] - u) + lambda*xtemp[0];
                ytemp[1] = 0.5*(xtemp[1] - u)*(xtemp[1] - u) + 0.5*(xtemp[1]*(-xtemp[1] + 2*z) - w)/(theta-1.0);
                ytemp[2] = 0.5*(xtemp[2] - u)*(xtemp[2] - u) + 0.5*(theta+1.0)*w;
                x[j*n + i] = xtemp[mymin(ytemp,3)];
                x[j*n + i] = d[j*n + i]>= 0 ? x[j*n + i] : -x[j*n + i];
            }
            //return;
        }



        void mexFunction (int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
        {
            /*set up input arguments */
            double* d       =            mxGetPr(prhs[0]);
            long     n      =      (long)mxGetScalar(prhs[1]);
            long     b      =      (long)mxGetScalar(prhs[2]);
            double  lambda  =            mxGetScalar(prhs[3]);
            double  theta   =            mxGetScalar(prhs[4]);

            double *x;


            /* set up output arguments */
            plhs[0] = mxCreateDoubleMatrix(n,b,mxREAL);

            x=mxGetPr(plhs[0]);

            funnn(x, d, n, b, lambda, theta);
        }

The problem is that when I compile my MATLAB code in which it calls my C functions (of course I have already written mex hello1.c and mex hello2.c), MATLAB returns me the screen which exhibits that MATLAB has encountered an internal problem and needs to close. In fact this error was detected while a MEX-file was running.

Is this because my functions mexFunction are not written correctly? Can anyone who knows how to write MEX functions help me?

Any help will be very appreciated!


Solution

  • For hello1.c, mxGetPr in MEX does not give you a double pointer. It gives you a single pointer and for 2D memory, it is in a column-major layout. You have to access the right value in the 2D array by the following syntax, given that i and j are the row and column in the 2D array you want to access:

    ind = j*rows + i;
    

    ... and thus if you want location (i,j) in your 2D array x, simply do:

    double val = x[j*rows + i];
    

    rows is the total number of rows in your 2D array. As such, you will have to correct this in your code to be able to access the 2D array properly. You'll also have to do the same for f as well. In addition, you're missing a pair of curly braces around the second for loop and I'll explain why later.

    Therefore, your function becomes:

    void funcc(double *f, double *x, long n, long b, double lambda, double theta) // Note change in function declaration
    {
        long i;
        long j;
        double u,v,y,z,w;
        y = theta*lambda;
        w = lambda*lambda;
        z = 0.5*(theta+1.0)*w;
    
        u = 0.0;
        // n is the rows, b is the columns
        for(i=0;i<n;i++)
        {
            for(j=0;j<b;j++) { // Added
            v = fabs(x[j*n + i]); // Change here
            if (v <= lambda)
                u += lambda*v;
            else if (v > y)
                u += z;
            else
                u += 0.5*(v*(2*y - v) - w)/(theta-1.0);
            } // Added
        } 
        *f = u; // Change
        //return; // Superfluous
    }
    

    Your mexFunction now becomes:

    void mexFunction (int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
    {
        /*set up input arguments */
        double *x       =            mxGetPr(prhs[0]); // Change
        long     n      =      (long)mxGetScalar(prhs[1]);
        long     b      =      (long)mxGetScalar(prhs[2]);
        double  lambda  =            mxGetScalar(prhs[3]);
        double  theta   =            mxGetScalar(prhs[4]);
        int     type    =       (int)mxGetScalar(prhs[5]);
    
        double *f; // Change
    
        /* set up output arguments */
        plhs[0] = mxCreateDoubleMatrix(1,1,mxREAL);
    
        f=mxGetPr(plhs[0]);
    
        funcc(f, x, n, b, lambda, theta);
    }
    

    For hello2.c, everything is fine except for the second for loop. You simply need to surround the code block with curly braces:

               for(i=0;i<n;i++)
               {
                    for(j=0;j<b;j++) { // added
                    u = fabs(d[j*n + i]);
                    xtemp[0] = min(lambda,max(0,u - lambda));
                    xtemp[1] = min(z,max(lambda,(u*(theta-1.0)-z)/(theta-2.0)));
                    xtemp[2] = max(z,u);
    
                    ytemp[0] = 0.5*(xtemp[0] - u)*(xtemp[0] - u) + lambda*xtemp[0];
                    ytemp[1] = 0.5*(xtemp[1] - u)*(xtemp[1] - u) + 0.5*(xtemp[1]*(-xtemp[1] + 2*z) - w)/(theta-1.0);
                    ytemp[2] = 0.5*(xtemp[2] - u)*(xtemp[2] - u) + 0.5*(theta+1.0)*w;
                    x[j*n + i] = xtemp[mymin(ytemp,3)];
                    x[j*n + i] = d[j*n + i]>= 0 ? x[j*n + i] : -x[j*n + i];
                    } //added
                } 
    

    The reason why you need the extra braces for both files is because if you omit them, C only considers the first line after the loop to be the loop body. The rest of the code after the for loop finishes is executed and not part of the loop which is the reason why you're getting segmentation faults.