EXCEPTION_ACCESS_VIOLATION when using large array in C - c

this is another issue I'm stuck with. First of all I'm trying to read a level-4 matlab file which contains information exported from PicoScope 6, it reads four arrays from the file, A, Tstart, Tinterval and Length. Array number one is the largest by far, it contains 1000004 values, however the other three only contains one value each. When I exectue the code below it successfully reads the file, stores it into a multidimensional array but fails when I'm trying to use the array.
#include <jni.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <matio.h>
#include "ReadMatFile.h"
//macros
#define getLength(x) (sizeof(x) / sizeof(x[0]))
//variables
double *dataMatrix[4];
int innerSize[getLength(dataMatrix)];
//functions
jobjectArray convertToArray(JNIEnv *env, double **data, int length1D,
int *length2D);
JNIEXPORT jdoubleArray JNICALL Java_ReadMatFile_readMatFile(JNIEnv *env,
jobject object, jstring str) {
const char *fileName = (*env)->GetStringUTFChars(env, str, 0);
mat_t *matfp;
matvar_t *matvar;
matfp = Mat_Open(fileName, MAT_ACC_RDONLY | MAT_FT_MAT4);
if ( NULL == matfp) {
fprintf(stderr, "Error opening MAT file %s\n", fileName);
return NULL;
}
int i = 0;
while ( NULL != (matvar = Mat_VarReadNext(matfp))) {
double *data = (double*) (matvar->data);
dataMatrix[i] = data;
innerSize[i] = (int) matvar->nbytes / matvar->data_size;
Mat_VarFree(matvar);
matvar = NULL;
i++;
}
Mat_Close(matfp);
(*env)->ReleaseStringUTFChars(env, str, fileName);
int s;
for(s = 0; s < innerSize[0]; s++)
printf("A[%d] = %e\n", s, dataMatrix[0][s]); /* Fails here */
return NULL;
//return convertToArray(env, dataMatrix, getLength(dataMatrix) ,innerSize);
}
jobjectArray convertToArray(JNIEnv *env, double **data, int length1D,
int *length2D) {
jsize outerSize = (jsize) length1D;
jclass class = (*env)->FindClass(env, "[D");
jobjectArray outer = (*env)->NewObjectArray(env, outerSize, class, 0);
jsize i;
for (i = 0; i < outerSize; i++) {
jsize innerSize = (jsize) length2D[i];
jdoubleArray inner = (*env)->NewDoubleArray(env, innerSize);
(*env)->SetDoubleArrayRegion(env, inner, 0, innerSize, data[i]);
(*env)->SetObjectArrayElement(env, outer, i, inner);
(*env)->DeleteLocalRef(env, inner);
}
return outer;
}
What is the cause of this? It creates a minidump when I run this application. Is the array too large?
A fix for this and also a explanation of what is wrong would be much appreciated!
Thanks in advance folks.

I suspect your problem is in the following code:
double *data = (double*) (matvar->data);
dataMatrix[i] = data;
innerSize[i] = (int) matvar->nbytes / matvar->data_size;
Mat_VarFree(matvar); // whoopsie
If Mat_VarFree does what I think it does, matvar->data is no longer a valid pointer, meaning dataMatrix[i] is no longer a valid pointer, hence the crash.
I think what you intend to do is something more along the lines of
innerSize[i] = matvar->nbytes / matvar->data_size;
dataMatrix[i] = malloc( sizeof *dataMatrix[i] * innerSize[i] );
if ( dataMatrix[i] )
memcpy( dataMatrix[i], matvar->data, matvar->nbytes );
Mat_VarFree( matvar );
that is, create a local copy of the data in matvar->data and save it to your dataMatrix. In your original code, all you copied was a pointer value; you never created a separate copy of your data.

Related

How to easily parse an array from an INI file to an array in C?

In my code I use the iniparser (https://github.com/ndevilla/iniparser) to parse double, int and strings. However, I'm interested into parsing arrays, delimited with comma such as
arr = val1, val2, ..., valn
Any easy and quick way, like the parser above?
The best way is to make your own structure.
You can find easily on the web structures that you can import for your code. Another solution, not so great is to put your values as void pointers. And when you want to take your values back you take the void pointer and cast it with which kind of value you want( int,double,char ect). But this may conflict the values so you must be careful. You must know what kind value is in which cell of the pointer. It is not the ideal way but its a cheat way to avoid making your own structure.
You can use libconfini, which has array support.
test.conf:
arr = val1, val2, ..., valn
test.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <confini.h>
struct my_conf_T {
size_t arrlen;
char ** arr;
};
static int my_listnr (IniDispatch * this, void * v_conf) {
#define conf ((struct my_conf_T *) v_conf)
if (ini_string_match_si("arr", this->data, this->format)) {
conf->arrlen = ini_array_get_length(this->value, INI_COMMA, this->format);
if (!conf->arrlen || !this->v_len) {
/* Array is empty */
return 0;
}
conf->arr = (char **) malloc(conf->arrlen * sizeof(char *) + this->v_len + 1);
if (!conf->arr) {
fprintf(stderr, "malloc() failed\n");
exit(1);
}
char * remnant = (char *) ((char **) conf->arr + conf->arrlen);
memcpy(remnant, this->value, this->v_len + 1);
for (size_t idx = 0; idx < conf->arrlen; idx++) {
conf->arr[idx] = ini_array_release(&remnant, INI_COMMA, this->format);
ini_string_parse(conf->arr[idx], this->format);
}
}
return 0;
#undef conf
}
int main () {
struct my_conf_T my_conf = (struct my_conf_T) { 0 };
if (load_ini_path("test.conf", INI_DEFAULT_FORMAT, NULL, my_listnr, &my_conf)) {
fprintf(stderr, "Sorry, something went wrong :-(\n");
return 1;
}
if (my_conf.arr) {
/* Do something with `my_conf.arr`... */
for (size_t idx = 0; idx < my_conf.arrlen; idx++) {
printf("arr[%zu] = %s\n", idx, my_conf.arr[idx]);
}
free(my_conf.arr);
}
return 0;
}
Output:
arr[0] = val1
arr[1] = val2
arr[2] = ...
arr[3] = valn
P.S. I happen to be the author.

Segmentation fault happened in Linux but works in Mac

I have a c code which wrote in my Mac laptop in Xcode but it didn't work in Linux system.
I run this code by two ways:
1.One is run in Eclipse but the while loop didn't look like finish. Please find the message below:
Please wait while calculating...
But not more message in the console. It looks like while loop can't finish by some reason.
2.The second way is that I complier the code directly in Linux environment by the command:
cc -std=c99 main.c -o main
Then run by the command:
./main
The message shows that:
Please wait while calculating... Segmentation fault (core dumped)
I checked by gdb
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a9bd4a in ?? () from /lib/x86_64-linux-gnu/libc.so.6
My data is saved in:
/home/alan_yu/workspace/scandi.csv
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
char **split(char *line, char sep, int fields) {
char **r = (char **)malloc(fields * sizeof(char*));
int lptr = 0, fptr = 0;
r[fptr++] = line;
while (line[lptr]) {
if (line[lptr] == sep) {
line[lptr] = '\0';
r[fptr] = &(line[lptr+1]);
fptr++;
}
lptr++;
}
return r;
}
int cmpfunc (const void * a, const void * b)
{
return *(double *)a > *(double *)b ? 1 : -1;
}
#define LINE_SIZE 1000000
#define EXPECTED_STOCK_SIZE 10000000
void calculate2(char * fileName) {
printf("Please wait while calculating...\n");
// Open the file for reading.
FILE *file = fopen(fileName, "r");
// maximun size of the line to read.
// memory allocation for the line to read.
char* line = malloc(LINE_SIZE);
// char **stockNameArray = malloc( sizeof(char *) * EXPECTED_STOCK_SIZE);
// int stockNameArrayPos = 0;
double *bidArray = malloc( sizeof(double) * EXPECTED_STOCK_SIZE );
int bidArrayPos = 0;
double *askArray = malloc( sizeof(double) * EXPECTED_STOCK_SIZE);
int askArrayPos = 0;
double *spreadArray = malloc( sizeof(double) * EXPECTED_STOCK_SIZE);
int spreadArrayPos = 0;
double sum=0;
int i=0,j=0;
while (fgets(line, LINE_SIZE, file)!= NULL){
// printf("Please wait while ...%d\n ", j);
j++;
char **fields = split(line, ',', 15);
const char * volvbEquity = "VOLVB SS Equity";
int comp = strcmp(fields[0], volvbEquity);
if (comp == 0) {
double bidValue = atof(fields[2]);
double askValue = atof(fields[3]);
bidArray[bidArrayPos++] = bidValue;
askArray[askArrayPos++] = askValue;
if (askValue - bidValue > 0) {
double spreadValue = ((askValue - bidValue) / (askValue + bidValue) * 20000);
spreadArray[spreadArrayPos++] = spreadValue;
sum = sum + spreadValue;
}
}
}
//quick sort the spread
qsort(spreadArray, spreadArrayPos, sizeof(double), cmpfunc);
int mediumPos;
double mean;
double medium;
if(spreadArrayPos % 2 == 0) {
mediumPos = spreadArrayPos / 2;
medium = (spreadArray[mediumPos] + spreadArray[mediumPos+1]) / 2;
} else {
mediumPos = (spreadArrayPos)/2 + 1;
medium = spreadArray[mediumPos];
}
mean = sum / spreadArrayPos;
printf("Please find mean and medium %f %f\n", mean, medium);
free(bidArray);
free(askArray);
free(spreadArray);
}
int main(int argc, char **argv) {
calculate2("/home/alan_yu/workspace/scandi.csv");
return(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void split(char *line, char sep, char **fields) {
int lptr = 0, fptr = 0;
fields[fptr++] = line;
while (line[lptr]) {
if (line[lptr] == sep) {
line[lptr] = '\0';
fields[fptr] = &(line[lptr+1]);
fptr++;
}
lptr++;
}
}
int cmpfunc (const void * a, const void * b) {
return *(double *)a > *(double *)b ? 1 : -1;
}
#define LINE_SIZE 1000000
#define EXPECTED_STOCK_SIZE 10000000
#define COLUMN_NUM 15
void calculate2(char * fileName) {
printf("Please wait while calculating...\n");
// Open the file for reading.
FILE *file = fopen(fileName, "r");
// maximun size of the line to read.
// memory allocation for the line to read.
char* line = malloc(LINE_SIZE);
// char **stockNameArray = malloc( sizeof(char *) * EXPECTED_STOCK_SIZE);
// int stockNameArrayPos = 0;
double *bidArray = malloc( sizeof(double) * EXPECTED_STOCK_SIZE );
int bidArrayPos = 0;
double *askArray = malloc( sizeof(double) * EXPECTED_STOCK_SIZE);
int askArrayPos = 0;
double *spreadArray = malloc( sizeof(double) * EXPECTED_STOCK_SIZE);
int spreadArrayPos = 0;
double sum=0;
int i=0,j=0;
while (fgets(line, LINE_SIZE, file)!= NULL){
// printf("Please wait while ...%d\n ", j);
j++;
char **fields = malloc(sizeof(char *) * COLUMN_NUM);
split(line, ',', fields);
const char * volvbEquity = "VOLVB SS Equity";
int comp = strcmp(fields[0], volvbEquity);
if (comp == 0) {
double bidValue = atof(fields[2]);
double askValue = atof(fields[3]);
bidArray[bidArrayPos++] = bidValue;
askArray[askArrayPos++] = askValue;
if (askValue - bidValue > 0) {
double spreadValue = ((askValue - bidValue) / (askValue + bidValue) * 20000);
spreadArray[spreadArrayPos++] = spreadValue;
sum = sum + spreadValue;
}
}
// free memory for fields.
free(fields);
}
// free memory for the line variable.
free(line);
//quick sort the spread
qsort(spreadArray, spreadArrayPos, sizeof(double), cmpfunc);
int mediumPos;
double mean;
double medium;
if(spreadArrayPos % 2 == 0) {
mediumPos = spreadArrayPos / 2;
medium = (spreadArray[mediumPos] + spreadArray[mediumPos+1]) / 2;
} else {
mediumPos = (spreadArrayPos)/2 + 1;
medium = spreadArray[mediumPos];
}
mean = sum / spreadArrayPos;
printf("Please find mean and medium %f %f\n", mean, medium);
free(bidArray);
free(askArray);
free(spreadArray);
}
int main(int argc, char **argv) {
calculate2("/home/alan_yu/workspace/scandi.csv");
return(0);
}
On Linux, always run the program in valgrind if it is crashing.
It will not only tell you exactly what is wrong in your code, but also specify what code lines are responsible for the error.
You need to check the return value of fopen! I would suggest doing the same thing for malloc, but it's much less likely that malloc is failing due to a missing file or typographical error particularly if you're allocating large chunks! You wouldn't want to dereference a null pointer, right?
I'm assuming each line has at least four comma-separated fields, because you're using fields[3]. You should probably work out how to guard against using uninitialised values here. I'd start by re-engineering split so that you have some terminal NULL value or something in its output (and while we're on that topic, don't forget to free the return value).
Is it possible that you might be dividing by zero? That'd be something else you need to guard against.
Shouldn't cmpfunc return 0 when items are equal? I've seen implementations crash when return values for comparison functions for qsort and bsearch are inconsistent.
You claimed below in a comment that your lines have fifteen commas. This implies that you have sixteen fields (count them below), since the number of fields is n+1 where n is the number of separators.
field1, field2, field3, field4,
field4, field6, field7, field8,
field9, field10,field11,field12,
field13,field14,field15,field16
There are fifteen commas and sixteen fields in this table. You're only allocating enough for fifteen fields, however. This is a buffer overflow, more typical undefined behaviour.
Finally, I find out the problem comes from the
while (fgets(line, LINE_SIZE, file)!= NULL){
char **fields = split(line, ',', 15);
I have changed it to
char **fields = malloc(sizeof(char *) * 15 * 10000);
while (fgets(line, LINE_SIZE, file)!= NULL){
I haven't try to allocate a large memory to **fields after the while loop due to it takes too much memory to my machine.
It looks like under gcc compile that if I do:
while (fgets(line, LINE_SIZE, file)!= NULL){
char **fields = split(line, ',', 15);
It won't overwrite the **fields from last time. But it works in Mac
Not sure is that correct?
In the end, thanks for all of you guys help for my problem.

How to create an array consisting of the tokens created using the strtok function?

I am new with .ini files and thus this qn(which might seem silly) .I have created a .ini file and access it via my C program. The ini file looks like this:
[key]
title = A,H,D
The C program accesses it using:
LPCSTR ini ="C:\\conf.ini;
char var[100];
GetPrivateProfileString("key", "title", 0, var, 100, ini);
printf("%s", var);
char* buffer = strtok(var, ", ");
do{
printf("%s", buffer);
if (strcmp(buffer, "A")==0)
printf("Hello");
puts("");
}while ((buffer=strtok(NULL, ", "))!= NULL);
output looks as :
A H D F G IAHello
H
D
F
G
Now what I need to do is use these individual tokens again to form an array with indices within my C program. For example:
char x[A, H, D, F, G]
so that when I refer to the index 2, x[2] should give me 'D'. Could somebody suggest a way to do this. I have never used strtok before and thus very confused. Thank you in advance.
This question is quite similar to others regarding getting external information and storing it in an array.
The problem here is the amount of elements in your array to store.
You could use Link-lists, but for this example, I would scan the file, getting the total amount of items needed for the array - and then parse the file data again - storing the items in the array.
The first loop, goes through and counts the items to be store, as per your example posted. I will do the second loop just as an example - please note in my example you would of created nTotalItems and have counted the amount of items, storing that in nTotalItems ... I am assuming you want to store a string, not just a char...
Also please note this a draft example, done at work - only to show a method of storing the tokens into an array, therefore there is no error checking ec
// nTotalItems has already been calculated via the first loop...
char** strArray = malloc( nTotalItems * sizeof( char* ));
int nIndex = 0;
// re-setup buffer
buffer = strtok(var, ", ");
do {
// allocate the buffer for string and copy...
strArray[ nIndex ] = malloc( strlen( buffer ) + 1 );
strcpy( strArray[ nIndex ], buffer );
printf( "Array %d = '%s'\n", nIndex, strArray[ nIndex ] );
nIndex++;
} while ((buffer=strtok(NULL, ", "))!= NULL);
Just use an INI parser that supports arrays.
INI file:
[my_section]
title = A,H,D
C program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <confini.h>
#define MY_ARRAY_DELIMITER ','
struct configuration {
char ** title;
size_t title_length;
};
static char ** make_strarray (size_t * arrlen, const char * src, const size_t buffsize, IniFormat ini_format) {
*arrlen = ini_array_get_length(src, MY_ARRAY_DELIMITER, ini_format);
char ** const dest = *arrlen ? (char **) malloc(*arrlen * sizeof(char *) + buffsize) : NULL;
if (!dest) { return NULL; }
memcpy(dest + *arrlen, src, buffsize);
char * iter = (char *) (dest + *arrlen);
for (size_t idx = 0; idx < *arrlen; idx++) {
dest[idx] = ini_array_release(&iter, MY_ARRAY_DELIMITER, ini_format);
ini_string_parse(dest[idx], ini_format);
}
return dest;
}
static int ini_handler (IniDispatch * this, void * v_conf) {
struct configuration * conf = (struct configuration *) v_conf;
if (this->type == INI_KEY && ini_string_match_si("my_section", this->append_to, this->format)) {
if (ini_string_match_si("title", this->data, this->format)) {
/* Save memory (not strictly needed) */
this->v_len = ini_array_collapse(this->value, MY_ARRAY_DELIMITER, this->format);
/* Allocate a new array of strings */
if (conf->title) { free(conf->title); }
conf->title = make_strarray(&conf->title_length, this->value, this->v_len + 1, this->format);
if (!conf->title) { return 1; }
}
}
return 0;
}
static int conf_init (IniStatistics * statistics, void * v_conf) {
*((struct configuration *) v_conf) = (struct configuration) { NULL, 0 };
return 0;
}
int main () {
struct configuration my_conf;
/* Parse the INI file */
if (load_ini_path("C:\\conf.ini", INI_DEFAULT_FORMAT, conf_init, ini_handler, &my_conf)) {
fprintf(stderr, "Sorry, something went wrong :-(\n");
return 1;
}
/* Print the parsed data */
for (size_t idx = 0; idx < my_conf.title_length; idx++) {
printf("my_conf.title[%d] = %s\n", idx, my_conf.title[idx]);
}
/* Free the parsed data */
if (my_conf.title_length) {
free(my_conf.title);
}
return 0;
}
Output:
my_conf.title[0] = A
my_conf.title[1] = H
my_conf.title[2] = D

Loss of values in array in struct after function execution

I am working on a c code that holds a structure that hosts some values which I call range.
My purpose is to use this so called range dynamically (holding different amount of data at every execution). I am now provisionally using the # define comp instead. This so called range gets updated every time I call my update_range though the use of s1 structure (and memory allocations).
What I found weird is that when I introduced a "show_range" function to output the actual values inside/outside the update function I realized that I loose the first two values.
Here is the code.
Any suggestions on that?
Thanks in advance!
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <complex.h>
#define comp 1024
// struct holding a complex-valued range
struct range {
int dimensions; /* number of dimensions */
int* size; /* array holding number of points per dimension */
complex double* values; /* array holding complex valued */
int components; /* number of components that will change on any execution*/
};
// parameters to use in function
struct s1 {
int tag;
struct range* range;
};
int update_range(struct s1* arg);
int show_range(struct range* argrange, char* message);
int copy_range(struct range* in, struct range* out);
int main(void) {
int ret = 0;
struct s1 s1;
s1.tag = 0;
s1.range = malloc(sizeof(struct range));
update_range(&s1);
show_range(s1.range, "s1.range inside main function");
return ret;
}
////////////////////////////////////////////
int update_range(struct s1* arg) {
int ret = 0;
int i;
struct range range;
range.dimensions = 1;
range.size = malloc(range.dimensions * sizeof(int));
range.components = comp;
range.size[0] = range.components; // unidimensional case
range.values = malloc(range.components * sizeof(complex double));
for (i = 0; i < range.components; i++) {
range.values[i] = (i + 1) + I * (i + 1);
}
show_range(&range, "range inside update_range function");
arg->range->size =
malloc(range.dimensions * sizeof(int)); // size was unknown before
arg->range->values =
malloc(comp * sizeof(complex double)); // amount of values was unknown
copy_range(&range, arg->range);
show_range(arg->range, "arg->range inside update_range function");
if (range.size)
free(range.size);
range.size = NULL;
if (range.values)
free(range.values);
range.values = NULL;
return ret;
}
////////////////////////////////////////////
// Show parameters (10 first values)
int show_range(struct range* argrange, char* message) {
int ret = 0;
vint i;
printf(" ******************************\n");
printf(" range in %s \n", message);
printf(" arg.dimensions=%d \n", argrange->dimensions);
printf(" arg.size[0]=%d \n", argrange->size[0]);
printf(" argrange.components=%d \n", argrange->components);
printf(" first 10 {Re} values: \n");
for (i = 0; i < 10; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
printf("\n");
return ret;
}
////////////////////////////////////////////
// copy range
int copy_range(struct range* in, struct range* out) {
int ret = 0;
if (in == NULL) {
fprintf(stderr, "error: in points to NULL (%s:%d)\n", __FILE__,
__LINE__);
ret = -1;
goto cleanup;
}
if (out == NULL) {
fprintf(stderr, "error: out points to NULL (%s:%d)\n", __FILE__,
__LINE__);
ret = -1;
goto cleanup;
}
out->dimensions = in->dimensions;
out->size = in->size;
out->values = in->values;
out->components = in->components;
cleanup:
return ret;
}
Your copy_range function is broken, because it copy only pointer to size and values and not the memory. After you call free(range.size); and free(range.values); you are deleting mamory also from original object but without setting its pointers back to NULL.
After calling update_range, s1.range has non NULL pointers in size and values, but they are pointing to deleted memory.
You are experiencing undefined behaviour (UB) due to accessing freed memory. Your copy_range() function only does a shallow copy of the two pointer fields so when you run free(range->size) you make arg->range->size invalid.
You should make copy_range() a deep copy by allocating and copying the pointer contents like:
out->size = malloc(in->dimensions * sizeof(int));
memcpy(out->size, in->size, in->dimensions * sizeof(int));
out->values = malloc(in->components * sizeof(complex double));
memcpy(out->values , in->values, in->components * sizeof(complex double));
There are not 10 items to print, so the lines:
printf(" first 10 {Re} values: \n");
for (i = 0; i < 10; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
Will be printing from random memory.
a much better method would be:
printf(" first %d {Re} values: \n", min(argrange.components,10));
for (i = 0; i < argrange.components; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
The above is just one of many problems with the code.
I would suggest executing the code using a debugger to get the full story.
as it is, the code has some massive memory leaks due mostly
to overlaying malloc'd memory pointers.
for instance as in the following:
arg->range->size =
malloc(range.dimensions * sizeof(int)); // size was unknown before
arg->range->values =
malloc(comp * sizeof(complex double)); // amount of values was unknown

How to pass a pointer to array of structures into a function

pointers always get me in C programing.
I am having trouble, I want to pass a pointer to an array of structs into a function so it can modify the structs and then pass the members of the array can be used in other functions later. The problem is when I think I index the array and point it to the modified struct then I try to look at the members later they aren't the modified values. Here is some of my code
typedef struct
{
int rows;
int columns;
int *data;
} Mat;
int main(void)
{
Mat result, decoded_result;
int result_data[8] =
{ 0, 0, 0, 0, 0, 0, 0, 0 };
int decoded_data[4] =
{ 0, 0, 0, 0 };
result.columns = 1;
result.rows = 8;
result.data = &result_data[0];
decoded_result.columns = 1;
decoded_result.rows = 4;
decoded_result.data = &decoded_data[0];
Mat m1, m2, m3, m4, m5;
m1.rows = m2.rows = m3.rows = m4.rows = m5.rows = 4;
m1.columns = m2.columns = m3.columns = m4.columns = m5.columns = 1;
int md1[4], md2[4], md3[4], md4[4], md5[4];
m1.data = &md1[0], m2.data = &md2[0], m3.data = &md3[0], m4.data = &md4[0], m5.data =
&md5[0];
Mat mat_array[10] =
{ m1, m2, m3, m4, m5 };
decode_data(&result, &decoded_result, mat_array);
return 0;
}
int decode_data(Mat *result, Mat *decoded_result, Mat *mat_array)
{
int ii;
int size_of_EEPROM = 5;
//steps to decode data
for (ii = 0; ii < size_of_EEPROM; ii++)
{
decode(result, decoded_result); //decodes hamming 8,4, works
mat_array[ii] = *decoded_result; ///This is where the problem is
}
return 0;
}
Thanks in advance for the help with pointers :)
As Mat carries a pointer, simply assigning Mat a to Mat b won't work. At least not for the data referenced by Mat's member data.
What's needed to be done here is also called a Deep Copy. Deep coping would also create a copy of what is referenced by data.
Below is an example of how this could be done for Mat.
Note: As negative rows and columns are of no use you'd better declare Mat like this:
typedef struct
{
size_t rows;
size_t columns;
int * data;
} Mat;
(As size_t is defined to be unsigned this kind of declaration makes it unnecessary to test for negative values carried by the members rows and columns before allocating the new data when deep-coping as shown below)
#include <stdlib.h> /* for malloc(), size_t */
#include <string.h> /* for memcpy() */
#include <errno.h> /* for errno, ENOMEM, EINVAL */
...
/* Deep-copies src to dst. */
/* Returns 0 on success or -1 on error. Sets errno in the latter case. */
int mat_copy(Mat * dst, const Mat * src)
{
if ((!dst) || (!src))
{
errno = EINVAL;
return -1;
}
dst->rows = src->row;
dst->columns = src->columns
dst->data = NULL;
if (src->data)
{
size_t size = dst->rows * dst->columns * sizeof (*(dst->data));
dst->data = malloc(size);
if (!dst->data)
{
errno = ENOMEM;
return -1;
}
memcpy(dst->data, src->data, size);
}
return 0;
}
There is rule of three in C++ when using pointers. It says that if you need one of following then you need other two always. These three are Destructor/Copy Constructor/Assign Operator.
So what happen's in your scenario. When you write mat_array[ii] = *decoded_result it actually makes:
mat_array[ii].rows = decoded_result.rows;
mat_array[ii].columns = decoded_result.columns;
mat_array[ii].data = decoded_result.data // here just assign pointers, not the entire data.
In this case you have to make assignment operator to make actual copy of data.

Resources