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

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.

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.

Growing arrays. Refer to the elements by pointers, not indexes

Since the array address may change when memory is reallocated,
the main part of the program (in the body of the function main ()) should refer to the elements by
indexes, not pointers. Why?
Can you show an example of accessing items with pointers?
(Sorry for my English).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Nameval Nameval;
struct Nameval {
char *name;
int value;
};
struct NVtab {
int nval; /* current number of values */
int max; /* allocated number of values */
Nameval *nameval; /* array of name-value pairs */
};
enum {NVINIT = 1, NVGROW = 2};
/* addname: add new name and value to nvtab */
int addname(struct NVtab *nvtab, Nameval newname) {
Nameval *nvp;
if (nvtab->nameval == NULL) { /* first time */
nvtab->nameval = (Nameval *) malloc(NVINIT * sizeof(Nameval));
if (nvtab->nameval == NULL)
return -1;
nvtab->max = NVINIT;
nvtab->nval = 0;
} else if (nvtab->nval >= nvtab->max) { /* grow */
nvp = (Nameval *) realloc(nvtab->nameval,
(NVGROW*nvtab->max)*sizeof(Nameval));
if (nvp == NULL)
return -1;
nvtab->max *= NVGROW;
nvtab->nameval = nvp;
}
nvtab->nameval[nvtab->nval] = newname;
return nvtab->nval++;
}
int main(void) {
struct NVtab nvtab = {0, 0, NULL};
int curnum;
curnum = addname(&nvtab, (Nameval) {.name="Andy", .value=12});
printf("%d\n", curnum);
curnum = addname(&nvtab, (Nameval) {.name="Billy", .value=18});
printf("%d\n", curnum);
curnum = addname(&nvtab, (Nameval) {.name="Jack", .value=71});
printf("%d\n", curnum);
for (int i = 0; i < nvtab.nval; i++) {
printf("%s %d\n", nvtab.nameval[i].name,
nvtab.nameval[i].value);
}
}
For example, why can`t we show array like this:
for (int i = 0; i < nvtab.nval; i++)
printf("%s %d\n", nvtab.*(nameval+i).name, nvtab.*(nameval+i).value);
You are not supposed to assign a pointer calculated for a specific index to a variable with storage duration which could extend over an insert operation.
That pointer could become invalid, so the lesson behind that example is to always re-evaluate iterators on dynamic data structures.
E.g. what not to do:
auto *foo = &nvtab.nameval[i];
addname(&nvtab, (Nameval) {.name="Billy", .value=18});
printf("%s %d\n", foo->name, foo->value);
In the last line it can work or crash. Depending on whether realloc moved the allocation or resized in-place. Except that you can never know for sure until you execute it, as it isn't even fully deterministic.
This is not valid syntax:
nvtab. *(nameval+i).name
The member access operator . expects to be followed by the name of the member. What you want is:
(*(nvtab.nameval+i)).name

How could I know an Uncertain type parameters' size

const static int VECTOR_BASIC_LENGTH = 20;
struct m_vector
{
void* my_vector;
size_t my_capacity;
size_t my_head;
};
typedef struct m_vector Vector;
Vector creat_Vector(size_t size,void *judge)
{
Vector _vector;
size = size?size:VECTOR_BASIC_LENGTH;
_vector.my_capacity = size;
_vector.my_head = 0;
//How I write the following two lines
_vector.my_vector = malloc(sizeof(*judge) * size);
return _vector;
}
The type of judge is uncertain,so I pass a void pointer as a parameters.I need the size of *judge to allocate memory to _vector.my_vector,for example if I use:
int *a;
creat_Vector(5,a);
I want the following line:
_vector.my_vector = malloc(sizeof(*judge)*size);
is equal to:
_vector.my_vector = malloc(sizeof(*a)*5);
How could I achieve this function.Using pure C
There is a forbidden thing done in your code.
You statically (at compile time) allocate/declare a local _vector of type Vector in your function creat_Vector. Then you return this object to the outside world. However, when you are exiting your function, all local data is dead. So, you should absolutely rethink this.
One suggestion would be:
int init_Vector(Vector* _vect, size_t size, unsigned int ptr_size)
{
size = size?size:VECTOR_BASIC_LENGTH;
_vect->my_capacity = size;
_vect->my_head = 0;
_vect->my_vector = malloc(size*ptr_size);
if (_vect->my_vector) {
return 0;
}
return 1;
}
Then:
Vector _vector;
char *a;
if (init_Vector(&_vector, 5, sizeof(char)) == 0) {
printf("Success!\n");
}
else {
printf("Failure!\n");
/* treat appropriately (return error code/exit) */
}
/* do whatever with a (if needed) and _vector*/

EXCEPTION_ACCESS_VIOLATION when using large array in 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.

qsort for structure array

I try to sort a struct below, given an intention to sort their error rate, while retaining the information of sid and did. While there is no compilation error, I get a seg fault in runtime. I wonder what has gone wrong....
#include <stdio.h>
#include <stdlib.h>
struct linkdata {
int sid;
int did;
double err;
};
typedef struct linkdata LD;
typedef int (*qsort_func_t)(const void *, const void *);
static int compareByErr (const void * a, const void * b)
{
fprintf(stderr, "aerr=%.3f, berr=%.3f\n", (*(LD**)a)->err, (*(LD**)b)->err);
int aerr = (*(LD**)a)->err;
int berr = (*(LD**)b)->err;
return aerr - berr;
}
int main() {
int idx;
int numnode;
struct linkdata* perr;
qsort_func_t qsort_func = compareByErr;
numnode = 3;
perr = (LD*) malloc (numnode*numnode*sizeof(LD));
perr[0].sid = 0; perr[0].did = 1; perr[0].err = 0.642;
perr[1].sid = 0; perr[1].did = 2; perr[1].err = 0.236;
perr[2].sid = 0; perr[2].did = 3; perr[2].err = 0.946;
idx = 3;
qsort(perr, idx, sizeof(perr), compareByErr);
int i;
for (i=0; i<idx; i++){
fprintf(stderr,"err[%d][%d] = %.3f\n", perr[i].sid, perr[i].did, perr[i].err);
}
free(perr);
}
There are many errors in the code.
1. compareByErr
The a and b parameters of the compareByErr function are objects of LD*, not LD**. You did an unnecessary dereferencing. Try to change that function to:
static int compareByErr (const void * a, const void * b)
{
fprintf(stderr, "aerr=%.3f, berr=%.3f\n", ((LD*)a)->err, ((LD*)b)->err);
int aerr = ((LD*)a)->err;
int berr = ((LD*)b)->err;
return aerr - berr;
}
2. compareByErr
There is another problem, that you implicitly convert the double into int. Since all those "errors" are 0.???, they will all be truncated to 0. Making the whole array unsorted. Change it to:
double aerr = ((LD*)a)->err;
double berr = ((LD*)b)->err;
return aerr < berr ? -1 : aerr > berr ? 1 : 0;
3. malloc
You are allocating for 32 nodes, but only 3 are needed. Change that to
perr = (LD*) malloc (numnode * sizeof(LD));
4. qsort
The 3rd argument is the size of each element of the array, not sizeof(perr) which is just the size of a pointer (4 bytes). Change that line to:
qsort(perr, idx, sizeof(*perr), compareByErr);
// ^
to actually get the element size.
The idx seems unnecessary. You could just use numnode here.
Your comparison function expects to be sorting an array of pointers to structs, but you're not doing that. This problem is covered by the other answers.
What they didn't mention is that you're also using the wrong sizeof for the sort. Since the array is an array of structs, you must tell qsort that the size of a member is the size of a struct. Change sizeof perr to sizeof *perr
Also, converting the floats to ints before comparing them results in them all being equal because they're all zero...
You're mis-treating the arguments to your comparator callback.
This:
fprintf(stderr, "aerr=%.3f, berr=%.3f\n", (*(LD**)a)->err, (*(LD**)b)->err);
should be:
{
const LD *lda = a, *ldb = b;
fprintf(stderr, "aerr=%.3f, berr=%.3f\n", lda->err, ldb->err);
/* ... */
}
Of course you don't have to introduce new variables of the proper type, but it makes the subsequent code that much easier. I always do this.
Further, this:
int aerr = (*(LD**)a)->err;
int berr = (*(LD**)b)->err;
return aerr - berr;
is adoringly terse, but it can hide integer overflow issues that are bit scary. I would recommend:
return (a->err < b->err) ? -1 : a->err > b->err;
This uses an explicit literal to generate the -1 value, while relying on comparisons generating 0 or 1 for the two other cases.

Resources