Is void** portable C? - c

I want to implement a generic growing array and use this struct for it:
struct dynamic_array
{
void** data;
size_t length;
size_t capacity;
};
Because void* doesn't allow arithmetic, I wanted to know if a void* array allows it, since it is a pointer to a void*. If that doesn't work, I'd like to know how else I could implement a generic array.
Edit: Since not everyone knows what I want to do with it, here's a code snippet how I could use the array:
for(size_t i = 0; i < array->length; i++)
{
if(strcmp((char*)array->data[i], some_string) == 0)
{
break;
}
}
Of course it's not only going to be char* but struct* too, and I know I have to cast them, but void* should allow casting back and forth without data loss, right?

Yes, this works. A pointer to void (void *) is a perfectly valid data object, so you can have an array of pointers to void, and access elements in that array in the normal way.
An example code snippet:
int i;
char c;
float f;
struct dynamic_array a;
a.capacity = 1024;
a.data = malloc(a.capacity * sizeof(void*));
a.data[0] = &i;
a.data[1] = &c;
a.data[2] = &f;
a.length = 3;
As Lee Daniel Crocker wrote, void * doesn't allow pointer arithmetic because the compiler doesn't know what it's pointing to. But void ** does, because we know exactly what it points to: pointers.

Related

C: Array of memory addresses?

I'm trying to make a sort of container for multiple different structs. Unfortunately C only allows type specific arrays, meaning I'd have to make a different array for each type of struct.
The current solution I came up with is a container that holds memory addresses. This way the program can just pass the memory address of one of the elements to a function.
Currently the only code I have is a failed attempt using void pointers (not really familiar with pointers and memory addresses yet unfortunately)
The following is my test code I was writing to try and understand how this stuff works:
void* arr[10]={};
int len=0;
int n[5]={1,2,3,4,5};
for (int i=0;i<5;i++) { //add pointers nums in n to arr
arr[i]=(void*)(&n[i]);
len++;
}
for (int i=0;i<len;i++) { //print contents of arr
printf("%p\n", (void*)arr[i]);
printf("\t%d\n", arr[i]); //trying to print actual value (eg. 2 for index 2) but not really sure how to...
}
Thanks!
Your approach is correct but there is some stuff missing...
In C any object pointer can be converted to a void-pointer and back to a pointer of the original type. So an int-pointer can be converted to a void-pointer an back to an int-pointer. And a float-pointer can be converted to a void-pointer an back to an float-pointer.
So using an array of void-pointers to store pointers to different object types is a fine approach.
But... in order to convert the void-pointer back to the original type, you need to know what the original type was. If you just saves the void-pointer, you don't have that information.
Instead consider something like:
struct gp
{
void* p;
unsigned type_tag;
}
#define INT_TYPE 0
#define FLOAT_TYPE 1
and use it like:
struct gp arr[2];
int n = 42;
float f = 42.42;
arr[0].p = &n;
arr[0].type_tag = INT_TYPE;
arr[1].p = &f;
arr[1].type_tag = FLOAT_TYPE;
for (int i=0; i < 2; ++i)
{
if (arr[i].type_tag == INT_TYPE)
{
int* p = (int*)arr[i].p; // Cast void-pointer back to int-pointer
printf("%d\n", *p); // Get int-value using *p, i.e. dereference the pointer
}
else if (arr[i].type_tag == FLOAT_TYPE)
{
int* p = (float*)arr[i].p; // Cast void-pointer back to float-pointer
printf("%f\n", *p); // Get float-value using *p, i.e. dereference the pointer
}
}
You need to derefence the pointer stored in the array. You also need to cast it to the original type of the referenced objects.
printf("\t%d\n", *(int *)arr[i]);

How to get struct address inside array of structs?

I'm trying to get struct's address.
I want to get address in an int *, and I want to change address by adding numbers to the int *. I tried several ways, but I can't solve it.
struct num_d {
unsigned char data;
unsigned char pad1;
unsigned char pad2;
unsigned char pad3;
};
struct num_d **m = malloc(sizeof(struct num_d *) * row);
for (int i = 0; i < row; i++)
{
m[i] = malloc(sizeof(struct num_d) * col);
}
How can I get m[0][0]'s address in an int *?
first things first lets typedef your struct, so we can type less and be more clear:
typedef struct num_d num_d;
void pointer
A pointer to void is a "generic" pointer type. A void * can be converted to any other pointer type without an explicit cast. we cannot de-reference a void * or do pointer arithmetic with it; you must convert it to a complete data type pointer first (like int* e.g.) then do the de-refrence or the pointer arithmetic.
Now, malloc() return a void* which points to the allocated heap buffer (if malloc successed in allocation other wise null is the return value).
you code become:
num_d** m = malloc(sizeof(num_d*) * row); /*m is an array of void* pointers (not initialized)*/
for (int i = 0; i < row; i++)
{
m[i] = malloc(sizeof(num_d) * col); /*in each element in m you have a void* that points to struct num_d on the heap*/
}
the sizeof(void*) is the same as sizeof any pointer (except function pointers in some machines/os).
putting it all together
How can I get m[0][0]'s address in an int *?
This is a wrong question! because m is an array of void* to "num_d structs" (holding the num_d heap address).
if you want the start address of the i-th num_d struct in the array m, then, just return the void* in the index i in this array m[i]. and if you want to cast it just cast it (no need actually) just assign it:
int* ptr = m[i];
Take in mind that compilers will warn you, regarding the assignment above (but this assignment is supported and legal) :
warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
or (no need again):
int* ptr = (int*)m[i];
I don't know why you need such behavior, it makes more sense to cast to num_d*
if you want the address of the first data member in the struct num_d, then you must cast to the appropriate data type to get the expected data:
unsigned char data = ((num_d*)m[i])->data;
unsigned char* p_data = &((num_d*)m[i])->data;
You don't need to have the address in an int* in order to be adding to it. The way that [] works, is that it adds to the pointer and dereferences.
You can just add to *(m[0] + 1) to get the second element.
How about:
int *ptr = (int *) m[0];

C function declaration returning pointer to specific sized array

I have been playing around with C function declarations/definitions and came up with these.
Is there a reason why g1 would be preferred over g2, other than wanting to return a pointer to a specific sized array?
Is there a better way to write g1 (with typedefs? etc.)?
#include <stdlib.h>
char (*g1(int dummy))[10]
{
char (*p)[10] = malloc(sizeof *p);
return p;
}
char * g2(int dummy)
{
char (*p)[10] = malloc(sizeof *p);
return (void *)p;
}
int main()
{
g1(10);
g2(20);
}
Thanks in advance.
From what I can tell, g1 returns a pointer to an array of char containing exactly 10 elements, whereas g2 returns a pointer to a single char, which would allow for a char array of any length following it in memory.
Seeing as C will not enforce the bounds of an array, the only advantage I can see with g1 over g2 is the ability to specify a size when assigning a variable, just as you have mentioned.
If you wanted to rewrite g1 using a typedef, you could use the following:
typedef char (*char_array_t)[10];
char_array_t g1(int dummy)
{
char_array_t p = malloc(sizeof *p);
return p;
}
g1 is more "correct" since it accurately reflects the type of the object you are returning (pointer to 10-element array of char). You don't normally see functions that return pointers to arrays, since the array size must be fixed at compile time, limiting its usefulness, and most of us subconsciously avoid writing code like that because it's just too damned eye-stabby. If I were writing a function that allocated a 2D array, I'd usually write it as
void g1( size_t rows, size_t cols, char (**p)[cols] )
{
*p = malloc( sizeof **p * rows );
}
int main( void )
{
char (*table)[10];
g1( 5, 10, &table );
if ( table )
{
...
}
}
which allows me to take advantage of VLA semantics (in C99 or later), making it flexible without being excessively ugly.
You can typedef some of the ugliness away:
typedef char MyType[10];
MyType *g1( int dummy );
{
MyType *p = malloc( sizeof *p );
...
return p;
}
but I'm leary of using typedefs just to make the code scan better. You should only typedef a type for abstraction purposes (i.e., to hide the implementation from the user of the type). If the user of the type needs to be aware of the "array-ness" of the type, then do not hide it behind a typedef.
I don't like g2 because it lies. p is not a char *, it's a char (*)[10]. That matters.
Is there a better way to write?
If the function needs to return "a pointer to an array of size 10 chars" then g1() is fine. It meets the design goal.
char (*g1(int dummy))[10] {
char (*p)[10] = malloc(sizeof *p);
return p;
}
If the function needs to return "a pointer to 10 chars" then use
char *allocate10char(int dummy) {
char *p = malloc(sizeof *p * 10);
return p;
}
If char (*g1(int dummy))[10] is too strange, then the coding goal needs to imporve.
`

C functions to create dynamic array of structs

can someone help with this piece of code? I leaved out check of allocations to keep it brief.
typedef struct {
int x;
int y;
} MYSTRUCT;
void init(MYSTRUCT **p_point);
void plusOne(MYSTRUCT **p_point, int *p_size);
int main()
{
MYSTRUCT *point;
int size = 1;
init(&point);
plusOne(&point, &size);
plusOne(&point, &size);
point[1]->x = 47; // this was the problem
point[1].x = 47; // this is solution
return 0;
}
void init(MYSTRUCT **p_point)
{
*p_point = (MYSTRUCT *) malloc( sizeof(MYSTRUCT) );
}
void plusOne(MYSTRUCT **p_point, int *p_size)
{
(*p_size)++;
*p_point = realloc(*p_point, *p_size * sizeof(MYSTRUCT) ); // also calling to the function is fixed
}
I don't understand why index notation doesn't work after calling to functions.
This is because you are not multiplying the p_size by sizeof(MYSTRUCT) in the call of realloc, and not assigning the results back to p_point:
*p_point = realloc(*p_point, *p_size * sizeof(MYSTRUCT));
Notes:
You do not need to cast the result of malloc or realloc in C.
For consistency, consider passing &size to init, and set it to 1 there.
You have some type confusion going on... Here:
MYSTRUCT *point;
you declare point to be a pointer to a MYSTRUCT structure (or an array of them).
The syntax point[i] is equivalent to *(point + i) - in other words, it already dereferences the pointer after the addition of the appropriate offset, yielding a MYSTRUCT object, not a pointer to one.
The syntax p->x is equivalent to (*p).x. In other words, it also expects p to be a pointer, which it dereferences, and then yields the requested field from the structure.
However, since point[i] is no longer a pointer to a MYSTRUCT, using -> on it is wrong. What you are looking for is point[i].x. You could alternatively use (point + i) -> x, but that's considerably less readable...

Memory error(I guess) - C - Pointer(using as array) in a struct

Here is my struct:
struct person{
int id;
char name[80];
int age;
char uni[80];
int *block;
int *friends;
int f_count;
int b_count;
};
Here is my function that gives error(Other functions are working correctly, I tested it, and the values passing to this function is correct, i tested it too.) This function giving this error (when running, no error while compiling): The instruction at 0xblabla referenced memory at 0xblabla. The memory could not be read.
void add_friend(struct person **p, int *p1, int *p2)
{
int *newf1 = NULL;
int *newf2 = NULL;
(*p)[*p1].f_count += 1;
newf1 = (int *)realloc((*p)[*p1].friends, ((*p)[*p1].f_count) * sizeof(int));
if (newf1 != NULL)
{
(*p)[*p1].friends = newf1;
(*p)[*p1].friends[((*p)[*p1].f_count) - 1] = *p2;
}
(*p)[*p2].f_count += 1;
newf2 = (int *)realloc((*p)[*p2].friends, (*p)[*p2].f_count * sizeof(int));
if (newf2 != NULL)
{
(*p)[*p2].friends = newf2;
(*p)[*p2].friends[((*p)[*p2].f_count) - 1] = *p1;
}
}
Update:
In response to your comment:
int main ( void )
{
int i=1, j=2;//local vars
struct person me;//a local, stack allocated, struct
void add_person(struct person *p, int p1, int p2);//prototype
//pass ADDRESS OF struct to function
add_person(&me, i, j);
return EXIT_SUCCESS;
}
void add_person(struct person *p, int p1, int p2)
{
p->some_int = p2;//changes the struct we declared in main
(*p).friends = newf2;//alt syntax: dereference pointer
}
Here, you see you have 2 ways of using a struct, either leave it as is, and use the indirection operator ->, or dereference it (*), and use direct access (.). Not all that hard, really...
For a better understanding, or at least a primer in pointers, I'd suggest this answer of mine, where I make an analogy between pointers, and a calendar. I've used this explanation to help a few people and all of them (up till now, no exception) found it quite helpful. It's a really simple way of thinking about pointers that isn't full proof (once you get into more complex stuff like decayed arrays of pointers to structs it doesn't quite stack up), but when learning, it should help you come to terms with the basics.
Ok, you have a pointer to a pointer. Great, so if you dereference that pointer, which you do (*p) you end up with a regular pointer to a struct. Great, but why would you then need the [*i], still? it's a pointer, not an array, unless [*i] is 0, you'll be accessing memory out of bounds, either write:
p[*i]->friends = newf2;//for example
or, if you want to make your life harder, still:
*(p+(*i)).friends = newf2;
That's just awful IMO, though...
Your approach (dereferencing + getting an index/offset) could perhaps work if you were to write this:
(*p)[0].friends = newf2;
But again, that's just making life difficult for yourself.
As is your passing pointers to ints to the function. Sure, sometimes you have to pass a pointer, but really, sending an int by copy isn't a lot of overhead:
void add_friend(struct person **p, int p1, int p2)
{//works fine
p[i]->friends = newf2;
}
//call like so:
struct person **pers_array = calloc(10, sizeof(*pers_array));//alloc memory for pointers
for (int i=0;i<10;++i) pers_array[i] = malloc(sizeof *pers_array[i]);//alloc struct
add_friend(pers_array, 1, 2);
And as ever, don't cast void * in C + every malloc and or calloc has to have a free that goes with it

Resources