What is the difference between initializing struct in following ways in C? - c

I am learning c. I have an struct that looks like below. I see 2 different ways of initializing the struct variable. It would be great, if someone could explain what is the difference between these 2 ways & which one is preferred in which case.
typedef struct {
int length;
int* elements;
} Array;
Array create_array_type_one(int size) {
Array result;
result.length = 0;
result.elements = (int *)malloc(size * sizeof(int));
return result;
}
Array* create_array_type_two(int size) {
Array *array = (Array *) malloc(sizeof(Array));
array->length = 0;
array->elements = (int *) malloc(sizeof(int) * size);
return array;
}

So, here we are talking about STRUCTURES & FUNCTIONS.
Basically there are three methods by which invoker and invoked structure function can communicate to each other.
Passing each member of the structure as an actual argument of the function call, or returning to the each member type.
Sending the copy of the structure to the entire called function or returning to the struct type (call by value).
Using pointers, pass the structure as an argument and indirectly work on the original structure or returning the address of the struct (call by reference).
Your, CASE 1:
Array create_array_type_one(int size) {
Array result;
result.length = 0;
result.elements = (int *)malloc(size * sizeof(int));
return result;
}
In this case you are returning a copy of the entire structure to the calling function. So, in order to use it in your main() function, you should do something like this:
Array new;
new = create_array_type_one(5);
Here, you are assigning the returned structure of type Array to a structure of type Array.
In CASE 2:
Array* create_array_type_two(int size) {
Array *array = (Array *) malloc(sizeof(Array));
array->length = 0;
array->elements = (int *) malloc(sizeof(int) * size);
return array;
}
In this case you are using pointers and returning a pointer to the newly created data structure of type Array. You are not sending a copy of the structure to the calling function instead you are sending its address to the calling function. Therefore, what happening in the main() while calling like this is:
Array *ptr;
ptr = create_array_type_two(5);
Both cases has there own advantages and disadvantages like CASE 1 ensures data safety as all the work done by the called function happens on a copy but uses extra memory. Where CASE 2 is more efficient and faster as compared to the previous method, as it uses same memory location for the operation.

The difference of them is the return type.
create_array_type_one() returns Array type memory location.
create_array_type_two() returns a pointer to Array type memory location.
As Array type has only two elements, int and int *, the size difference between two of them is not big . So you can use anyone for your coding preference in this case.
I'd like to recommend you the second one if the size of structure is kind of big...

Related

Is there a way to create a dynamic type assignment in C

I am working to create a set of functions in C that will allow a dynamically growing array. In this example I have create a struct with a variable titled len that stores the active length of the array, another variable titled size that stores the total length of the array assigned during initialization, and another variable titled array which is a pointer to the memory containing the array data. In this example the variable array is initialized in the struct as an integer. Within the function titled int_array I initialize the array and and return the struct. Within that function I call the init_int_array function that does the heavy lifting. In addition, I have another function titled append_int_array that checks the memory allocation and assigns another chunk of memory if necessary and then appends the array with a new index/variable. As you can see, this example is hard coded for an integer, and I will need to repeat these lines of code for every other data type if I want an array to contain that type of data. There has got to be a way to instantiate the struct so that the variable array can be a different data type so that I do not have to repeat all lines of code for every data type, but I am not sure what that method is. Any help would be appreciated. The code is shown below. NOTE: I also have a function to free the array memory after use, but I am omitting it since it is not relevant to the question.
array.h
#ifndef ARRAY_H
#define ARRAY_H
#include<stdlib.h>
#include<stdio.h>
typedef struc
{
int *array;
size_t len;
size_t size;
}Array;
void init_int_array(Array, size_t num_indices);
Array int_array(size_t num_indices);
void append_int_array(Array *array, int item);
#endif /* ARRAY_H */
Array.c
void init_int_array(Array *array, size_t num_indices) {
/* This function initializes the array with a guess for
the total array size (i.e. num_indices)
*/
int *int_pointer;
int_pointer = (int *)malloc(num_indices * sizeof(int));
if (int_pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
free(int_pointer);
exit(0);
}
else {
array->array = int_pointer;
array->len = 0;
array->size = num_indices;
}
}
Array int_array(size_t num_indices) {
/* This function calls init_int_array to initialize
the array and returns a struct containing the array
*/
Array array;
init_int_array(&array, num_indices);
return array;
}
void append_int_array(Array *array, int item) {
/* This function adds a data point/index to the array
and also doubles the memory allocation if necessary
to incorporate the new data point.
*/
array->len++;
if (array->len == array->size){
array->size *= 2;
int *int_pointer;
int_pointer = (int *)realloc(array->array, array->size * sizeof(int));
if (int_pointer == NULL) {
printf("Unable to reallocate memory, exiting.\n");
free(int_pointer);
exit(0);
}
else {
array->array = int_pointer;
array->array[array->len - 1] = item;
}
}
else
array->array[array->len - 1] = item;
}
A simple solution is rewrite your header like this:
typedef struct
{
void *array; // buffer
size_t len; // amount used
size_t elem; // size of element
size_t size; // size of buffer
} Array;
void init_array(Array *, size_t num_indices, size_t elem);
Array array(size_t num_indices, size_t elem);
void append_array(Array *array, void *item);
The changes to your code would be as follows:
Remove references to int in the name.
Make all inputs be to arbitrary type using void *.
Use array.elem instead of sizeof(int).
The biggest change is that elements to append will be passed by pointer, not by value.
Cast the buffer to whatever type you need to access elements.
Cast the buffer to char * internally to do pointer math on it.
Here is a sample calling sequence you could use:
Array buf = array(10, sizeof(int));
for(int i = 0; i < 3; i++) {
append_array(&buf, &i); // Remember that buf knows sizeof(int)
}
printf("Second element (of %d) is %d\n", buf->len, ((int *)buf->array)[1]);
C is a strongly- and statically-typed language without polymorphism, so in fact no, there is no language-supported form of dynamic typing. Every object you declare, every function parameter, every struct and union member, every array element has a specific type declared in your source code.
Some of the things you can do:
use a typedef or a preprocessor macro to provide indirection of the data type in question. That would allow you to have (lexically) one structure type and one set of support functions that provide for your dynamically-adjustable array to have any one element type of the user's choice, per program.
use preprocessor macros to template the structure type and support functions so that users can get separate versions for any and all element types they want. This might be usefully combined with _Generic selection.
define and use a union type for use as the array's element type, allowing use of any of the union's members' types. With a little more work, this can be made a tagged union, so that objects of different types in the same array could be supported. The cost, however, is wasted space and worse memory efficiency when you use members having smaller types.
use void * or maybe uintmax_t or unsigned char[some_largish_number] as the element type, and implement conversions to and from that type. This has some of the disadvantages of the union alternative, plus some complications surrounding the needed conversions. Also, there is no type that can be guaranteed large enough to accommodate all other data types. Nor even all built-in data types, though this is a more realistic goal.
use void as the formal element type (possible only with dynamic allocation and pointers, not with an array-style declaration). Add a separate member that recoirds the actual size of the elements. Implement wrappers / conversions that support use of that underlying structure in conjunction with various complete data types. This is described in more detail in another answer.

Writing to array of pointers in C

I need to write the pointer address of a struct (struct is called "Post") that has reposted another Post. There's a fixed return type called result with the following declaration:
struct result {
void** elements;
size_t n_elements;
};
For the Post struct, it has the following declaration:
struct post {
uint64_t pst_id;
uint64_t timestamp;
size_t* reposted_idxs;
size_t n_reposted;
};
Here's my code:
result* find_all_reposts(post* posts, size_t count, uint64_t post_id, query_helper* helper) {
result * ret_result = (result *) malloc(sizeof(result));
ret_result->elements[100];
ret_result->n_elements = 0;
for(int i = 0; i < count; i++){
post * temp = &posts[i];
size_t total_reposted = temp->n_reposted;
if(total_reposted > 0){
for(int q = 0; q < total_reposted; q++){
int index_of_repost = temp->reposted_idxs[q];
ret_result->elements[q] = &posts[index_of_repost];
ret_result->n_elements++;
}
}
}
return ret_result;
}
However I get a SEGV error for ret_result->elements[q] = &posts[index_of_repost];. I thought it could be originally that I hadn't initialised the elements field in the ret_result struct but I receive warning: statement with no effect for that:
warning: statement with no effect [-Wunused-value]- ret_result->elements[100];
I'm thinking that the void ** type for the elements field in result might be messing me around. From what I understand that's a pointer to a pointer which can obviously be an array and hence is basically a pointer to an array of posts?
I should clarify that count is the number of posts and that the returned-result is managed separately and hence any heap-allocated memory is freed in a separate process.
Thanks for your help :)
You haven't initialized ret_result->elements to anything. The statement ret_result->elements[100] is a no-op, the only reason you're not segfaulting there too is because your compiler is cutting it out. If you want that field to be a pointer to an array of size 100 you must initialize it with malloc. I'm not sure why you're declaring it to be a void ** double pointer here, but if it must be that way then something like this might work:
ret_result->elements = malloc(100 * sizeof(struct post *));
The call's arguments could also be 100 * sizeof(void *), but it might be a little what you intend to store there if you specify the struct to which the data will be pointing.

How to return a char** in C

I've been trying for a while now and I can not seem to get this working:
char** fetch (char *lat, char*lon){
char emps[10][50];
//char** array = emps;
int cnt = -1;
while (row = mysql_fetch_row(result))
{
char emp_det[3][20];
char temp_emp[50] = "";
for (int i = 0; i < 4; i++){
strcpy(emp_det[i], row[i]);
}
if ( (strncmp(emp_det[1], lat, 7) == 0) && (strncmp(emp_det[2], lon, 8) == 0) ) {
cnt++;
for (int i = 0; i < 4; i++){
strcat(temp_emp, emp_det[i]);
if(i < 3) {
strcat(temp_emp, " ");
}
}
strcpy(emps[cnt], temp_emp);
}
}
}
mysql_free_result(result);
mysql_close(connection);
return array;
Yes, I know array = emps is commented out, but without it commented, it tells me that the pointer types are incompatible. This, in case I forgot to mention, is in a char** type function and I want it to return emps[10][50] or the next best thing. How can I go about doing that? Thank you!
An array expression of type T [N][M] does not decay to T ** - it decays to type T (*)[M] (pointer to M-element array).
Secondly, you're trying to return the address of an array that's local to the function; once the function exits, the emps array no longer exists, and any pointer to it becomes invalid.
You'd probably be better off passing the target array as a parameter to the function and have the function write to it, rather than creating a new array within the function and returning it. You could dynamically allocate the array, but then you're doing a memory management dance, and the best way to avoid problems with memory management is to avoid doing memory management.
So your function definition would look like
void fetch( char *lat, char *lon, char emps[][50], size_t rows ) { ... }
and your function call would look like
char my_emps[10][50];
...
fetch( &lat, &lon, my_emps, 10 );
What you're attempting won't work, even if you attempt to cast, because you'll be returning the address of a local variable. When the function returns, that variable goes out of scope and the memory it was using is no longer valid. Attempting to dereference that address will result in undefined behavior.
What you need is to use dynamic memory allocation to create the data structure you want to return:
char **emps;
emps = malloc(10 * sizeof(char *));
for (int i=0; i<10; i++) {
emps[i] = malloc(50);
}
....
return emps;
The calling function will need to free the memory created by this function. It also needs to know how many allocations were done so it knows how many times to call free.
If you found a way to cast char emps[10][50]; into a char * or char **
you wouldn't be able to properly map the data (dimensions, etc). multi-dimensional char arrays are not char **. They're just contiguous memory with index calculation. Better fit to a char * BTW
but the biggest problem would be that emps would go out of scope, and the auto memory would be reallocated to some other variable, destroying the data.
There's a way to do it, though, if your dimensions are really fixed:
You can create a function that takes a char[10][50] as an in/out parameter (you cannot return an array, not allowed by the compiler, you could return a struct containing an array, but that wouldn't be efficient)
Example:
void myfunc(char emp[10][50])
{
emp[4][5] = 'a'; // update emp in the function
}
int main()
{
char x[10][50];
myfunc(x);
// ...
}
The main program is responsible of the memory of x which is passed as modifiable to myfunc routine: it is safe and fast (no memory copy)
Good practice: define a type like this typedef char matrix10_50[10][50]; it makes declarations more logical.
The main drawback here is that dimensions are fixed. If you want to use myfunc for another dimension set, you have to copy/paste it or use macros to define both (like a poor man's template).
EDITa fine comment suggests that some compilers support variable array size.
So you could pass dimensions alongside your unconstrained array:
void myfunc(int rows, int cols, char emp[rows][cols])
Tested, works with gcc 4.9 (probably on earlier versions too) only on C code, not C++ and not in .cpp files containing plain C (but still beats cumbersome malloc/free calls)
In order to understand why you can't do that, you need to understand how matrices work in C.
A matrix, let's say your char emps[10][50] is a continuous block of storage capable of storing 10*50=500 chars (imagine an array of 500 elements). When you access emps[i][j], it accesses the element at index 50*i + j in that "array" (pick a piece of paper and a pen to understand why). The problem is that the 50 in that formula is the number of columns in the matrix, which is known at the compile time from the data type itself. When you have a char** the compiler has no way of knowing how to access a random element in the matrix.
A way of building the matrix such that it is a char** is to create an array of pointers to char and then allocate each of those pointers:
char **emps = malloc(10 * sizeof(char*)); // create an array of 10 pointers to char
for (int i = 0; i < 10; i++)
emps[i] = malloc(50 * sizeof(char)); // create 10 arrays of 50 chars each
The point is, you can't convert a matrix to a double pointer in a similar way you convert an array to a pointer.
Another problem: Returning a 2D matrix as 'char**' is only meaningful if the matrix is implemented using an array of pointers, each pointer pointing to an array of characters. As explained previously, a 2D matrix in C is just a flat array of characters. The most you can return is a pointer to the [0][0] entry, a 'char*'. There's a mismatch in the number of indirections.

How to append to a pointer array in c

I have an array of pointers to structs and I'm trying to find a way to fill the first NULL pointer in an array with a new pointer to a struct. i.e. I want to add a new element onto the end of an array.
I tried a for loop like this:
struct **structs;
int i;
for(i = 0; i < no_of_pointers; i++) {
if (structs[i] == NULL) {
structs[i] = &struct;
}
}
In theory, this would go through the array and when it finds a null pointer it would initialise it. I realise now that it would initialise all null pointers, not just the first, but when I run it it doesn't even do that. I've tried a while loop with the condition while(structs[i] != NULL) and that just goes on forever, making me think that the issue is with how I'm using NULL.
What is the correct way to add a new element to an array of this kind?
Is there some function like append(structs, struct) that I don't know of?
Thanks!
The length of an array in C is fixed, you cannot change it after you defined an array, which means you cannot add an element to the end of an array. However, unless you defined a constant array, you could assign new values to elements of an array. According to your question description, I believe this is what you want.
Also note that, as other already pointed it out in comments, struct is a keyword of C, therefore
you cannot use it as a type name (as you did in struct **structs)
you also cannot use it as a variable name (as you did in structs[i] = &struct;)
Here is one way to do it:
define an array properly
struct struct_foo **structp;
structp = malloc (no_of_elements * sizeof(*structp));
if (structp == NULL) {
/* error handle */
}
Note, at here the elements of structp is not initialized, you need to initialize them properly. That is what we are going to do in step 2.
do something with structp, maybe initialize all its elements to NULL or some no-NULL value
find the first no-NULL element in structp, and assign it a new value
struct struct_foo foo;
for (i = 0; i < no_of_elements; i++) {
if (structp[i] == NULL) {
structp[i] = &foo;
break;
}
}
Note that this foo also is uninitialized, you may want to initialize it first, or you could initialize it later.
According to man malloc:
void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
void *reallocarray(void *ptr, size_t nmemb, size_t size);
...
The reallocarray() function changes the size of the memory block
pointed to by ptr to be large enough for an array of nmemb elements,
each of which is size bytes. It is equivalent to the call
realloc(ptr, nmemb * size);
Try implementing a system like this
struct **structs;
int new_struct() {
static int i = 0; // index of last allocated struct
i++;
struct *structp = malloc(sizeof(struct)); // new structure
// initialize structp here
reallocarray(structs, i, sizeof(struct));
structs[i] = structp;
return i; // use structs[index] to get
}
Then you may invoke new_struct(), which resizes the structs array and appends structp to it. The important part is that
a) create_struct returns the index of the newly created struct, and
b) it stores a static int i, which keeps track of the size of the structs.

How can I make a pool with pointers in C?

I'm making my library, and just when I thought understanding the pointers syntax, I just get confused, search on the web and get even more confused.
Basically I want to make a pool, here is what I actually want to do:
the following points must be respected :
when I add an object to the pool, the pointers of the current array to the objects are
added to a new array of pointers + 1 (to contain the new object).
the new array is pointed by "objects" of my foo structure.
the old array is free'ing.
when I call the cleanup function, all the object in the pool are
free'd
How should I define my structure ?
typedef struct {
int n;
(???)objects
} foo;
foo *the_pool;
here's the code to manage my pool :
void myc_pool_init ()
{
the_pool = (???)malloc(sizeof(???));
the_pool->n = 0;
the_pool->objects = NULL;
}
void myc_push_in_pool (void* object)
{
if (object != NULL) {
int i;
(???)new_pointers;
the_pool->n++;
new_pointers = (???)malloc(sizeof(???)*the_pool->n);
for (i = 0; i < the_pool->n - 1; ++i) {
new_pointers[i] = (the_pool->objects)[i]; // that doesn't work (as I'm not sure how to handle it)
}
new_array[i] = object;
free(the_pool->objects);
the_pool->objects = new_array; // that must be wrong
}
}
void myc_pool_cleanup ()
{
int i;
for (i = 0; i < the_pool->n; ++i)
free((the_pool->objects)[i]); // as in myc_push_in_pool, it doesn't work
free(the_pool->objects);
free(the_pool);
}
Note: the type of objects added to the pool are not known in advance, so i should handles all pointers as void
any feedback would be very welcomed.
A straight answer to your question would be: use void *. This type is very powerful as it allows you to put any kind of pointer in your pool. However, it's up to you to do the correct casts when retrieving a void * pointer from your pool.
Your struct would look like this
typedef struct {
int n;
(void **)objects
} foo;
foo *the_pool;
As in, an array of pointers.
Your malloc:
new_pointers = (void **)malloc(sizeof(void *)*the_pool->n);
There is an performance issue here. You could simply allocate an array of a fixed size, and only reallocate if the number of elements exceeds a predefined load factor (= number used/ max size)
Also, instead of allocating a new pointer each time you add something to your pool, you could just use realloc (http://www.cplusplus.com/reference/cstdlib/realloc/)
the_pool->objects = (void **)realloc(the_pool->objects, the_pool->n* sizeof(void*));
Realloc tries to increase the current allocated area, without the need to copy everything. Only if the function cannot increase the allocated area contiguously will it allocate a new area and copy everything.
Firstly, you already answered your "What should the type of foo.objects be?" question: void *objects;, malloc already returns void *. Your struct needs to store the size_t item_size;, too. n should probably also be a size_t.
typedef struct {
size_t item_count;
size_t item_size;
void *objects;
} foo;
foo *the_pool;
You could use a home-grown loop, but I'd consider memcpy to be a more convenient way to copy your old items to your new space, and the new item to it's new space.
Dereferencing a void * is a constraint violation, as is pointer arithmetic on a void *, so new_pointers will need to be a different type. You need a type that points to objects of the right size. You could use an array of the right number of unsigned char, like so:
// new_pointers is a pointer to array of the_pool->item_size unsigned chars.
unsigned char (*new_pointers)[the_pool->item_size] = malloc(the_pool->item_count * sizeof *new_pointers);
// copy the old items
memcpy(new_pointers, the_pool->objects, the_pool->item_count * sizeof *new_pointers);
// copy the new items
memcpy(new_pointers + the_pool->item_count, object, sizeof *new_pointers);
Remember, free() is only for pointers returned by malloc(), and there should be a one-to-one correspondence: Each malloc() should be free()d. Look how you malloc: new_pointers = malloc(sizeof(???)*the_pool->n); ... What makes you think you need a loop (in myc_pool_cleanup) to free each item, when you can free them all in one foul swoop?
You could use realloc, but you otherwise seem to be handling malloc/memcpy/free *in myc_push_in_pool* flawlessly. Lots of people tend to mess up when writing realloc code.

Resources