How to get struct address inside array of structs? - c

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];

Related

Why is a double-void pointer required here? Dynamic "generic" array

I tried to implement a form of collections-library. I do it all the time, when learning a new language, because it teaches most of the language details.
So, I started with a form of "generic" dynamic array. Well it is not really generic, because it just holds pointers to the actual data.
But to be honest, I don't fully understand, why I need a double void pointer here.
The Vector struct defined in my header file (I declared every method and #include in the header file, but I omitted this here to keep the code readable. I also ommitted some bounds checks)
typedef struct {
size_t capacity; //the allocated capacity
size_t length; //the actual length
void **data; //here I don't fully understand, why I need a double pointer.
} Vector;
Here is my implementation of a few methods, where the compiler complains when I use a single void pointer in my struct, so void *data instead of void **data.
#include "utils.h"
const size_t INITIAL_SIZE = 16;
//Creates a new empty vector.
Vector *vec_new(void) {
printf("sizeof Vector is: %ld", sizeof(Vector));
Vector *vec = malloc(sizeof(Vector));
vec->length = 0;
vec->capacity = INITIAL_SIZE;
void *data = calloc(INITIAL_SIZE, sizeof(void*));
if(data == NULL) {
free(vec->data);
fprintf(stderr, "Error allocating memory.");
exit(EXIT_FAILURE);
}
vec->data = data;
return vec;
}
//This method appends the specified value at the end of the vector.
void vec_push(Vector *vec, void *data) {
if(vec->length == vec->capacity-1) {
vec_resize(vec);
}
vec->data[vec->length] = data;
vec->length += 1;
}
//gets the value at the specified index or NULL if index is out of bounds.
void *vec_get(Vector *vec, size_t index) {
return vec->data[index];
}
//Resizes the vector to 1.5x its current capacity.
void vec_resize(Vector *vec) {
vec->capacity *= 1.5;
void *data = realloc(vec->data, sizeof(void*) * vec->capacity);
if(data == NULL) {
free(vec->data);
fprintf(stderr, "Error allocating memory.");
exit(EXIT_FAILURE);
}
vec->data = data;
}
It seems like here is where the magic happens, which i do not yet understand:
void *data = malloc(...);
vec->data = data;
Malloc/calloc return a void pointer, so i either have to declare an actual type or just using the returned void pointer. So the first line is clear.
vec->data is, under the assumption I do not use a double pointer in the struct definition equivalent to (*vec).data as far as I understand it. So basically this line should assing a void pointer to a void pointer.
Can maybe someone explain it to me in simple terms, why exactly a single void pointer is not enough here or where I might misunderstand something.
But to be honest, I don't fully understand, why I need a double void pointer here.
Some background first - maybe you already know that:
A pointer of the type someType * is a pointer to some variable of the type someType or to an array of variables of the type someType.
A pointer of the type someType ** is a pointer to a variable of the type someType * - this means: A pointer to a pointer to a variable of the type someType.
A pointer of the type void * is a pointer to anything; because the compiler does not know to what kind of element this pointer points to, it is not possible to access such an element directly.
In contrast to this, it is known what variable a pointer of the type void ** points to: It points to a variable of the type void *.
Why you need void** in this position:
The key are the lines:
vec->data[vec->length] = data;
...
return vec->data[index];
In these lines, the code accesses the data vec->data points to. For this reason, vec->data cannot be void * but it must be xxx * while xxx is the type of data the pointer vec->data points to. And because vec->data points to a pointer of the type void *, xxx is void * so xxx * is void **.
vec->data = data;
Your observation is correct: vec->data is of the type void ** and data is of the type void *.
The reason is that malloc() returns some memory and the compiler does not know which kind of data is stored in this memory. So the value returned by malloc() is void * and not void **.
In the automotive industry, you would use an explicit pointer cast like this:
vec->data = (void **)data;
The expression (xxx *)y tells the compiler that the pointer y points to some data of the type xxx. So (void **) tells the compiler that the pointer points to an element of the type void *.
However, in desktop applications you often don't write the (void **).
If you have a pointer of the type
T *p1;
where T is some type specifier as for example void then pointer to this pointer will be declared like
T **p2 = &p1.
In this call of calloc
calloc(INITIAL_SIZE, sizeof(void*))
you are going to allocate an array of pointers of the type void *. The function returns a pointer to the first element of the allocated array. So you need to write
void **data = calloc(INITIAL_SIZE, sizeof(void*));
To make it more clear let's assume that you need to allocate dynamically an integer array. In this case you will write
int *data = calloc( INITIAL_SIZE, sizeof( int ) );
So dereferencing the pointer data like *data you will get an object of the type int more precisely the first element of the allocated array.
When elements of the array have the type void * then dereferencing the pointer data like *data you must to get a pointer of the type void * (the first element of the allocated array). So to make the operation correct the pointer data shall have the type void **.

How to access second member of struct via pointer?

I have seen the first address of struct is simultaneously the first address of first member of that struct. Now what I would like to understand is, why I need always double pointer to move around in the struct:
#include <stdio.h>
#include <stdlib.h>
struct foo
{
char *s;
char *q;
};
int main()
{
struct foo *p = malloc(sizeof(struct foo));
char ar[] = "abcd\n";
char ar2[] = "efgh\n";
*(char**)p = ar;
*(char**)((char**)p+1) = ar2; //here pointer arithmetic (char**)p+1
printf("%s\n",p->q);
}
the question is, why do I need char** instead of simple char*?
What I saw in assembler is in case of simple char*, the arithmetic would behave like normal char. That is -> the expression of (char*)p+1 would move the address p just by one byte (instead of 8 as address are 8 bytes long). But yet the type char* is address, so I don't get why the arithmetic behave like the dereference type instead (plain char -> one byte).
So the only solution for me was to add another indirection char**, where the pointer-arithmetic magically takes 8 as size. So why in structs is needed such bizarre conversion?
You are doing funny things. You should just do:
struct foo *p = malloc(sizeof(struct foo));
char ar[] = "abcd\n";
char ar2[] = "efgh\n";
p->s = ar;
p->q = ar2;
First of all, what you are doing is slightly bizarre. It's also unsafe, since there may be padding between struct members and your address calculation may be off (that's likely not true in this particular case, but it's something to keep in mind).
As to why you need multiple pointers...
The type of p is struct foo * - it's already a pointer type. Each of the members s and q have type char *. To access the s or q members, you need to dereference p:
(*p).s = ar; // char * == char *
(*p).q = ar2; // char * == char *
So if you're trying to access the first character pointed to by s through p, you're trying to access a character through a pointer (s) through another pointer (p). p does not store the address of the first character of s, it stores the address of the thing that stores the address of the first character of s. Hence the need to cast p to char ** instead of char *.
And at this point I must emphasize DON'T DO THIS. You can't safely iterate through struct members using a pointer.
The -> operator was introduced to make accessing struct members through a pointer a little less eye-stabby:
p->s = ar; // equivalent to (*p).s = ar
p->q = ar2; // equivalent to (*p).q = ar2
As the address of an object of a structure type is equal to the address of its first member then you could write for example
( void * )&p->s == ( void * )p
Here is a demonstrative program
#include <stdio.h>
#include <stdlib.h>
struct foo
{
char *s;
char *q;
};
int main(void)
{
struct foo *p = malloc(sizeof(struct foo));
printf( "( void * )p == ( void * )&p->s is %s\n",
( void * )p == ( void * )&p->s ? "true" : "false" );
return 0;
}
Its output is
true
So the value of the pointer p is equal to the address of the data member s.
In other words a pointer to the data member s is equal to the pointer p.
As the type of the data member s is char * then pointer to s has the type char **.
To assign the pointed object you need to cast the pointer p of the type struct foo * to the type char **. To access the pointed object that is the data member s you have to dereference the pointer of the type char **.
As a result you have
*(char**)p = ar;
Now the data member s (that is the pointer of the type char *) is assigned with the address of the first element of the array ar.
In the second expression the left most casting is redundant
*(char**)((char**)p+1) = ar2;
^^^^^^^^
because the expression (char**)p+1 is already has the type char **. So you could just write
*((char**)p+1) = ar2;
why do I need char** instead of simple char*
With pointer usage, the the left side of the assignment, code needs the address of the object.
*address_of_the_object = object
As the object is a char *, the type on the left side, the address of the object, needs to be type char **.
How to access second member of struct via pointer?
Better to instead use the sensible:
p->q = ar2;
... then the convoluted:
// |-- address of p->q as a char * ----|
*((char **) ((char *)p + offsetof(struct foo, q))) = ar2;
//|------------ address of p->q as a char ** ---|
OP's *(char**)((char**)p+1) = ar2; is amiss as it does the wrong pointer math and assumes no padding.
Convoluted approach details.
To portable find the offset within a struct, use offsetof(struct foo, q). It returns the byte offset and will accounts for potential padding. Add that to a char * version of the struct address to do the proper pointer addition to form the address of p->q. That sum is a char *, Convert to the type of the address of the object. Lastly de-reference it on the LHS as part of the assignment.

Is void** portable 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.

How do I cast this pointer

I have the following struct:
struct Map {
void* arr; // includes pointers to certain blocks of memory
int mem_block_count;
};
The void* arr holds pointers to certain cells in memory. Each cell holds a void* pointer to another cell in memory (as a linked list) a char* string, and a value with its own size.
You should be able to grab one of these pointers to a cell by doing arr[i] where i is an index - is this right?
I am trying to access the first pointer to one of these cells, which is probably arr[0]. Then, I want to get access to the pointer to the next cell in memory. But this is of void type. So how do I get at it? For getting access to the char*, I just move forward in memory, and then do a strcpy. But how do I get access/deref the next pointer?
EDIT: I also thought about casting the void pointer to an int, but I'm not sure I would get the right value. Something like:
int *next_pointer;
next_pointer = (int*) map->arr[i]
But is this not preserving the pointer to the pointer when I cast this as an int? How do I dereference a pointer to a pointer correctly?
EDIT - Couldn't I also, because it is a linked list of pointers, also do something like - map->arr + index * sizeof(void*) to get to the start of a given cell?
You can't use array indexing on a void pointer, as it really just a generic pointer without a type. And if there's no type then there's no way of adding the correct offset to the base memory address. You have to cast it to the correct structure before using array indexing:
((struct some_structure *) arr)[1]
You need pointers to pointers.
#include <stdio.h>
#include <stdlib.h>
struct Map {
void **arr; // includes pointers to certain blocks of memory
int mem_block_count;
};
int main(void) {
struct Map map = {0};
int a1[100];
double a2[100];
char a3[100];
map.arr = malloc(3 * sizeof *map.arr);
if (!map.arr) /* error */;
a1[42] = 42;
a2[42] = 42;
a3[42] = 42;
map.mem_block_count = 3;
map.arr[0] = a1;
map.arr[1] = a2;
map.arr[2] = a3;
printf("%d %f %c\n", ((int *)(map.arr[0]))[42],
((double *)(map.arr[1]))[42],
((char *)(map.arr[2]))[42]);
free(map.arr);
return 0;
}

C pointer "type ** name" versus "type * name[]" as argument

I had a bit of a confusion. Below is a very simple example which works:
#include <stdlib.h>
typedef struct
{
unsigned char one: 1;
unsigned char two:1;
unsigned char three: 1;
unsigned char four: 1;
} nibble_bits;
typedef union
{
unsigned char all : 4;
nibble_bits bits;
} nibble;
void initArr(nibble ** arrLoc, unsigned int size)
{
nibble * start = arrLoc[0];
int i =0;
for (i=0; i<size; i++)
{
start[i].all = 0;
}
}
int main()
{
nibble * fourNibbles = (nibble *) malloc(4 * sizeof(nibble));
initArr(&fourNibbles,4);
}
This compiles fine with no warnings. However, when I change the first line in main:
nibble * fourNibbles = (nibble *) malloc(4 * sizeof(nibble));
to:
nibble fourNibbles[4];
I get the following:
warning: main.c: In function ‘main’:
main.c:150: warning: passing argument 1 of ‘initArr’ from incompatible pointer type
Upon running, I get a "Bus error 10".
Seems to me like the lines are doing the same thing, except that the malloc is allocating space for the array on the heap and the array declaration is on the stack. But (I thought) either way "fourNibbles" is of type "pointer to nibble", and hence the address of "fourNibbles" would be pointer to pointer to nibble (nibble **).
What am I missing here?
These are not even remotely the same. This
nibble * fourNibbles = (nibble *) malloc(4 * sizeof(nibble));
declares a pointer fourNibbles, while this
nibble fourNibbles[4];
declares an array. Arrays and pointers are two completely different things, which (at object level) have nothing in common. Trying to use them interchangeably in object contexts (like & operator) will only lead to disaster. There lots of information on this topic here on SO (search for "array pointer difference") as well as in this [de-facto standard] C FAQ: http://c-faq.com/aryptr/index.html
There is another thing that draws attention in your code though. Your function
void initArr(nibble ** arrLoc, unsigned int size)
is specifically tailored to the first variant, since it requires a pointer to a pointer as its first argument. It will not work if you attempt to force a pointer to an array to the first argument (which you already had a chance to observe firsthand).
However, the real question here is why your initArr function is written in such a bizarre way. This sequence
void initArr(nibble ** arrLoc, unsigned int size)
{
...
nibble * start = arrLoc[0];
...
start[i].all = 0;
looks rather unusual. Why are you passing a pointer to a pointer instead of an ordinary single-level pointer? E.g. you could simply do
void initArr(nibble *start, unsigned size)
{
unsigned i;
for (i = 0; i < size; ++i)
start[i].all = 0;
}
This version would be called as
initArr(fourNibbles,4); /* note: no `&` operator */
and it would be compatible with both malloc-ed arrays and explicitly declared arrays.
P.S. In C language a better idiom for malloc is
nibble * fourNibbles = malloc(4 * sizeof *fourNibbles);
Note that in this variant type name nibble is mentioned only once.
You are missing that the address of an array has a different type from the pointer that the plain array name becomes when used in an expression.
That is:
int *a1 = ...;
int a2[] = { ... };
some_func(&a1);
some_func(&a2);
cannot be correct unless some_func() expects a void *. The first call passes an int ** — a pointer to pointer to int; the second call passes an int (*)[] — a pointer to array of int. Drop the & from the array.
However, in your code, the problems are more complex. Because the function expects a nibble **, you have problems. What you should be doing is passing a nibble *:
void initArr(nibble *arrLoc, unsigned int size)
{
for (unsigned int i = 0; i < size; i++)
start[i].all = 0;
}
int main(void)
{
nibble *fourNibbles_1 = (nibble *) malloc(4 * sizeof(nibble));
nibble fourNibbles_2[4];
initArr(fourNibbles_1, 4);
initArr(fourNubbles_2, 4);
initArr(&fourNubbles_2[0], 4);
}
Your actual code is doing some really rather weird stuff. How much damage it is doing may depend on how big a pointer is compared to a nibble.

Resources