I have the following code
#include <stdlib.h>
#include <stdio.h>
typedef struct {
int age;
} data;
int storage (data **str) {
*str = malloc(4 * sizeof(**str));
(*str)[0].age = 12;
return 0;
}
int main() {
data *variable = NULL;
storage(&variable);
return 0;
}
I took it from a website source. I think I have a misunderstanding about a basic pointer to pointer concept because here in this code, we have a pointer to a struct, variable, and we are passing this to storage function, which expects pointer to pointer of struct type. After memory was malloced, I don't understand this assignment
(*str)[0].age = 12
It was assigned as if, str was of (*)[] type. I dont understand how this assignment works, like str is now a pointer to an array of structs?
First, a note about C syntax for dereferencing pointers:
a[b] is equivalent to *(a + b), is equivalent to *(b + a), is equivalent to b[a].
Now, in
int main() {
data *variable = NULL;
storage(&variable);
return 0;
}
variable is of type "pointer to data", therefore its address &variable is of type "pointer to pointer to data". This is passed to int storage(data **str), and is the correct type for the argument str.
int storage (data **str) {
*str = malloc(4 * sizeof(**str));
(*str)[0].age = 12;
return 0;
}
Here, str is dereferenced, yielding an lvalue of type data * designating the same object as main()s variable. Since it is an lvalue, it can be assigned to.
malloc() allocates memory without declared type, large enough (and sufficiently aligned) to contain four contiguous objects of type data. It returns a pointer to the beginning of the allocation.
(*str)[0] is now an lvalue designating an object of type data, and by accessing the memory malloc() allocated through this expression, the effective type of the memory becomes data. (*str)[0].age = 12; assigns the value 12 to the age-member of this object, leaving the other members of the struct (and the rest of the allocated memory) uninitialized.
It can be illustrated like this
main:
data* variable = NULL; //variable is a pointer
storage(&variable) //the address of the pointer is &variable
the storage(data**) allows the function to take the address
of the pointer variable
this allows storage to change what variable points to
In storage, the following statement changes what variable points to by dereferencing (since we did pass the address of variable):
*str = malloc(4 * sizeof(**str) )
The malloc allocates a memory block containing four structs (which each has the size sizeof(struct data) bytes)
A struct is just a convenient way to access a part of memory, the
struct describes the layout of the memory. The statement
(*str)[0].age = 12;
is the equivalent of
data* d = *str;
d[0].age = 12;
or you can write it as a ptr with offset:
data* d = *str;
*(d + 0).age = 12;
edit: a clarification about malloc
malloc returns a block of memory allocated in bytes, the return type of malloc is void* so per definition it has no type and can be assigned to a pointer of arbitrary type:
T* ptr = malloc(n * sizeof(T));
After the assignment to ptr, the memory is treated as one or more elements of type T by using the pointer T*
Well, I think your code is simply identical to:
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
int age;
} data;
int main()
{
data *variable = NULL;
variable = malloc(4 * sizeof(*variable));
*(variable + 0).age = 12;
return 0;
}
So variable is malloced with a block of memory, which is large enough to hold 4 datas(from variable[0] to variable[3]). That's all.
This piece of code might help illustrate what's happening, the really interesting line is
assert(sizeof(**str2) == sizeof(data));
Your numbers may vary form mine but first lets create a struct with a rather dull but hard to fake size for testing purposes.
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct {
uint8_t age;
uint8_t here_as_illustartion_only[1728];
} data;
int main() {
data str;
data * str1 = &str;
data ** str2 = &str1;
printf("sizeof(str) =%*zu\n", 5, sizeof(str));
printf("sizeof(str1) =%*zu\n", 5, sizeof(str1));
printf("sizeof(str2) =%*zu\n", 5, sizeof(str2));
printf("sizeof(*str2) =%*zu\n", 5, sizeof(*str2));
printf("sizeof(**str2) =%*zu\n", 5, sizeof(**str2));
assert(sizeof(**str2) == sizeof(data));
return 0;
}
On my machine this prints the following
sizeof(str) = 1729
sizeof(str1) = 8
sizeof(str2) = 8
sizeof(*str2) = 8
sizeof(**str2) = 1729
Note the size of the pointer to pointer ie sizeof(**) is the dull number we're looking for.
Related
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.
I was hoping someone could help me figure out why one version of the below code works, while the other doesn't. Below I've included the initArray method, stored in "worksheet.c". The function is accessed in main, both versions are given below.
void initArray(struct dynArray *a) {
a->data = malloc(10 * TYPE_SIZE);
assert(a->data != 0);
a->size = 0;
a->capacity = 10;
}
This works. I create a dynArray struct and pass it to initArray by reference.
#include "worksheet0.h"
#include <stdio.h>
int main(void)
{
struct dynArray b;
initArray(&b);
return 0;
}
This fails with a seg fault. I thought that passing b here would be the same as passing the struct by reference.
int main(void)
{
struct dynArray *b = NULL;
initArray(b);
return 0;
}
Because in the second case there is no memory allocated to which the struct pointer points to. It is simply a pointer having the value NULL. On your case by dereferencing the value NULL you have invoked undefined behavior.
It would work if you allocate memory, make changes to it and then return it's value. [But then you have to return the address of the allocated memory.] OR you can pass the address of the pointer variable and allocate memory to which dereferenced pointer (here the pointer has type struct dynAray**) would point to and make changes to it.
Let's be more clear now slowly:
Why the first case works? You have a struct dynArray variable whose address you have passed into the function and then you have accessed the content of that address - wait! that means you have accessed the struct dynArray variable itself and made changes to its member variables. Yes that is what exactly happened in the first case.
In the second case, you have a pointer to struct dynArray. And then you passed it - de-referenced it. Where was it pointing to? Is it some struct dynArray variable's address that it contained? No. It was NULL. So it is wrong if you expect it to work.
The second would work - but you have to change things a bit! Let's see how:
struct dynArray* initArray() {
struct dynArray* a = malloc(sizeof *a);
assert(a != NULL);
a->data = malloc(10 * TYPE_SIZE);
assert(a->data != 0);
a->size = 0;
a->capacity = 10;
return a;
}
And in main()
struct dynArray* b;
b = initArray();
You don't even need to pass the pointer variable. That would be meaningless if you want to do it like this.
And you know you can also pass the address of the pointer variable so that you can make changes to it -
void initArray(struct dynArray** a) {
*a = malloc(sizeof **a);
assert((*a) != NULL);
(*a)->data = malloc(10 * TYPE_SIZE);
assert((*a)->data != 0);
(*a)->size = 0;
(*a)->capacity = 10;
}
For this in main() you would call it like this
struct dynArray* b;
initArray(&b);
In the first example a pointer holding the address of an actual struct is passed to the function. But, in the second example the pointer b does not point to a struct. Instead, this pointer is initialized to NULL, and when this null pointer is dereferenced in the initArray() function, undefined behavior ensues.
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;
}
Pointer1 points to 5.
Pointer2 points to 3.
I want to multiply 5*3, but I only have the pointers. How would I do this in C?
Also, what does uint32_t *pointer mean when:
pointer[2] = {1, 2};
I do not know what is so hard for the answerers to understand about this question. It is obviously about dereferencing pointers.
This is how you display the contents of the pointer that it is pointing to:
#include <stdio.h>
int main(void)
{
int num1 = 5;
int num2 = 3;
int* num1_ptr = &num1;
int* num2_ptr - &num2;
int sum = *num1_ptr * *num2_ptr;
printf("%d\n", sum);
return 0;
}
*num1_ptr and *num2_ptr takes your pointers and references what the contents of that memory address.
I can't answer the first half of your question without more information, but uint32_t* pointer is simply a pointer to an unsigned 32-bit integer value (unsigned int and uint32_t are usually equivalent types, depending on your compiler).
If I see a declaration that simply reads uint32_t* pointer without more information I'm going to assume it's a pointer to a single value, and that using the indexing operator [n] on such a pointer is basically overflowing the single-element-sized buffer. However if the pointer is assigned the result from an array or buffer function (e.g. malloc, calloc, etc) then using the indexing operator is fine, however I would prefer to see uint32_t pointer[] used as the declaration as it makes it much easier to determine the developer's intent.
uint32_t *pointer is just a pointer with garbage value unless you point it to something.
pointer[0] = 1;
pointer[1] = 2;
is only valid if you have earlier pointed it to some array of type uint32_t with atleast size two or to a block containing uint32_ts defined using malloc as follows:
uint32_t *pointer;
pointer = (uint32_t*)malloc(sizeof(int*SIZE); //SIZE > 2 here
or
uint32_t array[10];
pointer = & array[0]; // also, pointer = array; would also work.
int main(void)
{
int variableA = 5;
int variableB = 3;
int* ptr1 = &variableA; // Pointer1 points to 5.
int* ptr2 = &variableB; // Pointer2 points to 3.
int answer;
answer = (*ptr1) * (*ptr2); // I want to multiply 5*3, but I only have the pointers.
// Answer gets set to [value stored at ptr1(5)] MultipliedBy [value stored at ptr2(3)]
}
Your misconception is that pointers do not refer to values, such as 5 and 3.
pointers refer to variables, such as variableA and variableB; those variables have values which can be accessed and changed via the pointer.But the pointer only refers to the variable, not directly to the value behind it.
Can someone explain why I do not get the value of the variable, but its memory instead?
I need to use void* to point to "unsigned short" values.
As I understand void pointers, their size is unknown and their type is unknown.
Once initialize them however, they are known, right?
Why does my printf statement print the wrong value?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func(int a, void *res){
res = &a;
printf("res = %d\n", *(int*)res);
int b;
b = * (int *) res;
printf("b =%d\n", b);
}
int main (int argc, char* argv[])
{
//trial 1
int a = 30;
void *res = (int *)a;
func(a, res);
printf("result = %d\n", (int)res);
//trial 2
unsigned short i = 90;
res = &i;
func(i, res);
printf("result = %d\n", (unsigned short)res);
return 0;
}
The output I get:
res = 30
b =30
result = 30
res = 90
b =90
result = 44974
One thing to keep in mind: C does not guarantee that int will be big enough to hold a pointer (including void*). That cast is not a portable thing/good idea. Use %p to printf a pointer.
Likewise, you're doing a "bad cast" here: void* res = (int*) a is telling the compiler: "I am sure that the value of a is a valid int*, so you should treat it as such." Unless you actually know for a fact that there is an int stored at memory address 30, this is wrong.
Fortunately, you immediately overwrite res with the address of the other a. (You have two vars named a and two named res, the ones in main and the ones in func. The ones in func are copies of the value of the one in main, when you call it there.) Generally speaking, overwriting the value of a parameter to a function is "bad form," but it is technically legal. Personally, I recommend declaring all of your functions' parameters as const 99% of the time (e.g. void func (const int a, const void* res))
Then, you cast res to an unsigned short. I don't think anybody's still running on a 16-bit address-space CPU (well, your Apple II, maybe), so that will definitely corrupt the value of res by truncating it.
In general, in C, typecasts are dangerous. You're overruling the compiler's type system, and saying: "look here, Mr Compiler, I'm the programmer, and I know better than you what I have here. So, you just be quiet and make this happen." Casting from a pointer to a non-pointer type is almost universally wrong. Casting between pointer types is more often wrong than not.
I'd suggest checking out some of the "Related" links down this page to find a good overview of how C types an pointers work, in general. Sometimes it takes reading over a few to really get a grasp on how this stuff goes together.
(unsigned short)res
is a cast on a pointer, res is a memory address, by casting it to an unsigned short, you get the address value as an unsigned short instead of hexadecimal value, to be sure that you are going to get a correct value you can print
*(unsigned short*)res
The first cast (unsigned short*)res makes a cast on void* pointer to a pointer on unsigned short. You can then extract the value inside the memory address res is pointing to by dereferencing it using the *
If you have a void pointer ptr that you know points to an int, in order to access to that int write:
int i = *(int*)ptr;
That is, first cast it to a pointer-to-int with cast operator (int*) and then dereference it to get the pointed-to value.
You are casting the pointer directly to a value type, and although the compiler will happily do it, that's not probably what you want.
A void pointer is used in C as a kind of generic pointer. A void pointer variable can be used to contain the address of any variable type. The problem with a void pointer is once you have assigned an address to the pointer, the information about the type of variable is no longer available for the compiler to check against.
In general, void pointers should be avoided since the type of the variable whose address is in the void pointer is no longer available to the compiler. On the other hand, there are cases where a void pointer is very handy. However it is up to the programmer to know the type of variable whose address is in the void pointer variable and to use it properly.
Much of older C source has C style casts between type pointers and void pointers. This is not necessary with modern compilers and should be avoided.
The size of a void pointer variable is known. What is not known is the size of the variable whose pointer is in the void pointer variable. For instance here are some source examples.
// create several different kinds of variables
int iValue;
char aszString[6];
float fValue;
int *pIvalue = &iValue;
void *pVoid = 0;
int iSize = sizeof(*pIvalue); // get size of what int pointer points to, an int
int vSize = sizeof(*pVoid); // compile error, size of what void pointer points to is unknown
int vSizeVar = sizeof(pVoid); // compiles fine size of void pointer is known
pVoid = &iValue; // put the address of iValue into the void pointer variable
pVoid = &aszString[0]; // put the address of char string into the void pointer variable
pVoid = &fValue; // put the address of float into the void pointer variable
pIvalue = &fValue; // compiler error, address of float into int pointer not allowed
One way that void pointers have been used is by having several different types of structs which are provided as an argument for a function, typically some kind of a dispatching function. Since the interface for the function allows for different pointer types, a void pointer must be used in the argument list. Then the type of variable pointed to is determined by either an additional argument or inspecting the variable pointed to. An example of that type of use of a function would be something like the following. In this case we include an indicator as to the type of the struct in the first member of the various permutations of the struct. As long as all structs that are used with this function have as their first member an int indicating the type of struct, this will work.
struct struct_1 {
int iClass; // struct type indicator. must always be first member of struct
int iValue;
};
struct struct_2 {
int iClass; // struct type indicator. must always be first member of struct
float fValue;
};
void func2 (void *pStruct)
{
struct struct_1 *pStruct_1 = pStruct;
struct struct_2 *pStruct_2 = pStruct;
switch (pStruct_1->iClass) // this works because a struct is a kind of template or pattern for a memory location
{
case 1:
// do things with pStruct_1
break;
case 2:
// do things with pStruct_2
break;
default:
break;
}
}
void xfunc (void)
{
struct struct_1 myStruct_1 = {1, 37};
struct struct_2 myStruct_2 = {2, 755.37f};
func2 (&myStruct_1);
func2 (&myStruct_2);
}
Something like the above has a number of software design problems with the coupling and cohesion so unless you have good reasons for using this approach, it is better to rethink your design. However the C programming language allows you to do this.
There are some cases where the void pointer is necessary. For instance the malloc() function which allocates memory returns a void pointer containing the address of the area that has been allocated (or NULL if the allocation failed). The void pointer in this case allows for a single malloc() function that can return the address of memory for any type of variable. The following shows use of malloc() with various variable types.
void yfunc (void)
{
int *pIvalue = malloc(sizeof(int));
char *paszStr = malloc(sizeof(char)*32);
struct struct_1 *pStruct_1 = malloc (sizeof(*pStruct_1));
struct struct_2 *pStruct_2Array = malloc (sizeof(*pStruct_2Array)*21);
pStruct_1->iClass = 1; pStruct_1->iValue = 23;
func2(pStruct_1); // pStruct_1 is already a pointer so address of is not used
{
int i;
for (i = 0; i < 21; i++) {
pStruct_2Array[i].iClass = 2;
pStruct_2Array[i].fValue = 123.33f;
func2 (&pStruct_2Array[i]); // address of particular array element. could also use func2 (pStruct_2Array + i)
}
}
free(pStruct_1);
free(pStruct_2Array); // free the entire array which was allocated with single malloc()
free(pIvalue);
free(paszStr);
}
If what you want to do is pass the variable a by name and use it, try something like:
void func(int* src)
{
printf( "%d\n", *src );
}
If you get a void* from a library function, and you know its actual type, you should immediately store it in a variable of the right type:
int *ap = calloc( 1, sizeof(int) );
There are a few situations in which you must receive a parameter by reference as a void* and then cast it. The one I’ve run into most often in the real world is a thread procedure. So, you might write something like:
#include <stddef.h>
#include <stdio.h>
#include <pthread.h>
void* thread_proc( void* arg )
{
const int a = *(int*)arg;
/** Alternatively, with no explicit casts:
* const int* const p = arg;
* const int a = *p;
*/
printf( "Daughter thread: %d\n", a );
fflush(stdout); /* If more than one thread outputs, should be atomic. */
return NULL;
}
int main(void)
{
int a = 1;
const pthread_t tid = pthread_create( thread_proc, &a );
pthread_join(tid, NULL);
return EXIT_SUCCESS;
}
If you want to live dangerously, you could pass a uintptr_t value cast to void* and cast it back, but beware of trap representations.
printf("result = %d\n", (int)res); is printing the value of res (a pointer) as a number.
Remember that a pointer is an address in memory, so this will print some random looking 32bit number.
If you wanted to print the value stored at that address then you need (int)*res - although the (int) is unnecessary.
edit: if you want to print the value (ie address) of a pointer then you should use %p it's essentially the same but formats it better and understands if the size of an int and a poitner are different on your platform
void *res = (int *)a;
a is a int but not a ptr, maybe it should be:
void *res = &a;
The size of a void pointer is known; it's the size of an address, so the same size as any other pointer. You are freely converting between an integer and a pointer, and that's dangerous. If you mean to take the address of the variable a, you need to convert its address to a void * with (void *)&a.