C and dynamic structure element access - c

I have this complicated structure thingie:
#include <stdlib.h>
typedef struct {
int x;
int y;
} SUB;
typedef struct {
int a;
SUB *z;
} STRUCT;
#define NUM 5
int main(void)
{
STRUCT *example;
int i;
example = malloc(sizeof(STRUCT));
example->z = malloc(NUM * sizeof(SUB));
for(i = 0; i < NUM; ++i) {
/* how do I access variable in certain struct of array of z's */
}
return 0;
}
example is dynamically allocated structure and z inside the example is dynamically allocated array of SUB structures.
How do I access certain variable in certain element of structure z?
I have been trying something like this: example->z[i].x but it doesnt seem to work.
At the moment I am using this shabby looking workaraound:
SUB *ptr = example->z;
int i;
for(i = 0; i < amount_of_z_structs; ++i) {
/* do something with 'ptr->x' and 'ptr->y' */
ptr += sizeof(SUB);
}

Your problem isn't where you say it is. Your code as posted gives a compile error:
error: request for member ā€˜zā€™ in something not a structure or union
at the line
example.z = malloc(sizeof(STRUCT));
because you meant to write example->z, since example is a pointer to STRUCT, not a STRUCT.
From there on, you can access example->z[i].x exactly as you said. That syntax has always been fine.
For example:
/* your declarations here */
example = malloc(sizeof(STRUCT));
example->z = malloc(NUM * sizeof(SUB));
for(i = 0; i < NUM; ++i) {
example->z[i].x = i;
example->z[i].y = -i;
printf("%d %d\n", example->z[i].x, example->z[i].y);
}
/* output:
0 0
1 -1
2 -2
3 -3
4 -4
*/

When you have pointers pointing to pointers you often end up running into precedence issues. I can't recall if this is one, but you might try (example->b)[i].x.

First of all, your second malloc is wrong; example is a pointer so this:
example.z = malloc(NUM * sizeof(SUB));
should be this:
example->z = malloc(NUM * sizeof(SUB));
Then in your loop you can say things like this:
example->z[i].x = i;
example->z[i].y = i;
You'll also want to have this near the top of your file:
#include <stdlib.h>

Try this:
int my_x = example[3].z[2].x;
The above code will first access the example[3] (the fourth element of the example array).
Once you get that particular element, its contents can be automatically access in the same way as you do with normal objects.
You then access z[2] from that element. Note that, example[3] is an element, so you could use a . to access its members; if its an array, you can access it as an array.
So till now, example[3].z[2] is one element of the SUB array inside one element of the example array.
Now you can simply access the member x using the way shown above.
typedef struct {
int x;
int y;
} SUB;
typedef struct {
int a;
SUB *z;
} STRUCT;
STRUCT *example;
int main() {
example = malloc(sizeof(STRUCT)*10); //array of 10;
int i=0,j=0;
for (;i<10;i++){
example[i].a = i;
example[i].z = malloc(sizeof(SUB)*5);
for (j=0; j<5; j++)
example[i].z[j].x = example[i].z[j].y = j;
}
//access example[3] and access z[2] inside it. And finally access 'x'
int my_x = example[3].z[2].x;
printf("%d",my_x);
for (i=0;i<10;i++){
printf("%d |\n",example[i].a);
//example[i].z = malloc(sizeof(SUB)*5);
for (j=0; j<5; j++)
printf("%d %d\n",example[i].z[j].x,example[i].z[j].y);
free(example[i].z);
}
free(example);
}

In the 'shabby workaround', you wrote:
SUB *ptr = example->z;
int i;
for(i = 0; i < amount_of_z_structs; ++i) {
/* do something with 'ptr->x' and 'ptr->y' */
ptr += sizeof(SUB);
}
The problem here is that C scales pointers by the size of the object pointed to, so when you add 1 to a SUB pointer, the value is advanced by sizeof(SUB). So, you simply need:
SUB *ptr = example->z;
int i;
for (i = 0; i < NUM; ++i) {
ptr->x = ptr->y = 0;
ptr++;
}
Of course, as others have said, you can also do (assuming C99):
for (int i = 0; i < NUM; ++i)
example->z[i].x = example->z[i].y = 0;

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#define NUM 5
typedef struct
{
int x;
int y;
}SUB;
typedef struct
{
int a;
SUB* z;
}STRUCT;
void main(void)
{
clrscr();
printf("Sample problem..\n\n");
STRUCT* example;
int i;
example = (STRUCT*)malloc(sizeof(STRUCT));
example->z = (SUB*)malloc(NUM * sizeof(SUB));
for(i = 0; i < NUM; i++)
{
example->z[i].x = i +1;
example->z[i].y = (example->z[i].x)+1;
printf("i = %d: x:%d y:%d\n", i, example->z[i].x, example->z[i].y);
}
}

Related

Attempt to access elements of a 2d struct array failing

typedef struct{
unsigned long a;
unsigned long b;
unsigned long c;
} mini_struct;
struct ministruct** build_2Dstruct(unsigned long x, unsigned long y){
double x_squared = pow(2, x);
struct ministruct** temp = (mini_struct**)malloc(x*sizeof(mini_struct*));
for(int i = 0; i < x_squared; i++){
temp[i] = (mini_struct*)malloc(y*sizeof(mini_struct));
for(int j = 0; j < y; j++){
temp[i][j].a = 0;
etc....
}
}
return temp;
}
In the code above I am trying to create a 2D array of ministructs**, with the whole struct being made out of 2^x ministructs*, and each ministruct* has y amount of ministructs.
aka:
x = 2,
y = 2,
[[struct, struct], [struct, struct], [struct, struct], [struct, struct]]
However, for some reason when I try to access the second element or index 1 of the struct inside each struct*, it says there is an error: "expression must be pointer to complete object".
I just do not understand why the code is not allowing me to access each individual element of the elements of the array?
Thanks
You are trying to make an x by y array of structs. So:
// create array of x pointers
mini_struct **temp = malloc(x*sizeof(mini_struct*));
for (int i=0; i<x; i++) {
// to array of y structs
temp[i] = malloc(y*sizeof(mini_struct));
for (int j=0; j < y; j++) {
temp[i][j].a = 0;
... etc.
Question is incomplete so I will be making asumptions.
You seem to be wanting to allocate a 2D array of structs and initialize all members to 0. Here is a possible solution:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
typedef struct mini_struct{
unsigned long a;
unsigned long b;
unsigned long c;
} mini_struct;
struct mini_struct** build_2Dstruct(unsigned long x, unsigned long y){
double x_squared = pow(x, 2);
mini_struct **temp = (mini_struct **) malloc(x_squared * sizeof(mini_struct*));
for(int i = 0; i < x_squared; i++){
temp[i] = (mini_struct *) calloc(y, sizeof(mini_struct));
}
return temp;
}
int main () {
int x = 3;
int y = 4;
mini_struct **struct2D = build_2Dstruct(x, y);
int x_squared = pow(x,2);
for (int i = 0; i < x_squared; ++i) {
for (int j = 0; j < y; ++j) {
printf("Value of data stored at struct[%d][%d] is: %d\n", i, j, struct2D[i][j]);
}
}
for (int i = 0; i < x_squared; ++i) {
free(struct2D[i]);
}
free(struct2D);
}
As you can see, this contains the whole program, not just the snippet you showed. In this case, a main function would have been useful so that we don't have to guess what you want to do. My solution creates the 2D array with all elements initialized to 0 (you can use calloc to do that, no need for a second for loop).
Another important point is that, because the function returns a newly heap allocated 2D array, you need to free it to avoid a memory leak (end of main function).
You allocate x pointers to mini_struct:
mini_struct **temp = (mini_struct **) malloc(x_squared * sizeof(mini_struct*));
But then when you initialize them:
for(int i = 0; i < x_squared; i++){
temp[i] = (mini_struct *) calloc(y, sizeof(mini_struct));
}
You index temp based on upto x_squared.
Consider if x is 2. You would allocate temp to be an array of two pointers to mini_struct. But then your for loop would attempt to initialize four elements in temp.

Pass static two dimensional struct array to function by reference

I try to pass a static two dimensional struct as a reference to a function.
But I don't know how to get that done in correct way.
From my understanding, I pass a pointer to the first element of struct test to initfield(). C does know the size of the struct test so I can jump to the specific requested locations of the data. I just don't know how to adress the required data.
Here's my code that hopefully describes what I am looking for.
struct test{
int i;
double d;
};
void initfield(struct test *a, int structsize)
{
int i, j;
for (i = 0; i < structsize; i++)
{
for (j = 0; j < structsize; j++)
{
a[i][j]->i = 1;
a[i][j]->d = 1.0;
}
}
}
int main(void)
{
int i, j;
struct test field[8][8];
initfield(field, 8);
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
printf("test[%i][%i].i = %i", i, j, test.i);
printf("test[%i][%i].d = %i", i, j, test.d);
}
}
return 0;
}
Update :
I've replaced both printf's with the following :
printf("test[%i][%i].i = %i", i, j, field[i][j].i);
printf("test[%i][%i].d = %lf", i, j, field[i][j].d);
However, I still encounter errors with initfield.
The problem, is actually, in your initfield() code,
void initfield(struct test *a, int structsize)
a is of type struct test *, and later, you're doing
a[i][j]->i = 1;
which expects a to be struct test **
That said,
for (j = 0; j < 8; j++)
{
printf("test[%i][%i].i = %i", i, j, test.i);
printf("test[%i][%i].d = %i", i, j, test.d);
}
is completely wrong. Neither is there any variable called test, nor you can access a 2-D array using structVar.membervar format. Moreover, you are using %d to print a double, which in turn invokes undefined behaviour.
Solution: You can make use of array properties and pointer arithmetic to achieve what you want.
You have to change the loop inside the initfield() code, like
for (i = 0; i < structsize; i++)
{
for (j = 0; j < structsize; j++)
{
((a+(i*structsize))+j)->i = 7; //I changed the value to store, just like that
((a+(i*structsize))+j)->d = 2.0; //I changed the value to store, just like that
}
}
and, in main(), use %f to print the values.
A Live variant
First, structsize is not a good identifier name. It's not the size of the struct, it's the size of one dimension of the array. I'd implement it with parameters x and y, or width and heigth, or any better names for the two dimensions.
field is also a bad name. A field is often used to call a member of a struct. It is very confusing to use the identifier field to call an array of array of structs.
Then to your problem: field is an array of array of structs. In function parameter, this is equivalent to a pointer to a pointer.
The first parameter of initfield should be of type struct test **. Then later in the function, you dereference twice with your [] operators:
a is of type struct test **
a[i] is of type struct test *
a[i][j] is of type struct test
To access the fields of a[i][j], you need the . operator since its a struct test: a[i][j].d. The operator -> would work if a[i][j] was of type struct test *, but it isn't.
In this case it doesn't matter: as other have said, you can't access the second dimension of the array without explicitly calculating with the help of the size of the first dimension. a[i][j] does not work, you need some kind of pointer arithmetic: struct test *p = a + i * structsize + j and use p->i and p->d.
In the main function however, the dimensions of field are know, so field[i][j].d works.
You're assuming C can figure out that a inside refers to a square array with side length structsize, although you clearly say that a has type "pointer to struct test", which is not the same.
You need to do the indexing manually, inside the function:
static void initfield(struct test *a00, size_t sidelength)
{
for(size_t i = 0; i < sidelength; ++i)
{
for(size_t j = 0; j < sidelength; ++j)
{
struct test *aij = a00 + i * sidelength + j;
aij->i = 1;
aij->j = 1.0;
}
}
}
I didn't test the above, but something like that should work. It basically just uses simple pointer arithmetic to compute the address of the 2D array element at (i, j) given the address of the one at (0, 0).
It works fine i din't thought about doing calculation the adresses myself.
Thanks very much!
Here's my final adapted code which just works perfectly!
struct test{
int i;
double d;
};
void initfield(struct test *a00, int structsize)
{
int i, j;
for (i = 0; i < structsize; i++)
{
for (j = 0; j < structsize; j++)
{
struct test *acurrent = a00 + i * structsize + j;
acurrent->i = 1;
acurrent->d = 1.0;
}
}
}
int main(void)
{
int i, j;
struct test field[8][8];
initfield(&field[0][0], 8);
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
printf("test[%i][%i].i = %i\n", i, j, field[i][j].i);
printf("test[%i][%i].d = %lf\n", i, j, field[i][j].d);
}
}
return 0;
}
Best way to do this:
void initfield(size_t x, size_t y, struct test a[x][y]);
Be aware though, C is strange, the above is still a pointer, equivalent to struct test*. If you wish to have a true array pointer type, you'd have to do:
void initfield(size_t x, size_t y, struct test a[x][y])
{
struct test (*ptr)[x][y] = (void*)a;
or preferably:
struct test (*ptr)[y] = *a;
ptr[i][j] = something; // use the array pointer with sane syntax

Passing an element of a generic array to a generic function

We have an array with pointers to generic arrays, and an array of generic functions, we want to apply to each element in array i the function i from func_ptarrs.
typedef struct genarr{
void * arr;
int elemsize;
int numelem;
}GENARR;
typedef void(*funcptr)(void*);
typedef unsigned char byte;
void updateall(GENARR *arrs, funcptr *func_ptarrs, int n){
int j,i;
for (i = 0; i < n; i++){
for (j = 0; j < arrs[i].numelem; j++){
func_ptarrs[i]((arrs[i].((byte*)(arr + j*arrs[i].elemsize)))); //error: expected member name
//func_ptarrs[i]((arrs[i].arr)); //no error
}
}
}
In the second try it's pointer to the beginning of the array so it's accepted, but I need to be able to send each element of the array to the generic function.
I don't understand how to send the right amount of bytes and move correctly in array all while sending pointers of the elements to the generic functions.
Maybe I should use memcpy?
You need this instead,
func_ptarrs[i](((byte*) arrs[i].arr + j * arrs[i].elemsize))
and I think it's pretty obvious why it would work.
You could write accessor macros too, like
#define ARRAY_VALUE(type, x, i (*(type *) ((x).arr + (i) * (x).elemsize))
which you can then use like
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_VALUE(type, x, i) (*(type *) ((x).arr + (i) * (x).elemsize))
typedef struct genarr
{
void * arr;
int elemsize;
int numelem;
} GENARR;
int main (void)
{
GENARR array;
int data[10];
array.arr = data;
array.elemsize = sizeof(*data);
array.numelem = sizeof(data) / array.elemsize;
for (int i = 0 ; i < array.numelem ; ++i)
ARRAY_VALUE(int, array, i) = i;
for (int i = 0 ; i < array.numelem ; ++i)
printf("%d\n", ARRAY_VALUE(int, array, i));
return 0;
}

Pointers to structures and functions

I have a simple structure called entry defined which contains name and age. Given an array of these structures, I want to sort the array based on age.
Below is my attempt at applying this, at the moment I can't even get this to compile. I think my pointer logic is incorrect in both the if statement comparison and the subsequent swapping of the pointers. I've tried various ways to do the same thing, but I'm not getting anywhere. I'm pretty new to C, and I'm still trying to get my head around pointers, so it's probably something basic I'm misunderstanding. Can anybody please explain what I'm doing wrong below?
Any help would be greatly appreciated.
#include <stdio.h>
struct entry {
char name[15];
int age;
};
void entrySort( struct entry *dict);
void entrySort( struct entry *dict){
int i,j; // counters
int ct = 4;
struct entry *tmp; // temporary holder
for( i = 0; i < ct; i++){
for( j = 0; j < ct; j++ ){
if ((*dict[i].age) > (*dict[j].age)){
tmp = (dict + i);
(dict+i) = (dict+j);
(dict+j) = tmp;
}
}
}
int main (void){
int ct = 4, i;
struct entry reg[4] =
{{ "John", 24 },
{ "Alan", 18 },
{ "Jim", 40 },
{ "Sarah",32 }};
entrySort(reg);
for( i = 0; i < ct; i++)
printf("name: %s. Age: %d\n", reg[i].name, reg[i].age);
return 0;
}
You pass an array of struct entry objects as a pointer: struct entry *dict, but you are treating it as it would be an array of pointers to struct entry objects: (*dict[i]).age.
(dict+i) is still just a pointer pointing to the memory where i+1. element is stored, i.e. &dict[i]. To actually access this element at index i, you need to use dereference operator: *(dict + i), which is equal to dict[i].
And also note that your swapping of elements at i and j is wrong. "Temporary holder" tmp should be an object that will temporarily hold data, not just a pointer to memory, that you are going to rewrite, thus declare it as struct entry tmp;:
struct entry tmp;
for( i = 0; i < ct; i++) {
for( j = 0; j < ct; j++ ) {
if ((dict[i].age) > (dict[j].age)) {
tmp = dict[i];
dict[i] = dict[j];
dict[j] = tmp;
}
}
}
By the way in the code you have posted, the ending curly brace (}) of your if is missing.
Try:
#include <stdio.h>
struct entry {
char name[15];
int age;
};
void entrySort( struct entry *dict, int);
void entrySort( struct entry *dict, int ct){
int i,j; // counters
/* int ct = 4; */
struct entry tmp; // temporary holder
for( i = 0; i < ct; i++){
for( j = 0; j < ct; j++ ){
if ((dict[i].age) > (dict[j].age)){ /* no * */
tmp = *(dict + i);
*(dict+i) = *(dict+j);
*(dict+j) = tmp;
}
}
}
int main (void){
int ct = 4, i;
struct entry reg[4] =
{{ "John", 24 },
{ "Alan", 18 },
{ "Jim", 40 },
{ "Sarah",32 }};
entrySort(reg, ct);
for( i = 0; i < ct; i++)
printf("name: %s. Age: %d\n", reg[i].name, reg[i].age);
return 0;
}
For completeness, here's how you'd do it with qsort:
#include <stdlib.h>
int sort_entry(const void *va, const void *vb) {
const struct entry *a = va;
const struct entry *b = vb;
if(a->age < b->age) return -1;
else if(a->age == b->age) return 0;
return 1;
}
...
qsort(reg, ct, sizeof(struct entry), sort_entry);

Dynamic array in struct calloc or pointers failing, C

I'm attempting to complete an assignment on sparse matrices in C. I have a sparse matrix held as a list of values and coordinates and am converting it to Yale format.
I have run into a strange memory allocation issue that no one seems to have seen before. My code is:
yale* convertMatrix(matrix_list* input){
int matrix_elements = input->elements;
int matrix_rows = input->m;
yale* yale = (struct y*)calloc(1, sizeof(yale));
int* A = (int*)calloc(matrix_elements, sizeof(int));
int* IA = (int*)calloc(matrix_rows + 1, sizeof(int));
int* JA = (int*)calloc(matrix_elements, sizeof(int));
printf("%d elements\n",matrix_elements);
yale->A = A; // Value
yale->IA = IA; // Row (X)
yale->JA = JA; // Column (Y)
yale->elements = matrix_elements;
yale->m = matrix_rows;
yale->n = input->n;
list* tmp_list = input->first;
for(int i = 0, j = 0, tmp_y = 0; i < matrix_elements && tmp_list!=NULL; i++){
printf("Input Value: %d \n",tmp_list->point.value);
A[i] = tmp_list->point.value;
// Initialise the first row
if(i == 0) IA[0] = tmp_list->point.x;
else{
// Add a new row index
if(tmp_y != tmp_list->point.x){
j++;
IA[j] = i;
tmp_y = tmp_list->point.x;
}
}
JA[i] = tmp_list->point.y;
tmp_list = tmp_list->next;
}
for(int i = 0; i < matrix_elements; i++)
printf("%d,",yale->A[i]);
printf("\n");
for(int i = 0; i < matrix_rows + 1; i++)
printf("%d,",yale->IA[i]);
printf("\n");
for(int i = 0; i < matrix_elements; i++)
printf("%d,",yale->JA[i]);
return yale;
}
And here is the struct for yale:
typedef struct y{
int n;
int m;
int elements;
int *IA;
int *JA;
int *A;
} yale;
But the program segfaults at the first relevant printf on the first iteration of the loop.
printf("%d,",yale->A[i]);
I'm positive:
matrix_elements is an integer (9 in my test case)
matrix_rows is an integer
A / IA / JA are all filled with correct values (if you swap yale->A for A in the printf, it works fine).
Directly callocing the array to the struct pointers doesn't affect the result.
Mallocing, callocing, not typecasting, all no effect.
Thanks to Xcode and gdb I can also see that at the point of the segfault. The structure pointers do NOT seem to point to the arrays
I suggest you run your code under Valgrind. This should report the buffer overflow error. (A buffer overflow is where you write past the end of an array).
I also recommend you write some unit tests for your code. They can be very helpful detecting bugs. In particular, I suggest you write a test with a 3x3 input matrix with a value in every position. Check that the values you get out are what you expect.
To get it compiled, I need to prepend this to the snippet:
#include <stdlib.h>
#include <stdio.h>
typedef struct y{
int n;
int m;
int elements;
int *IA;
int *JA;
int *A;
} yale;
typedef struct list {
struct list *next;
struct point { int x,y,value; } point;
} list;
typedef struct matrix_list {
int elements;
int m;
int n;
struct list *first;
int *point;
} matrix_list;
UPDATE: I transformed the program into something more readable (IMHO). I don't have the faintest idea what the IA and JA are supposed to do, but the below fragment should be equivalent to the OP.
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
struct y {
unsigned int n;
unsigned int m;
unsigned int elements;
unsigned int *IA;
unsigned int *JA;
int *A;
} ;
struct list {
struct list *next;
struct point { unsigned int x,y; int value; } point;
} ;
struct matrix_list {
unsigned int elements;
unsigned int m;
unsigned int n;
struct list *first;
} ;
struct y *convertMatrix(struct matrix_list* input)
{
unsigned int matrix_elements = input->elements;
unsigned int matrix_rows = input->m;
unsigned int ii,jj,tmp_y;
struct y *yale ;
struct list *tmp_list ;
yale = calloc(1, sizeof *yale);
assert (yale != NULL);
printf("%u elements\n",matrix_elements);
yale->A = calloc(matrix_elements, sizeof *yale->A);
assert (yale->A != NULL);
yale->IA = calloc(matrix_rows + 1, sizeof *yale->IA);
assert (yale->IA != NULL);
yale->JA = calloc(matrix_elements, sizeof *yale->JA);
assert (yale->JA != NULL);
yale->elements = matrix_elements;
yale->m = matrix_rows;
yale->n = input->n;
// Initialise the first row, set start condition
// FIXME: this ignores the empty list or size=0 cases
yale->IA[0] = tmp_y = input->first->point.x;
ii = jj = 0;
for(tmp_list = input->first ;tmp_list; tmp_list = tmp_list->next) {
printf("Input Value: %d \n",tmp_list->point.value);
yale->A[ii] = tmp_list->point.value;
// Add a new row index
if(tmp_y != tmp_list->point.x){
jj++;
yale->IA[jj] = ii;
tmp_y = tmp_list->point.x;
}
yale->JA[ii] = tmp_list->point.y;
if (++ii >= matrix_elements ) break;
}
for(int i = 0; i < matrix_elements; i++)
printf("%d,",yale->A[i]);
printf("\n");
for(int i = 0; i < matrix_rows + 1; i++)
printf("%u,",yale->IA[i]);
printf("\n");
for(int i = 0; i < matrix_elements; i++)
printf("%u,",yale->JA[i]);
return yale;
}
Note: I moved the (ii == 0) {} condition out of the loop, and replaced the one-letter indices by there two-letter equivalents. Also: all the indices are unsigned (as they should be)

Resources