How can I make an iterator over a dynamic array (in a struct)?
Your dynamic array, as represented by type struct _Lista, does not contain "elements of any type". At least not directly. It contains only and exactly elements of type void *. Pretty much everything you've written will work if you change type iterator accordingly, to a double pointer:
typedef void **iterator;
Do note, however, that this iterator implementation has a severe flaw: it does not carry any information about the bounds of the list. That may be OK if you ensure that there is a sentinel value after the last valid element (and maybe before the first, too), but otherwise you'll need a more complex data structure than just one pointer.
Related
What is the difference between using flexible array member (FAM) or pointer member ? In the two cases, a malloc and an affectation element by element must be done. But with FAM, a memory allocation is done for the whole structure and with ptr member, a memory allocation is done for the ptr member only (see code). What are the pros ans the cons of these two methods ?
#include <stdio.h>
#include <stdlib.h>
typedef struct farr_mb {
int lg;
int arr[];
} Farr_mb;
typedef struct ptr_mb {
int lg;
int * ptr;
} Ptr_mb;
int main() {
int lg=5;
Farr_mb *a=malloc(sizeof(Farr_mb)+lg*sizeof(int));
Ptr_mb b; b.ptr=malloc(lg*sizeof(int));
for (int i=0;i<lg;i++) (a->arr)[i]=i;
for (int i=0;i<lg;i++) (b.ptr)[i]=i;
for (int i=0;i<lg;i++) printf("%d \t",(a->arr)[i]=i);
printf("\n");
for (int i=0;i<lg;i++) printf("%d \t",(b.ptr)[i]=i);
return 0;
}
Before we get to the pros and cons, let's look at some real-world examples.
Let's say we wish to implement a hash table, where each entry is a dynamically managed array of elements:
struct hash_entry {
size_t allocated;
size_t used;
element array[];
};
struct hash_table {
size_t size;
struct hash_entry **entry;
};
#define HASH_TABLE_INITIALIZER { 0, NULL }
This in fact uses both. The hash table itself is a structure with two members. The size member indicates the size of the hash table, and the entry member is a pointer to an array of hash table entry pointers. This way, each unused entry is just a NULL pointer. When adding elements to a hash table entry, the entire struct entry can be reallocated (for sizeof (struct entry) + allocates * sizeof (element) or freed, as long as the corresponding pointer in the entry member in the struct hash_table is updated accordingly.
If we used element *array instead, we would need use struct hash_entry *entry: in the struct hash_table; or allocate the struct hash_entry separately from the array; or allocate both struct hash_entry and array in the single chunk, with the array pointer pointing just after the same struct hash_entry.
The cost of that would be two extra size_ts worth of memory used for each unused hash table slot, as well as an extra pointer dereference when accessing elements. (Or, to get the address of the array, two consecutive pointer dereferences, instead of one pointer dereference plus offset.) If this is a key structure heavily used in an implementation, that cost can be visible in profiling, and negatively affect cache performance. For random accesses, the larger the element array is, the less difference there is, however; the cost is largest when the arrays are small, and fit within the same cacheline (or a few cachelines) as the allocated and used members.
We do not usually want to make the entry member in the struct hash_table a flexible array member, because that would mean you no longer can declare a hash table statically, using struct hash_table my_table = HASH_TABLE_INITIALIZER;; you would need to use a pointer to a table, and an initializer function: struct hash_table *my_table; my_table = hash_table_init(); or similar.
I do have another example of related data structures using both pointer members and flexible array members. It allows one to use variables of type matrix to represent any 2D matrix with double entries, even when a matrix is a view to another (say, a transpose, a block, a row or column vector, or even a diagonal vector); these views are all equal (unlike in e.g. GNU Scientific Library, where matrix views are represented by a separate data type). This matrix representation approach makes writing robust numerical linear algebra code easy, and the ensuing code is much more readable than when using GSL or BLAS+LAPACK. In my opinion, that is.
So, let's look at the pros and cons, from the point of view of how to choose which approach to use. (For that reason, I will not designate any feature as "pro" or "con", as the determination depends on the context, on each particular use case.)
Structures with flexible array members cannot be initialized statically. You can only refer to them via pointers.
You can declare and initialize structures with pointer members. As shown in above example, using a preprocessor initializer macro can mean you do not need an initializer function. For example, a function accepting a struct hash_table *table parameter can always resize the array of pointers using realloc(table->entry, newsize * sizeof table->entry[0]), even when table->entry is NULL. This reduces the number of functions needed, and simplifies their implementation.
Accessing an array via a pointer member can require an extra pointer dereference.
If we compare the accesses to arrays in statically initialized structures with pointer to the array, to a structure with a flexible array member referred via a static pointer, the same number of dereferences are made.
If we have a function that gets the address of a structure as a parameter, then accessing an array element via a pointer member requires two pointer dereferences, whereas accessing a flexible array element requires only one pointer dereference and one offset. If the array elements are small enough and the array index small enough, so that the accessed array element is in the same cacheline, the flexible array member access is often significantly faster. For larger arrays, the difference in performance tends to be insignificant. This does vary between hardware architectures, however.
Reallocating an array via a pointer member hides the complexity from those using the structure as an opaque variable.
This means that if we have a function that receives a pointer to a structure as a parameter, and that structure has a pointer to a dynamically allocated array, the function can reallocate that array without the caller seeing any change in the structure address itself (only structure contents change).
However, if we have a function that receives a pointer to a structure with a flexible array member, reallocating the array means reallocating the entire structure. That potentially modifies the address of the structure. Because the pointer is passed by value, the modification is not visible to the caller. Thus, a function that may resize a flexible array member, must receive a pointer to a pointer to the structure with a flexible array member.
If the function only examines the contents of a structure with a flexible array member, say counts the number of elements that fulfill some criteria, then a pointer to the structure suffices; and both the pointer and the pointed-to data can be marked const. This might help the compiler produce better code. Furthermore, all the data accessed is linear in memory, which helps more complex processors manage caching more efficiently. (To do the same with an array having a pointer member, one would need to pass the pointer to the array, as well as the size field at least, as parameters to the counting function, instead of a pointer to the structure containing those values.)
An unused/empty structure with a flexible array member can be represented by a NULL pointer (to such structure). This can be important when you have an array of arrays.
With structures with flexible array members, the outer array is just an array of pointers. With structures with pointer members, the outer array can be either an array of structures, or an array of pointers to structures.
Both can support different types of sub-arrays, if the structures have a common type tag as the first member, and you use an union of those structures. (What 'use' means in this context, is unfortunately debatable. Some claim you need to access the array via the union, I claim the visibility of such an union is sufficient because anything else will break a huge amount of existing POSIX C code; basically all server-side C code using sockets.)
Those are the major ones I can think of right now. Both forms are ubiquitous in my own code, and I have had no issues with either. (In particular, I prefer using a structure free helper function that poisons the structure to help detect use-after-free bugs in early testing; and my programs do not often have any memory-related issues.)
I will edit the above list, if I find I've missed important facets. Therefore, if you have a suggestion or think I've overlooked something above, please let me know in a comment, so I can verify and edit as appropriate.
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
I'm not really a fan of C, but I did homework for this exercise though. So far, what I got is that in C, initializing an array, as far as I know, is not like JavaScript. C has fixed arrays, and not initialized by a particular value. So NULL checking won't work in this case.
I have an array of structures. How would I know if that index in an array is empty or not (filled with a struct or not)?
#define LIST_LENGTH 30
//This is the struct that is inserted in the array
typedef struct node{
char fName[30];
char mName[30];
char lName[30];
char id[8];
} NODE;
typedef struct {
int size; //size is the struct's total capacity (at 30)
int length; //tracks how many elements are added, but not where
NODE nodes[LIST_LENGTH]; //This is the array in question
} List;
//somewhere in my code, I have to insert a value to the array at a specific position.
//if that position is occupied, I have to find the nearest empty position
//to the right, and shift the values rightward for that spot to be empty
Also, we are constrained to using arrays for this exercise. If we were granted to use linked-lists, this would be a walk in the park since we already know how to use dynamic lists.
How do I go about it? Or am I looking at the problem at the wrong angle (besides having to use arrays instead of linked-lists)?
One option would be to use some kind of sentinel value in your struct. For example, you could check if the id field is zero length, which would indicate an unoccupied spot in the array.
The downside is that you have to initialize all the elements properly when you create the array. You would also have to reset the sentinel value if you "remove" an element from the array.
As mentioned in one of the other answers, you could also change to have an array of pointers to the structures, in which case you could directly check for NULL.
Arrays in C do not have positions that are empty. If the array exists, all the elements in it exist.
An element might not be initialized, but there is no general way to determine that, except by tracking it yourself in your program. E.g., as soon as the array is allocated, initialize everything in it. Or maintain a number N indicating that the first N elements of the array have been initialized.
If you want to know whether each individual element has been initialized or not, you must maintain that information yourself, either in a separate array or by adding a flag to the structure, so that each element has its own flag saying whether the rest of the structure in that element has been initialized. You will, of course, need to initialize these flags.
Add 'set/valid' field to your NODE typedef and each time you insert NODE into List just set 'set/valid' to one for example. This way you can always tell if this is valid array element etc.
I have an array of structures. How would I know if that index in an array is empty (not filled with a struct)?
What you can do is either add a flag to the structure, isInitialized, to store whether it has been filled or not
//This is the struct that is inserted in the array
typedef struct node{
char fName[30];
char mName[30];
char lName[30];
char id[8];
int isInitialized;
} NODE;
and initialize all its instances within the array to 0.
Or you can initialize the structure with an illegal or "useless" value (e.g. all strings to length zero, or a special ID).
int isInitialized(NODE *s)
{
/* Since C strings are zero-terminated, char id[8] is at most one
seven-char string terminated by a binary zero. It can never be
normally a sequence of eight 0xFF. */
return memcmp(s->id, 0xFF, 8);
}
// You still have to manually mark nodes free at the beginning.
void initialize(NODE *s)
{
memset(s->id, 0xFF, 8);
}
if (isInitialized(&(myList->nodes[15])))
{
...
}
One caveat to the above code is that now "id" can not safely be taken and printed: an initialization check must be performed, otherwise printf() could fail to find the terminating zero and proceed onwards, and in the case of the last structure, maybe exceed the boundaries of accessible memory and determine a protection fault crash. One could reason, however, that since it does not make sense to print an uninitialized structure (where the saving binary zero could have been lacking anyway), such a check would have had to be performed regardless.
Or you could keep a counter of how many structures have been used so far (this assumes that you never mark as available a structure "in the middle" of the array).
If you have an array of pointers to structures, then you will be able to store NULL in the pointers to not-yet-initialized structures (i.e., the pointer array is allocated, the structures it points to are not yet necessarily so); but here you preallocate the structures, so you have to do it differently.
I wonder why we can pass structure to C function by value, but we can never do the same with array (which is passed by address).
When I was learning C, they told me that arrays consume much stack, so it's not preferred to pass them by value.
But it seems that structures are often (if not always) larger than arrays and are more complex data structure, so this explanation makes no sense for me now !
Can anybody help with as much details as possible ?
In C, an array is always defined as a pointer to the first position of the array, so by definition, when you are passing an array to a function your are passing its memory address, hence its reference.
When you define a variable of type struct, you're allocating all the space in memory needed to to contain this struct, and if you make something like:
struct a, b;
...
a = b;
You are copying all the values from b to a, and in the same way, when you are passing it to a function, you are copying the values of the original struct to the stack. That's called passing a parameter by value.
It's true what you're stating in your question. A struct may be more complex than an array, but it's perfectly possible to pass it as value, and it may be inefficient, but the reason that you can't pass an array by value is because it is defined as a pointer by default.
I am wondering why I keep getting error: flexible array member not at end of struct error when I call malloc. I have a struct with a variable length array, and I keep getting this error.
The struct is,
typedef struct {
size_t N;
double data[];
int label[];
} s_col;
and the call to malloc is,
col = malloc(sizeof(s_col) + lc * (sizeof(double) + sizeof(int)));
Is this the correct call to malloc?
You can only have one flexible array member in a struct, and it must always be the last member of the struct. In other words, in this case you've gone wrong before you call malloc, to the point that there's really no way to call malloc correctly for this struct.
To do what you seem to want (arrays of the same number of data and label members), you could consider something like:
struct my_pair {
double data;
int label;
};
typedef struct {
size_t N;
struct my_pair data_label[];
};
Note that this is somewhat different though: instead of an array of doubles followed by an array of ints, it gives you an array of one double followed by one int, then the next double, next int, and so on. Whether this is close enough to the same or not will depend on how you're using the data (e.g., for passing to an external function that expects a contiguous array, you'll probably have to do things differently).
Given a struct definition and a pointer to the start of a struct, it is necessary that the C compiler be able to access any member of the struct without having to access anything else. Since the location of each item within the structure is determined by the number and types of items preceding it, accessing any item requires that the number and types of all preceding items be known. In the particular case where the last item is an array, this poses no particular difficulty since accessing an item in an array requires knowing where it starts (which requires knowing the number and type of preceding items, rather than the number of items in the array itself), and the item index (which the compiler may assume to be smaller than the number of items for which space exists, without having to know anything about the array size). If a Flexible Array Member appeared anywhere other than at the end of a struct, though, the location of any items which followed it would depend upon the number of items in the array--something the compiler isn't going to know.
typedef struct {
size_t N;
double data[];
int label[];
} s_col;
You can't have
flexible array member (double data[]) in the middle. Consider hardcoded array size or double *data