How to add struct to an array of structs in C? - c

Ok I have a struct defined as such...
typedef struct
{
enum COMMAND command;
enum CMD_SOURCE source;
CHAR parameters[16];
} focuserCommand;
I am trying to make a function that will add an instance of this type of struct to an array of focuserCommands. The array is defined like this...
extern focuserCommand CommandBuffer[CMD_BUFFER_SIZE];
the function I am trying to write should take a pointer to a focuserCommand and add it to CommandBuffer. I am implementing CommandBuffer as a FIFO ring buffer so I know i need to move the tail forwared so that my other functions can see that the buffer contains data. CmdBuffHead and CmdBuffTail represent the read and write pointers of the buffer. Writes are added to the tail, reads are made from the head.
void AddCmdToBfr( focuserCommand * cmd )
{
// What goes here to add the struct pointed to by cmd to
// element CmdBuffTail of the buffer?
CmdBuffTail++;
}

Given that you have the variable CmdBuffTail pointing at the next element of CommandBuffer to be written to, then:
void AddCmdToBfr(focusCommand *cmd)
{
assert(CmdBuffTail >= 0 && CmdBuffTail < CMD_BUFFER_SIZE);
CommandBuffer[CmdBuffTail++] = *cmd;
if (CmdBuffTail >= CMD_BUFFER_SIZE)
CmdBuffTail = 0;
}
This preserves the invariant that you need - that the index is in the range 0..CMD_BUFFER_SIZE-1.
You may also need a separate index (CmdBuffHead perhaps) to identify where to read from. If so, you would probably need to alter that value in AddCmdToBfr() if CmdBuffTail if catches up with it.
After fixing a goof copying the incoming command, it occurs to me that you need to think carefully about the memory management. In this case, your focususerCommand structure is simple enough (unless the typedef CHAR hides a pointer - in which case, slap wrists; don't hide pointers) that you can simply copy it with impunity. If you can't copy the structure simply (because it contains pointers to allocated memory), then you need to ensure you understand who owns the data to make sure that (a) any allocated memory is released, and (b) any allocated memory is released just once. This would mean, for example, that instead of just copying the new command over the old, you would have to first release the memory allocated to the old entry. Think in terms of C++ copy constructors and destructors - in C.

Related

malloc'd pointer inside struct that is passed by value

I am putting together a project in C where I must pass around a variable length byte sequence, but I'm trying to limit malloc calls due to potentially limited heap.
Say I have a struct, my_struct, that contains the variable length byte sequence, ptr, and a function, my_func, that creates an instance of my_struct. In my_func, my_struct.ptr is malloc'd and my_struct is returned by value. my_struct will then be used by other functions being passed by value: another_func. Code below.
Is this "safe" to do against memory leaks provided somewhere on the original or any copy of my_struct when passed by value, I call my_struct_destroy or free the malloc'd pointer? Specifically, is there any way that when another_func returns, that inst.ptr is open to being rewritten or dangling?
Since stackoverflow doesn't like opinion-based questions, are there any good references that discuss this behavior? I'm not sure what to search for.
typedef struct {
char * ptr;
} my_struct;
// allocates n bytes to pointer in structure and initializes.
my_struct my_func(size_t n) {
my_struct out = {(char *) malloc(n)};
/* initialization of out.ptr */
return out;
}
void another_func(my_struct inst) {
/*
do something using the passed-by-value inst
are there problems with inst.ptr here or after this function returns?
*/
}
void my_struct_destroy(my_struct * ms_ptr) {
free(ms_ptr->ptr);
ms_ptr->ptr = NULL;
}
int main() {
my_struct inst = my_func(20);
another_func(inst);
my_struct_destroy(&inst);
}
I's safe to pass and return a struct containing a pointer by value as you did it. It contains a copy of ptr. Nothing is changed in the calling function. There would, of course, be a big problem if another_func frees ptr and then the caller tries to use it or free it again.
Locality of alloc+free is a best practice. Wherever possible, make the function that allocates an object also responsible for freeing it. Where that's not feasible, malloc and free of the same object should be in the same source file. Where that's not possible (think complex graph data structure with deletes), the collection of files that manage objects of a given type should be clearly identified and conventions documented. There's a common technique useful for programs (like compilers) that work in stages where much of the memory allocated in one stage should be freed before the next starts. Here, memory is only malloced in big blocks by a manager. From these, the manager allocs objects of any size. But it knows only one way to free: all at once, presumably at the end of a stage. This is a gcc idea: obstacks. When allocation is more complex, bigger systems implement some kind of garbage collector. Beyond these ideas, there are as many ways to manage C storage as there are colors. Sorry I don't have any pointers to references (pun intended :)
If you only have one variable-length field and its size doesn't need to be dynamically updated, consider making the last field in the struct an array to hold it. This is okay with the C standard:
typedef struct {
... other fields
char a[1]; // variable length
} my_struct;
my_struct my_func(size_t n) {
my_struct *p = malloc(sizeof *p + (n - 1) * sizeof p->a[0]);
... initialize fields of p
return p;
}
This avoids the need to separately free the variable length field. Unfortunately it only works for one.
If you're okay with gcc extensions, you can allocate the array with size zero. In C 99, you can get the same effect with a[]. This avoids the - 1 in the size calculation.

Memory allocation of struct member variables

I am new to C. I have these two files set up in this way.
I do not fully understand how I am able to assign values in the Item array without dynamically allocating memory.
The line Collection c; places all fields on the stack, so is that why I can directly set array members?
//collection.c
typedef struct {
uint32 price;
uint32 itemId;
} Item;
typedef struct {
Item item[MAX_SIZE];
uint32 name;
} Collection;
void function(Collection * ptr)
{
int i;
uint32 id = 0;
for(i = 0; i < MAX_SIZE; i++)
{
ptr->item[i].price = 10;
ptr->item[i].itemId = id;
id++;
}
}
//collection_main.c
Collection c; //global struct variable
//calls function in collection.c
function(&c);
I do not fully understand how I am able to assign values in the Item array without dynamically allocating memory.
First, as you are new to C, be aware of a potential issue with passing C functions pointers (which is quite reasonable, BTW). Unless you can guarantee that your calling code will always pass a valid pointer you need to check that pointer value in the function as best you can. That will typically amount to checking for a non-null pointer like this :
if ( ptr == NULL )
return <whatever to signal an error> ;
In this case you did allocate memory, because you created a Collection variable and that contains allocated space for the required fields.
The line Collection c; places all fields on the stack,
If it's in a function it will (typically) allocate space on that function's stack frame, which you should logically view as a separate area that the calling code cannot access. Make no assumptions about the layout of the stack. A very typical bug is to try and return a pointer to an item declared inside a function, and even supposedly experienced programmers have been known to do it.
Another potential bug in passing a pointer to a function is trying to access beyond the limits of the space allocated and pointed to. This can do things like corrupt other variables or even crash code. Your own code is correctly using the declared constant size of the array, so no problem.
If you do this outside of a function (which is possible), you would be using space reserved by the OS for these type of variables. That may not be on the stack but elsewhere. The OS gets that information from the compiled code file.
so is that why I can directly set array members ?
C code (and the executable binary that's produced by the compiler) does not care or check whether the pointers you pass are valid or not. So it's possible to pass a bad pointer to a C function and cause chaos.
In this case you did allocate all the required valid memory when you declared the variable and you passed a pointer to that variable. So no problem.
Dynamic memory allocation
It is more usual to consider explicit allocation using the malloc() family of functions as dynamic allocation. Allocations for local and global variables may be dynamic in the sense that they can happen at runtime but the allocation and deallocation are not the responsibility of the programmer to explicitly control so you do not generally need to think about these as part of dynamic memory allocation.
A minor point to close :
uint32 name ;
I'd consider this a bad choice of field name. Using "name" implies a string, whereas you probably mean a string id from e.g. an array. So try something like :
uint32 nameid ;
instead.
You'd be surprised how many coding problems crop up in a production environment simply because of a poor choice of variable name. Make them informative if possible and practical.
This is just a good coding habit to get into, IMO.

C structs sharing common pointer?

I'm currently having an issue with the following struct:
typedef struct __attribute__((__packed__)) rungInput{
operation inputOperation;
inputType type;
char* name;
char numeroInput;
u8 is_not;
} rungInput;
I create multiple structs like above inside a for loop, and then fill in their fields according to my program logic:
while (a < 5){
rungInput input;
(...)
Then when I'm done filling the struct's fields appropriately, I then attempt to copy the completed struct to an array as such:
rungArray[a] = input; //memcpy here instead?
And then I iterate again through my loop. I'm having a problem where my structs seem to all have their name value be the same, despite clearly having gone through different segments of code and assigning different values to that field for every loop iteration.
For example, if I have three structs with the following names: "SW1" "SW2" SW3", after I am done adding them to my array I seem to have all three structs point me to the value "SW3" instead. Does this mean I should call malloc() to allocate manually each pointer inside each struct to ensure that I do not have multiple structs that point to the same value or am I doing something else wrong?
When you write rungArray[i] = input;, you are copying the pointer that is in the input structure into the rungArray[i] structure. If you subsequently overwrite the data that the input structure is pointing at, then you also overwrite the data that the rungArray[i] structure is pointing at. Using memcpy() instead of assignment won't change this at all.
There are a variety of ways around this. The simplest is to change the structure so that you allocate a big enough array in the structure to hold the name:
enum { MAX_NAME_SIZE = 32 };
…
char name[MAX_NAME_SIZE];
…
However, if the extreme size of a name is large but the average size is small, then this may waste too much space. In that case, you continue using a char *, but you do indeed have to modify the copying process to duplicate the string with dynamically allocated memory:
rungArray[i] = input;
rungArray[i].name = strdup(input.name);
Remember to free the memory when you discard the rungArray. Yes, this code copies the pointer and then overwrites it, but it is more resilient to change because all the fields are copied, even if you add some extra (non-pointer) fields, and then the pointer fields are handled specially. If you write the assignments to each member in turn, you have to remember to track all the places where you do this (that would be a single assignment function, wouldn't it?) and add the new assignments there. With the code shown, that mostly happens automatically.
You should malloc memory for your struct and then store the pointers to the structs inside your array. You could also turn your structs into a linked list by adding a pointer to each struct that points to the next instance of your struct.
http://www.cprogramming.com/tutorial/c/lesson15.html

Freeing the memory arrays of structures in C

Assume the following situation:
typedef struct {
int ID1;
int ID2;
char string[256];
} Reg;
I create an array dynamically, this structure:
Reg *myReg = (Reg*) malloc(sizeof(Reg)*100); //array of type Reg with 100 positions.
And throughout this example system, I fill this array.
There comes a certain point I do not want the pointer "myReg" point to this vector. I want him to point to NULL. And also to clear the memory space occupied by malloc I did.
question:
If I do:
free(myReg);
This will make myReg will point to NULL and release the space taken up that I've allocated?
free(myReg);
This will make myReg will point to NULL and release the space taken up
that I've allocated?
It will only release the memory. Even without reading the specs, if you look at how the free function is declared, you'll see it can't actually change what the pointer is pointing to.
/* Even if it wanted, `free` can't make `ptr` point to anything else. */
void free(void *ptr);
A call to free only free's the memory allocated and returns it to the heap. It will not set the your myReg to NULL. You must do it yourself.
One way is to write a macro as below:
#define MY_FREE(ptr) free(ptr); ptr = NULL;
Other answers are correct.
To help understanding why it must be so, consider that there may be multiple pointers pointing to this memory, or to different parts of it:
Reg *myReg = (Reg*) malloc(sizeof(Reg)*100);
Reg *myReg2 = myReg;
Reg *myReg3 = &myReg[50];
When you free myReg, all these pointers are unchanged. They point to the same piece of memory as before, but this memory must no longer be used.
You, the programmer, should set them to NULL (or just avoid using them after free).
C can't find them all and set them to NULL. More modern languages, such as Java, know how to track all the pointers to a given object, but C does nothing like this.

Reading and Writing Structures [C]

IMPORTANT EDIT:
Sorry everyone, i made a big mistake in the structure.
char *name; is meant to be outside of the structure, written to the file after the structure.
This way, you read the structure, find out the size of the name, then read in the string. Also explains why there is no need for a null terminator.
However, i feel somewhere, my actual question has been answered. If someone would like to edit their responses so i can choose one which is the best fitting i'd appreciate it.
Again, the question I was asking is "If you read in a structure, are you also reading in the data it holds, or do you need to access it some other way".
Sorry for the confusion
For an assignment, I've been tasked with a program which writes and reads structures to a disk (using fread and fwrite).
I'm having trouble grasping the concept.
Lets say we have this structure:
typedef struct {
short nameLength;
char* name;
}attendenceList;
attendenceList names;
now assume we give it this data:
names.name = "John Doe\0";
names.nameLength = strlen(names.name); /*potentially -1?*/
and then we use fwrite... given a file pointer fp.
fwrite(&names,sizeof(names),1,fp);
now we close the file, and open it later to read in the structure.
the question is this: when we read in the structure, are we also reading in the variables it stores?
Can we then now do something like:
if(names.nameLength < 10)
{
...
}
Or do we have to fread something more then just the structure, or assign them somehow?
Assuming the fread is:
fread(&names,sizeof(names),1,fp);
Also assuming we've defined the structure in our current function, as above.
Thanks for the help!
You have a problem here:
fwrite(&names,sizeof(names),1,fp);
Since attendenceList saves the name as a char * this will just write out the pointer, not the actual text. When you read that back in, the memory the pointer is referencing will most likely have something else in it.
You have two choices:
Put a character array (char names[MAXSIZE]) in attendenceList.
Don't write the raw data structure, but write the necessary fields.
You're writing the memory layout of the structure, which includes its members.
You'll get them back if you read the structure back in again - atleast if you do it on the same platform, with a program compiled with the same compiler and compiler settings.
Your name member is declared just as a char, so you can't store a string in it.
If name was a pointer like this:
typedef struct {
short nameLength;
char *name;
}attendenceList;
You really should not read/write the struct to a file. You will write the structure as it's laid out in memory, and that includes the value if the name pointer.
fwrite knows nothing about pointers inside your structure, it will not follow pointers and also write whatever they point to.
when you read the structure back again, you'll read in the address in the name pointer, and that might not point to anything sensible anymore.
If you declare name as an array, you'll be ok, as the array and its content is part of the structure.
typedef struct {
short nameLength;
char name[32];
}attendenceList;
As always, make sure you don't try to copy a string - including its nul terminator- to name that's larger than 32. And when you read it back again. set yourstruct.name[31] = 0; so you are sure the buffer is null terminated.
To write a structure, you'd do
attendenceList my_list;
//initialize my_list
if(fwrite(&my_list,sizeof my_list,1,f) != 1) {
//handle error
}
And to read it back again:
attendenceList my_list;
//initialize my_list
if(fread(&my_list,sizeof my_list,1,f) != 1) {
//handle error
}
}
I'm assuming you meant char* name instead of char name.
Also sizeof(name) will return 4 because you are getting the size of a char* not the length of the char array. So you should write strlen(name) not sizeof(name) inside your fwrite.
In your above example I would recommend storing the string exact size without the null termination. You don't need to store the string length as you can get that after.
If you are reading just a string from a file, and you wrote the exact size without the null termination. Then you need to manually null terminate your buffer after you read the data in.
So make sure you allocate at least the size of your data you are reading in plus 1.
Then you can set the last byte of that array to '\0'.
If you write a whole struct at a time to the buffer, you should be careful because of padding. The padding may not always be the same.
when we read in the structure, are we also reading in the variables it stores?
Yes you are, but the problem you have is that as I mentioned above you will be storing the pointer char* (4 bytes) and not the actual char array. I would recommend storing the struct elements individually.
You ask:
now we close the file, and open it later to read in the structure. the question is this: when we read in the structure, are we also reading in the variables it stores?
No. sizeof(names) is a constant value defined at compile time. It will be the same as
sizeof(short) + sizeof(void*) + some_amount_of_padding_to_align_things
it will NOT include the size of what names.name points to, it will only include the size of the pointer itself.
So you have two problems when writing this to a file.
you aren't actually writing the name string to the file
you are writing a pointer value to the file that will have no meaning when you read it back.
As your code is currently written, When you read back the names, names.name will point to somewhere, but it won't point to "John Doe\0".
What you need to do is to write the string pointed to by names.name instead of the pointer value.
What you need to do is sometimes called "flattening" the structure, You make a structure in memory that contains no pointers, but holds the same data as the structure you want to use, then you write the flattened structure to disk. This is one way to do that.
typedef struct {
short nameLength;
char name[1]; // this will be variable sized at runtime.
}attendenceListFlat;
int cbFlat = sizeof(attendenceListFlat) + strlen(names.name);
attendenceListFlat * pflat = malloc(cbFlat);
pflat->nameLength = names.nameLength;
strcpy(pflat->name, names.name);
fwrite(pflat, cbFlat, 1, fp);
The flattened structure ends with an array that has a minimum size of 1, but when we malloc, we add strlen(names.name) so we can treat that as an array of strlen(names.name)+1 size.
A few things.
Structures are just chunks of memory. It's just taking a bunch of bytes and drawing boundaries on them. Accessing structure elements is just a convenient way of getting a particular memory offset cast as a particular type of data
You are attempting to assign a string to a char type. This will not work. In C, strings are arrays of characters with a NULL byte at the end of them. The easiest way to get this to work is to set a side a fixed buffer for the name. When you create your structure you'll have to copy the name into the buffer (being very careful not to write more bytes than the buffer contains). You can then write/read the buffer from the file in one step.
struct attendanceList {
int namelen;
char name[256]; //fixed size buffer for name
}
Another way you could do it is by having the name be a pointer to a string. This makes what you're trying to do more complicated, because in order to write/read the struct to/from a file, you will have to take into account that the name is stored in a different place in memory. This means two writes and two reads (depending on how you do it) as well as correctly assigning the name pointer to wherever you read the data for the name.
struct attendanceList {
int namelen;
char* name; //the * means "this is a pointer to a char somewhere else in memory"
}
There's a third way you could do it, with a dynamically sized struct using a trick with a zero length array at the end of a struct. Once you know how long the name is, you allocate the correct amount (sizeof(struct attendanceList) + length of string). Then you have it in one contiguous buffer. You just need to remember that sizeof(struct attendanceList) is not the size you need to write/read. This might be a little confusing as a beginning. It is also kind of a hack that's not supported under all compilers.
struct attendanceList {
int namelen;
char name[0]; //this just allows easy access to the data following the struct. Be careful!
}

Resources