Segmentation error in mex file

1 回表示 (過去 30 日間)
abc
abc 2014 年 1 月 22 日
編集済み: abc 2014 年 1 月 23 日
Here is the mex code I wrote to read in a tab-delimited file. The mex file got created but it causes my MATLAB to end abruptly and give the following error. Can anyone help me where I am going wrong? Please let me know if any further information is required. I have attached the error report though I do not know if it can help
Abnormal termination: Segmentation violation
#include "mex.h"
#include "matrix.h"
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
FILE *ptr_file;
const char **field_names; /* pointers to field names */
char *buf[1024];
char *temp[20];
int count;
int i, j, k, l;
int date_field, mva_field, qc_load_field, air_field, qc_air_field, oil_field, qc_oil_field, wind_a_field, qc_wind_a_field, wind_b_field, qc_wind_b_field, wind_c_field, qc_wind_c_field, tamb1_field, qc_tamb1_field;
char *NAME;
NAME=mxArrayToString(prhs[0]);
count = 0;
//open file to count elements
ptr_file =fopen(NAME,"r");
if (ptr_file != NULL)
{
//skip first 3 lines
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
//start counting no. of elements
while(fgets(buf, sizeof(buf), ptr_file) != NULL)
count++;
fclose(ptr_file);
}
field_names[0] = "date";
field_names[1] = "mva";
field_names[2] = "qc_load";
field_names[3] = "air";
field_names[4] = "qc_air";
field_names[5] = "oil";
field_names[6] = "qc_oil";
field_names[7] = "wind_a";
field_names[8] = "qc_wind_a";
field_names[9] = "wind_b";
field_names[10] = "qc_wind_b";
field_names[11] = "wind_c";
field_names[12] = "qc_wind_c";
field_names[13] = "tamb1";
field_names[14] = "qc_tamb1";
plhs[0] = mxCreateStructMatrix(count, 1, 15, field_names);
plhs[1] = mxCreateDoubleMatrix(1,1,mxREAL);
date_field = mxGetFieldNumber(plhs[0],"date");
mva_field = mxGetFieldNumber(plhs[0],"mva");
qc_load_field = mxGetFieldNumber(plhs[0],"qc_load");
air_field = mxGetFieldNumber(plhs[0],"air");
qc_air_field = mxGetFieldNumber(plhs[0],"qc_air");
oil_field = mxGetFieldNumber(plhs[0],"oil");
qc_oil_field = mxGetFieldNumber(plhs[0],"qc_oil");
wind_a_field = mxGetFieldNumber(plhs[0],"wind_a");
qc_wind_a_field = mxGetFieldNumber(plhs[0],"qc_wind_a");
wind_b_field = mxGetFieldNumber(plhs[0],"wind_b");
qc_wind_b_field = mxGetFieldNumber(plhs[0],"qc_wind_b");
wind_c_field = mxGetFieldNumber(plhs[0],"wind_c");
qc_wind_c_field = mxGetFieldNumber(plhs[0],"qc_wind_c");
tamb1_field = mxGetFieldNumber(plhs[0],"tamb1");
qc_tamb1_field = mxGetFieldNumber(plhs[0],"qc_tamb1");
//open file again for storing elements columnwise
ptr_file =fopen(NAME,"r");
if (ptr_file != NULL)
{
//skip first 3 lines
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
//start collecting data
for(i=0;i<count;i++){ //increment line
//get line
fgets(buf, sizeof(buf), ptr_file);
j=0;
k=0;
//extract first word
while(buf[j] != '\t'){
temp[k] = buf[j];
j++;
k++;
}
temp[k] = '\0';
j++;
mxSetFieldByNumber(plhs[0],i,date_field,mxCreateString(temp));
// strcpy(elem[i].date, temp);
//extract second word
k=0;
while(buf[j] != '\t'){
temp[k] = buf[j];
j++;
k++;
}
temp[k] = '\0';
j++;
// elem[i].mva = atof(temp);
*mxGetPr(plhs[1]) = atof(temp);
mxSetFieldByNumber(plhs[0],i,mva_field,plhs[1]);
//extract third word
k=0;
while(buf[j] != '\t'){
temp[k] = buf[j];
j++;
k++;
}
temp[k] = '\0';
j++;
// strcpy(elem[i].qc_load, temp);
mxSetFieldByNumber(plhs[0],i,qc_load_field,mxCreateString(temp));
// similarly for other fields of the structure.
fclose(ptr_file);
}
}

採用された回答

James Tursa
James Tursa 2014 年 1 月 23 日
編集済み: James Tursa 2014 年 1 月 23 日
I don't see anywhere where you allocate field_names:
const char **field_names; /* pointers to field names */
:
field_names[0] = "date";
That, in and of itself, will bomb your code and MATLAB.
This line will bomb your code if the caller does not request 2 outputs:
plhs[1] = mxCreateDoubleMatrix(1,1,mxREAL);
This line will eventually bomb MATLAB because you can't re-use mxArray pointers (plhs[1]) this way when stuffing them into a cell array or struct array:
mxSetFieldByNumber(plhs[0],i,mva_field,plhs[1]);
You need to create a brand new mxArray for each of these iterative calls, and not re-use plhs[1] over and over. In fact, you should not use plhs[1] here at all ... use a different mxArray pointer. (There is another unofficial way involving bumping up the reference count, but I will not go into that here)
  3 件のコメント
James Tursa
James Tursa 2014 年 1 月 23 日
編集済み: James Tursa 2014 年 1 月 23 日
You only need one mxArray * variable, you just need to create the mxArray that it points to new each iteration. E.g.,
mxArray *mx;
:
LOOP {
mx = mxCreateWhatever(etc);
mxSetFieldByNumber(etc,etc,etc,mx);
}
Note that I have only one pointer variable, mx, but at each iteration it points to a brand new created mxArray.
As for the error you were getting, I could only comment if I saw the code itself (but it sounds like you had a pointer indirection issue).
Finally, no need to apologize. We have all been there and some of this stuff is not well documented (or even documented at all).
abc
abc 2014 年 1 月 23 日
編集済み: abc 2014 年 1 月 23 日
@James, Got it! The error was that it was not initialized at the very beginning of the code I feel. Also I then used mxCreateDoubleScalar instead of mxCreateDoubleMatrix and it is running now. There is only a minor modification I need now. The date I get is in chars and so are some other fields. What I want to do from this in MATLAB is to form these fields into vectors. It is fine for the integer fields but for the fields that contain characters, if I read them all in an array, I get all the characters in a string like'5/1/2000 0:00 5/1/2000 0:01' and so on. I am trying to use mxCreateCharMatrixFromStrings in my mex code but it is not running successfully. There is the error of too few arguments to call
Here is the modification I made for that. I know that the problem is in plhs[0], it cannot be accessed like this I feel. But how can I copy it to a different array of strings? mxGetFieldByNumber will get me only one element of that field at a time. Should I then use a for loop to get all elements into an array of strings and then use this function of mxCreateCharMatrixFromStrings?
mxArray *strtmp
strtmp=mxCreateCharMatrixFromStrings((mwSize)count, (const char **) (plhs[0].date));

サインインしてコメントする。

その他の回答 (1 件)

Bruno Pop-Stefanov
Bruno Pop-Stefanov 2014 年 1 月 22 日
My intuition tells me that you get this error when you try to access temp[20]. You allocate an array temp of only 20 char, but you never check that k is less than 20. It's enough to have 20 characters (or more) between two tabs to crash your program.
Allocate a bigger array for temp and add if statements to check that you never go out of bounds when writing into temp and buf.
  1 件のコメント
abc
abc 2014 年 1 月 22 日
@Bruno, Thank you for your prompt response. I understand what you are saying. I will try making the change you suggested. But I had tested my C code before mexing it and it was running fine. Is it possible that I made a mistake in mexing the file? If it helps I can attach my C code?
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
#define NAME "Cooley3_dynxfmr_20100501000000_20100930235930.txt"
int main(void)
//int mexFunction(int INPUT, char *NAME)
{
//Structure
typedef struct _col{
char date[20];
float mva;
char qc_load[1];
float air;
char qc_air[1];
float oil;
char qc_oil[1];
float wind_a;
char qc_wind_a[1];
float wind_b;
char qc_wind_b[1];
float wind_c;
char qc_wind_c[1];
float tamb1;
char qc_tamb1[1];
} col;
char buf[1024];
char temp[20];
int count = 0;
int i, j, k, l;
//open file to count elements
int ptr_file =fopen(NAME,"r");
if (ptr_file != NULL)
{
//skip first 3 lines
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
//start counting no. of elements
while(fgets(buf, sizeof(buf), ptr_file) != NULL)
count++;
fclose(ptr_file);
}
col *elem = malloc(count*sizeof(col));
//open file again for storing elements columnwise
ptr_file =fopen(NAME,"r");
if (ptr_file != NULL)
{
//skip first 3 lines
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
fgets(buf, sizeof(buf), ptr_file);
//start collecting data
for(i=0;i<count;i++){ //increment line
//get line
fgets(buf, sizeof(buf), ptr_file);
j=0;
k=0;
//extract first word
while(buf[j] != '\t'){
temp[k] = buf[j];
j++;
k++;
}
temp[k] = '\0';
j++;
strcpy(elem[i].date, temp);
//extract second word
k=0;
// strcpy(temp, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
while(buf[j] != '\t'){
temp[k] = buf[j];
j++;
k++;
}
temp[k] = '\0';
j++;
elem[i].mva = atof(temp);
//extract third word
k=0;
// strcpy(temp, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
while(buf[j] != '\t'){
temp[k] = buf[j];
j++;
k++;
}
temp[k] = '\0';
j++;
strcpy(elem[i].qc_load, temp);
//similarly for all other words
}
fclose(ptr_file);
}
printf("%s\t%f\t%s\t%f\t%f\t%s\n", elem[count-1].date, elem[count-1].mva, elem[count-1].qc_load, elem[count-1].air, elem[count-1].wind_a, elem[count-1].qc_wind_c);
free(elem);
return 0;
}

サインインしてコメントする。

カテゴリ

Help Center および File ExchangeWrite C Functions Callable from MATLAB (MEX Files) についてさらに検索

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by