Adressing values of a nested structure in C - c

I have a nested structure as follows:
typedef struct {
float mz_value;
float int_value;
} spectrum;
typedef struct {
// stuff
spectrum* spectra; /* Nested struct */
// more stuff
} chromatogram;
I allocate memory in my code as follows:
(chrom+i)->spectra=malloc(sizeof(spectrum)*1024);
I then want to assign some values to it and I have been trying all kinds of syntaxes similar to:
((chrom+i)->(spectra+j))->mz_value = (float)*(array_buffer+j);
// array_buffer is a float*
Yet this keeps giving me an error that I am failing at proper usages of braces, the only problem is that I can't figure out where o.O Any help would be greatly appreciated before I regret trying to use a nested structure.
Cheers,
Bas

Try
((chrom+i)->spectra+j)->mz_value = (float)*(array_buffer+j);
Or, preferably, use array notation, which is much clearer in this case:
chrom[i].spectra[j].mz_value = (float)array_buffer[j];

Your spectra value is not a statically allocated structure it's a pointer
and you need allocate memory for it.
If you are going to work with fixed number of spectrum items
use statically allocated array
spectrum spectra[someConstantValue];
or allocate/free it dynamically, in this case you also need to hold number of elements.
typedef struct {
// stuff
spectrum* spectra; /* Nested struct */
int count;
// more stuff
} chromatogram;

Related

Is this a correct way of freeing multiple dynamically allocated arrays that are part of a struct?

I am working on C code that reads in binary files, and organises the data contained in these files into a struct before processing. In its most concise form, the main function is structured as follows:
1) read_hgf_file
2) process_contents
3) free_allocated_memory
Because the data consists of recordings at different points in space, the most convenient is to organise the data in a struct with arrays. I have included the definition of this struct in a header file "read_hgf.h", which looks as follows (I am using MSVS 2017):
#pragma once
struct HGF {
int32_t Nrows;
int32_t Ncols;
int32_t Np;
float *data;
float *xcoords;
float *ycoords;
float *zcoords;
};
The first three fields help to define the size of the latter four.
In my main function, I call a function that fills these fields with the data from the binary file, which works fine. At the end now, I want to free the dynamically allocated memory associated with this struct. Because it looks messy if I free these arrays one-by-one in the main function, I want to wrap this functionality in a function free_hgf(). Did I understand correctly that I have to free these fields one-by-one, just as they are declared? Would the following be a correct way of doing that, or am I violating any C rules/best practices (particularly related to the combination of the * and -> operators)?
function:
#include "read_hgf.h"
void free_hgf(struct HGF **hgf) {
free((*hgf)->zcoords);
free((*hgf)->ycoords);
free((*hgf)->xcoords);
free((*hgf)->data);
*hgf = NULL;
}
Called from main as follows:
#include "read_hgf.h"
struct HGF hgf;
struct HGF *hgfPtr = &hgf;
free_hgf(&hgfPtr);
Thanks in advance!
I assume that the function which fills HGF structure is written by you and members of HGF structure are allocated with malloc, like
void read_hgf(struct HGF * hgf)
{
...
hgf->data = malloc(...);
hgf->xcoords = malloc(...);
hgf->ycoords = malloc(...);
hgf->zcoords = malloc(...);
...
}
Usage of the structure would be
struct HGF hgf;
read_hgf(&hgf);
...
free_hgf(&hgf);
and freeing part,
void free_hgf(struct HGF * hgf) // single pointer is enough to pass a structure
{
free(hgf->zcoords);
free(hgf->ycoords);
free(hgf->xcoords);
free(hgf->data);
// clear members
hgf.data = NULL;
...
}
Remember if you allocated memory N times (with malloc, realloc, ...), after you've done using them, you must call free N times.

invalid use of flexible array ERROR in C

I have the following struct:
typedef struct dish_t {
const char *name;
const char *cook;
int maxIngredients;
bool tasted;
Ingredient *ingredients[];
}* Dish;
And the following initialization function:
Dish dishCreate(const char* name, const char* cook, int maxIngredients) {
if (name == NULL || cook == NULL || maxIngredients <= 0 )
{
return NULL;
}
Dish newDish=malloc(sizeof(*newDish));
newDish->name=malloc(strlen(name)+1);
newDish->name=name;
newDish->cook=malloc(strlen(cook)+1);
newDish->cook=cook;
newDish->maxIngredients=maxIngredients;
newDish->ingredients=malloc(maxIngredients*sizeof(Ingredient*));
newDish->tasted=false;
return newDish;
}
Ingredient is also a struct.
and on this line
newDish->ingredients=malloc(maxIngredients*sizeof(Ingredient*));
I get the error.
I'm trying to initialize an array of pointers to a struct...what am I doing wrong?
Thanks.
The struct member ingredients is an array of pointers, not a pointer. You cannot assign to an array in C; not to change its contents, and certainly not to change its address. The pattern <array> = malloc(...) makes no sense in C.
Just change the declaration to
Ingredient *ingredients;
Forget about flexible member; that's a memory allocation strategy that won't add to the semantics or quality of your program.
In some kinds of programs, flexible arrays at the end of a structure can be a useful
optimization, since they reduce the number of calls to the allocator: a header structure plus some variable data can be allocated in a single malloc call and released in a single free call.
This doesn't achieve anything semantically interesting in the program, and naive use of this approach can make programs slower and waste memory, since two or more objects with flexible data at the end have to have their own copies of the data in situations where a program that uses a pointer could efficiently share that data.
The problem is that you try to make a flexible array of pointers, and then you try to create this using malloc, which is not what you're supposed to do.
With flexible arrays in a structure, you're supposed to make the initial allocation of the structure longer, to fit the number of elements in the array.
If you're going to use malloc for the array, you might as well use a normal pointer.
To explain what I mean:
typedef struct dish_t {
...
Ingredient ingredients[];
}* Dish;
...
Dish myDish = malloc(sizeof(*myDish) + sizeof(Ingredient) * 10);
The above malloc allocates the structure and enough space for ten entries in the array.

Using malloc to create an array of structs, will struct be created in each cell?

Suppose I have the following structs:
typedef struct plane_t Plane;
struct plane_t{
Point p1;
Point p2;
Point p3;
};
typedef struct arrangement_t* Arrangement;
struct arrangement_t{
//TODO add fields here
int maxPlanes;
int curPlanes;
Plane *planes;
};
And I have the following function:
Plane planeCreate(Point point1, Point point2, Point point3){
Plane newPlane = {{point1.x, point1.y, point1.z}, {point2.x, point2.y, point2.z}, {point3.x, point3.y, point3.z}};
return newPlane;
}
Arrangement arrangementCreate(int maxPlanes){
if (maxPlanes < 1) return NULL;
Arrangment newArrangment = malloc(sizeof struct arrangement_t);
if (newArrangment == NULL) return NULL;
newArrangment->planes = malloc(sizeof(Plane)*maxPlanes);
if (newArrangment->planes == NULL) {
free(newArrangment);
return NULL;
}
newArrangment->maxPlanes = maxPlanes;
newArrangment->curPlanes = 0;
return newArrangment;
}
Will the following line mean that every cell within the array will have a stuct of type Plane, or I still have to go over each cell in manually create them one by one?
newArrangment->planes = malloc(sizeof(Plane)*maxPlanes);
malloc will allocate enough space for an array of maxPlanes structs, but it's up to you to initialize them.
In other words, if malloc succeeds, you will be able to access the structs newArrangement->planes[0] through newArrangement->planes[maxPlanes-1]. The structs are laid out end-to-end in memory as one contiguous block.
Your code is probably (see below) fine (by "fine" I mean functional, not well-designed). Your malloc(sizeof(Plane)*maxPlanes) will allocate space for maxPlanes planes, and you do not have to allocate each cell.
The cells themselves don't "have a struct of type Plane", it is merely a block of memory large enough to hold the information stored in maxPlanes Plane structs. Since you are accessing that block via a Plane pointer, the data will be interpreted as a Plane struct.
I say probably because your Plane struct members will be uninitialized (will contain random data), and since you don't show what a Point is, there is not enough information to know if what you have is sufficient. You also do not show what you are going to end up doing with the arrangement_t, so I presume that it is acceptable to leave the values uninitialized and that you are setting the values to something meaningful later.
I'd also make a number of recommendations to clarify your code:
You typedef Arrangement as a pointer but Plane as a struct. I suggest perhaps qualifying your Arrangement type as ArrangementPtr or something instead to make the distinction and reduce confusion.
Consider using calloc instead of malloc for clarity: calloc(maxPlanes, sizeof(Plane))
If zeroing the memory is acceptable to you for initialization, you can do a quick memset(planes, 0, sizeof(Plane)*maxPlanes).
Unless you have a specific reason to use C (there are many), you may wish to consider C++ (with STL classes if they are available to you), which will greatly reduce a lot of the work and possible sources of error in your code (note this is still not ideal because public members can break invariants that you may have, but just as an example):
struct Plane {
Point p1;
Point p2;
Point p3;
Plane ();
Plane (const Point &, const Point &, const Point &);
};
struct Arrangement {
int maxPlanes;
int curPlanes;
std::vector<Plane> planes;
explicit Arrangement (int maxPlanes);
};
Plane::Plane () {
}
Plane::Plane (const Point &p1, const Point &p2, const Point &p3) :
p1(p1), p2(p2), p3(p3)
{
}
Arrangement::Arrangement (int maxPlanes) :
maxPlanes(maxPlanes),
curPlanes(0),
planes(maxPlanes)
{
}
That will handle all memory management for you; your job would be to catch std::bad_alloc to check for memory allocation errors, or add any necessary parameter validation.
Your code has a number of other problems, or potential for problems, but that's outside the scope of this question I think.

C: how to manage a large structure?

In C:
I am trying to use a structure containing a large array, and I have a stack overflow error while declaring it. I guess (correctly?) that I don't have enough memory in the stack, and therefore, I should use the heap (I don't want to change my stack memory size, as the code will be used by others). Could anyone show me a way to do it simply? Or should I use something else than a structure?
My code - definitions.h:
#define a_large_number 100000
struct std_calibrations{
double E[a_large_number];
};
My code - main.c:
int main(int argc, char *argv[])
{
/* ...
*/
// Stack overflows here:
struct std_calibrations calibration;
/* ...
*/
return (0);
}
Thank you for your help!
A couple of options:
Use malloc(3) and free(3) to dynamically allocate your structure at runtime. This option is what you're talking about when you say you "should use the heap."
struct std_calibrations *calibration = malloc(sizeof *calibration);
and later,
free(calibration);
Give the structure static storage duration. Either add a static keyword or make it global. This option may change some semantics about how you use the structure, but given your example code, it should be fine.
Change the member E to be a double* and malloc() memory for it:
struct std_calibrations calibration;
calibration->E = malloc(sizeof(*calibration->E) * a_large_number);
and remember to free(calibration->E); when no longer required. It would be possible to extend struct std_calibrations, if desired, to contain the number of elements in E so a user of struct std_calibrations could decide how many elements they require.

How to put several structs continuous into the memory?

I am implementing a PSO Algorithm. I use this
data structure:
typedef struct {
float x;
float y;
} C_struct_Class2D;
typedef struct {
C_struct_Class2D *pos;
C_struct_Class2D *best_pos;
C_struct_Class2D *vel;
} C_struct_Particle;
typedef struct { <br>
C_struct_Particle **particles;
C_struct_Particle *g;
} C_struct_Swarm;
I have to work with C, not with C++. That's why I use structs instread of classes.
Description of the strucs:
There is a Swarm(C_struct_Swarm) which consists of several Particles(**particles) an an optimum Particles(*g). Each Particle has a Position, Best Position and Velocity of Type
"C_struct_Class2D".
In a few methods I allocate memory space for each data and initialize it. But I' like
the whole data structure to be continuous in the memory. So that all structs are
behind each other in the address space.
The memory should look like:
C_struct_Swarm
particles[0]
particles[0]->pos
particles[0]->best_pos
particles[0]->vel
particles[1]
particles[1]->pos
particles[1]->best_pos
particles[1]->vel
...
...
...
...
particles[n]
particles[n]->pos
particles[n]->best_pos
particles[n]->vel
g->pos
g->best_pos
g->vel
How can I achieve this?
Regards
sw
Compose members by value
Include C_struct_Class2D by value inside C_struct_Particle:
typedef struct {
C_struct_Class2D pos;
C_struct_Class2D best_pos;
C_struct_Class2D vel;
} C_struct_Particle;
This guarantees the order of those members (pos is before best_pos is before vel).
Allocate an array of items, instead of an array of pointers to items
typedef struct {
C_struct_Particle *particles;
int num_particles;
C_struct_Particle g;
} C_struct_Swarm;
I should note that here, the data pointed to by particles is NOT contiguous with the other members, so what you are asking for is not entirely possible, unless you do something else like set g to always be the first particle, i.e. included in the particles "array".
Watch out for padding
If you don't care about padding (and in your code example it looks like you don't), then skip this. Otherwise it's platform/compiler specific. In GCC for example, you can use the packed attribute:
struct __attribute__ ((__packed__)) my_packed_struct
{
char c;
int i;
};
You cannot in the way you have described. If you want continuous blocks of memory, the only solution (as far as I know) is to use buffers (see my similar answer that might give you an idea how to implement it).
If you use gcc, for static object you could try __attribute__... more info here http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Variable-Attributes.html
iw source code as example

Resources