The situation is that I have an array of struct
tree_t tree[MAXTREES];
and I have been using a pointer to access the array's elements
for(int i = 0; i < MAXTREES; i++) {
tree_t *tptr = tree + i;
// ...
}
To make the code easier to manage - compare these simple examples:
int num;
num = tree[i].node[j].left; // could be like this
num = tptr->node[j].left; // but I am using this
That's the situation, but I made a bug by mistakenly typing
num = tree->node[j].left;
and because the array decays to a pointer to its first element, it's valid C code and it took me a while to spot what I had done wrong.
Is there a way to get a warning about this? Or is it just poor programming style?
Here is a compilable example, it's not worth actually runnning.
#include <stdint.h>
#define MAXLEAFS 16384
#define MAXTREES 15262
typedef struct {
int16_t left;
int16_t right;
} leaf_t;
typedef struct tree_t {
leaf_t node[MAXLEAFS];
int spudbase;
int root;
int width;
int spudics;
struct tree_t *nextree;
} tree_t;
tree_t tree[MAXTREES];
int main(void)
{
for(int i = 0; i < MAXTREES; i++) {
tree_t *tptr = tree + i;
for (int j = 0; j < MAXLEAFS; j++) {
int num;
num = tree[i].node[j].left; // could be like this
num = tptr->node[j].left; // but I am using this
num = tree->node[j].left; // this is my bug
}
}
}
Edit: To illustrate why I am doing this, here is a snippet of my actual code, which I simplified to ask the question. I am using a pointer to the struct to avoid nesting the array indexing here:
tree[index].spudics = tree[index].node[tree[index].root].left +
tree[index].node[tree[index].root].right;
and simplify with
tptr->spudics = tptr->node[tptr->root].left + tptr->node[tptr->root].right;
which IMO is more readable.
This is an avoidable problem. If you rewrite this to use iterator pointers you get code like this:
int main(void)
{
tree_t *tptr = tree;
for (int i = 0; i < MAXTREES; ++i, ++tptr) {
leaf_t *leaf = tptr->node;
for (int j = 0; j < MAXLEAFS; ++j, ++leaf) {
int num = leaf->left;
}
}
}
This avoids a lot of problems because you're using very focused pointers and there's really no reason to do things like leaf[j].left by accident. The correct code looks simple. The incorrect code looks broken.
Related
I have a structure:
struct Path{
int8_t maxtopy;
};
And I want to create an array of pointers to structure Path. I've tried something like that:
int main(){
struct Path *paths[NUMBER_OF_PATHS];
init_paths(paths);
}
void init_paths(struct Path **paths){
paths[0]->maxtopy = -1;
for(int i = 1; i < NUMBER_OF_PATHS; i++)
paths[i]->maxtopy = -1;
}
It is not going to work. Value to the first path is assigned correctly. But when for loop starts I am gettting Segmentation fault. I already figured out that when I am creating array of pointers, only the first pointer is going to be assigned to some structure. So I cannot e.g. paths[1]->maxtopy = -1;, because paths[1] doesn't point to any existing structure.
I have tried something like this:
for(int i = 1; i < NUMBER_OF_PATHS; i++){
static struct Path a;
paths[i] = &a;
paths[i]->maxtopy = i;
}
It doesn't work because it initialize a only once. So every pointer in paths array points to the same structure.
My question is: How to create an array of pointers that point to initialized structures?
You've created an array of pointers, butt the pointers need to point to something. You can dynamically allocate each with malloc.
struct Path{
int8_t maxtopy;
};
int main(void) {
struct Path *paths[NUMBER_OF_PATHS];
for (size_t i = 0; i < NUMBER_OF_PATHS; i++) {
paths[i] = malloc(sizeof(struct Path));
paths[i]->maxtopy = i;
}
return 0;
}
Of course, if your array is declared in main and is not of excessive size, you may want to simply write the following.
int main(void) {
struct Path paths[NUMBER_OF_PATHS];
for (size_t i = 0; i < NUMBER_OF_PATHS; i++) {
paths[i].maxtopy = i;
}
return 0;
}
const int NUMBER_OF_PATHS = 10;
struct Path {
int8_t maxtopy;
};
void init_paths(struct Path** paths) {
for (int i = 0; i < NUMBER_OF_PATHS; i++) {
paths[i] = (Path*)malloc(sizeof(Path));
paths[i]->maxtopy = i;
}
}
int main() {
struct Path* paths[NUMBER_OF_PATHS];
init_paths(paths);
for (auto i : paths) {
printf("%d\n", i->maxtopy);
}
}
I'm hiding a pointer with the typedef and I'm trying to make an array of it. my structure is:
typedef struct s {
int y;
int x;
int value;
} s;
typedef s *t;
and the main:
int main()
{
t *var;
int arg;
var = malloc(sizeof(t*));
arg = 40;
for (int x = 0; x < arg; x++)
{
var[x] = malloc(sizeof(t));
var[x]->x = -1;
var[x]->y = -1;
var[x]->value = 0;
}
for (int x = 0; x < arg; x++)
{
printf("|%d| ",var[x]->value);
}
return 0;
}
sometime it just goes to segmentation fault and sometimes the value is just dirty, but it still means that it did not allocated the memory as intented. what am I missing? I'm just trying to make an array of type t with arg length which must be a variable
I'm hiding a pointer with the typedef
This very bad practice is the root of all your bugs. Simply don't hide pointers behind typedef.
Because now you have a t* var which is actually a s**. Then you call var = malloc(sizeof(t*)); which is completely wrong, because you allocate room for a s**.
You should have allocated room for 40 * sizeof(s*) or otherwise var[x] will seg fault.
And then typedef or not, this is not a 2D array but a segmented look-up table, which adds extra complexity and slower code, for absolutely nothing gained. See Correctly allocating multi-dimensional arrays. But it doesn't even look like you need a 2D array, so what's all of that coming from?
With all of this in mind, lets go with the KISS principle and rewrite the code from scratch:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int y;
int x;
int value;
} s;
int main (void)
{
int arg = 40;
s* var = malloc(arg * sizeof(*var));
for (int i = 0; i < arg; i++)
{
var[i].x = -1;
var[i].y = -1;
var[i].value = 0;
}
for (int i = 0; i < arg; i++)
{
printf("|%d| ",var[i].value);
}
free(var);
return 0;
}
A 2D version would use s (*var)[y] = malloc( sizeof(s[x][y]) ); instead.
I have defined these 2 structs:
#define MAP_SIZE 5
typedef struct battle_cell {
int status_a;
int status_b;
int ship_a;
int ship_b;
} battle_cell;
struct battlemap {
battle_cell cell[MAP_SIZE][MAP_SIZE];
int progress_a;
int progress_b;
};
After the initalization of the map and all the other variables with zeros:
for (i = 0; i < MAP_SIZE; i++) {
for (j = 0; j < MAP_SIZE; j++) {
map->cell[i][j].status_a = 0;
map->cell[i][j].status_b = 0;
map->cell[i][j].ship_a = 0;
map->cell[i][j].ship_b = 0;
}
}
map->progress_a = 0;
map->progress_b = 0;
There is a point that I have to check the ship_a and ship_b values that live in each cell, something like that (the logic is a bit more complex than this iteration):
for (i = posXB; i < posXB + SHIP_SIZE; i++) {
map->cell[posYB][i].ship_b = 1;
}
I need to do exactly the same for the ship_a variable. So, I have to duplicate quite a big chunk of code because I am not able to find a way to get the field within the struct dynamically. For example, I could define a function:
void cell_iteration (battlemap *map, int pos, int pos_y, int ship_size, /* field_parameter/pointer */) {
int i;
for (i = pos; i < pos + ship_size; i++) {
map->cell[pos_y][i].ship_b = 1; // use the field_parameter/pointer instead of ship_b
}
}
Is there an elegant way to do something like that?
UPDATE
Just a clarification. The structs can definitely be simplified, but this is not my question. I 've just tried to create an example :)
Instead if ship_a and ship_b int the first struct, you can declare int ship[2] an array of 2 int.
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)
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);
}
}