Pointer initialization: address or value - c

I have a question regarding pointer initialization in C.
I understand that *ptr will give the value of that pointer is pointing to.
ptr will give you the address.
Now I got following syntax:
int *ptr = (int *) malloc(sizeof(*ptr));
Why is *ptr being initialized with an address of the Heap and not a value? malloc() returns an address right?
Shouldn't it be:
int *ptr;
ptr = malloc(...);

With *ptr, * is acting as the dereferencing operator.
With int *ptr, * is acting as part of the type declaration for ptr.
So the two things are entirely different, even though * is used. (Multiplication and comment blocks are further uses of * in C).

In that line, int * is the type.
int *ptr = (int *) malloc(sizeof(*ptr));
Is just this compressed into one line:
int *ptr;
ptr = (int *) malloc(sizeof(*ptr));

Actually , this:
int *ptr = (int *) malloc(sizeof(*ptr));
Is just short syntax for this:
int *ptr;
ptr = malloc(...);
The * is used for defining a type pointer and not to dereference the pointer .

Both snippets above do the same thing.
In the first case, the * before ptr is not the derefernece operator but is part of the definition of the type. So you actually are assigning a value to (initializing, actually) ptr, not *ptr.

The difference between
int *ptr = (int *) malloc(sizeof(*ptr));
and
int *ptr;
ptr = malloc(...);
is basically the same as the difference between
int i = 5;
and
int i;
i = 5;
The first variant defines and initializes a variable in one go. The second variant defines the variable but leave it uninitialized, and then assign a value to it.

Related

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

What does *p mean when **p is already declared

Code
short **p = (short **)malloc(sizeof(short *));
*p = malloc(sizeof(short));
**p = 10;
printf("**p = %d", **p);
Output
**p = 10
In this code, a multiple pointer **p is declared and *p is used without any declaration(maybe it's by **p).
What does *p mean in my case? Sorry for very simple question.
I saw C standard and stack overflow, but I couldn't find out something.
For any array or pointer p and index i, the expression p[i] is exactly equal to *(p + i) (where * is the unary dereference operator, the result of it on a pointer is the value that the pointer is pointing to).
So if we have p[0] that's then exactly equal to *(p + 0), which is equal to *(p) which is equal to *p. Going backwards from that, *p is equal to p[0].
So
*p = malloc(sizeof(short));
is equal to
p[0] = malloc(sizeof(short));
And
**p = 10;
is equal to
p[0][0] = 10;
(**p is equal to *(*(p + 0) + 0) which is equal to *(p[0] + 0) which is then equal to p[0][0])
It's important to note that the asterisk * can mean different things in different contexts.
It can be used when declaring a variable, and then it means "declare as pointer":
int *p; // Declare p as a pointer to an int value
It can be used to dereference a pointer, to get the value the pointer is pointing to:
*p = 0; // Equal to p[0] = 0
And it can be used as the multiplication operator:
r = a * b; // Multiply the values in a and b, store the resulting value in r
short **p = (short **)malloc(sizeof(short *));
This line declares a pointer to a pointer p. Additionally the value of p is set to the return value from malloc. It is equivalent to
short **p;
p = (short **)malloc(sizeof(short *));
The second line
*p = malloc(sizeof(short));
Here *p is the value of p. *p is of type pointer. *p is set to the return value of malloc. It is equivalent to
p[0] = malloc(sizeof(short));
The third line
**p = 10;
**p is the value of the value of p. It is of type short. It is equivalent to
p[0][0] = 10
In effect what the code above does is to allocate a 2D array of short, then allocate memory for the first row, and then set the element p[0][0] to 10.
As a general comment on your code, you should not use typecast in malloc. See Do I cast the result of malloc?
What does *p mean when **p is already declared?
short **p = (short **)malloc(sizeof(short *));
(better written as)
short **p = malloc (sizeof *p);
Declares the pointer-to-pointer-to short p and allocates storage for a signle pointer with malloc and assigns the beginning address for that block of memory to p. See: In C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?
*p = malloc(sizeof(short));
(equivalent to)
p[0] = malloc (sizeof *p[0]);
Allocates storage for a single short and assigns the starting address for that block of memory to p[0].
**p = 10;
(equivalent to)
*p[0] = 10;
(or)
p[0][0] = 10;
Assigns the value 10 to the dereference pointer *p[0] (or **p or p[0][0]) updating the value at that memory address to 10.
printf("**p = %d", **p);
Prints the value stored in the block of memory pointed to by p[0] (the value accessed by dereferencing the pointer as *p[0] or **p)
The way to keep this straight in your head, is p is a single pointer of type pointer-to-pointer-to short. There are 2-level of indirection (e.g. pointer-to-pointer). To remove one level of indirection, you use the unary * operator, e.g.
*p /* has type pointer-to short */
or the [..] also acts as a dereference such that:
p[0] /* also has type pointer-to short */
You still have a pointer-to so you must remove one more level of indirection to refernce the value stored at the memory location pointed to by the pointer. (e.g. the pointer holds the address where the short is stored as its value). So you need:
**p /* has type short */
and
*p[0] /* also has type short */
as would
p[0][0] /* also has type short */
The other piece to keep straight is the type controls pointer-arithmetic. So p++ adds 8-bytes to the pointer-to-ponter address so it now points to the next pointer. If you do short *q = (*p)++; (or short *q = p[0]++, adds 2-bytes to the address for the pointer-to-short, soqnow points to the nextshortin the block of memory beginning at*p(orp[0]`). (there is no 2nd short because you only allocated 1 -- but you get the point)
Let me know if you have further questions.
Let me put it in different way,
consider an example,
int x;
int *y = &x;
int **z = &y;
x = 10;
Which simplifies to this,
Note: Only for illustration purpose I have chosen address of x,y,z as 0x1000,0x2000,0x3000 respectively.
What does *p mean in my case?
In short the snippetshort **p = (short **)malloc(sizeof(short *)); is dynamically allocating a pointer to a pointer of type short i.e same asy in my example.

C, two kinds of functions

I always see two kinds of functions like the following:
void Function_1(
int** buff
)
{
int* retNb = null;
retNb = (int*) malloc(42 * sizeof(int));
*buff = retNb;
}
void Function_2(
int* retNb
)
{
retNb = (int*) malloc(42 * sizeof(int));
}
What is the difference between function_1 and function_2 ? What are their use case ?
A really big difference, they're really different - by ANY means.
Let's keep it simple:
void Function_1(int** buff)
Parameter in function 1 is a pointer to a pointer to an int named buff and what this function does is the following:
int* retNb = null;
Declaring an int pointer called retNb, the assignment to NULL here is really not necessary, though, because next line is the following:
retNb = (int*) malloc(42 * sizeof(int));
retNb is called to get the value returned from malloc. malloc allocated 42*sizeof(int) spot in memory and returned it to retNb and now it can be treated as a simple array with 42 integers and can be accessed with square brackets [] as retNb[i].
*buff = retNb;
in pointers * is the way to get to the content of the address in the variable (variable == pointer in this case) so when using *buff when buff is **buff (a pointer to a pointer) you're actually asking for the pointer buff points to. Let's say we have the code:
int** myPointerToPointer = NULL;
int* myPointer = malloc(sizeof(int));
*myPointer = 4; //or myPointer[0] = 4;
printf("%d\n", *myPointer);
myPointerToPointer = &myPointer;
printf("%d\n", *(*myPointerToPointer));
printf("%d\n", &myPointer);
printf("%d\n", *myPointerToPointer);
then the output would be:
4
4
SOME_ADDRESS
SAME_ADDRESS
because the first printing is the value of myPointer (4) and the second is the value of the value of myPointerToPointer which value is myPointer which value is 4 :P
Third and fourth outputs are the same two because the address of myPointer is actually where myPointerToPointer is pointing to.
About the second function:
void Function_2(int* retNb)
It gets an int pointer - not a pointer to a pointer - just a pointer - means it contains an address of an integer variable that can be accessed with the opeartor *.
retNb = (int*) malloc(42 * sizeof(int));
this line is assigning dynamic memory (again 42 times sizeof(int)) and now can be treated as a regular int array with 42 spots - BUT that's the only thing it does, it won't have anything point to it, just assign memory and that's it.
Hope you understand :P
In function two u are have a pointer to an array of 42 ints.
int function 1 you set buff to point to this array.

Strange pointers initialization

Today I had an exam on ponters in C, and there was some questions about double pointers where the following syntax was used
*pointer = &variable;
I don't know if I have done correctly, but can someone explain where will pointer point to and how will the value in variable change? At first I thought it will cause sntax error, but there was no such answer in a test. Thanks in advance
// two int variables.
int var1;
int var2;
// int pointer pointing to var1
int *ptr = &var1;
// pointer to int pointer..pointing to ptr
int **ptr_to_ptr = &ptr;
// now lets make the pointer pointed to by ptr_to_ptr
// point to var2
*ptr_to_ptr = &var2;
// or alternatively you can do:
// ptr = &var2;
Here's an example on how you could use it:
int foo = 123;
int **bar = malloc(sizeof(int *));
*bar = &foo;
Now bar is a pointer to a pointer to foo. Doesn't make much sense though.
pointer is a pointer to a pointer.
Eg,
int var1=42;
int* intptr;
int** ptr2intPtr;
ptr2intptr = &intptr;
//Syntax in question.
*ptr2intptr = &var1;
//Just like *intptr is same as var1, *ptr2intptr is same as intptr
//so the above line will be equivalent to intptr = &var1
//All the three are the same
printf("%d",**ptr2intptr);
printf("%d",*intptr);
printf("%d",var1);
If the pointer is initialized this way:
int *pointer;
int variable = 10;
pointer = malloc(sizeof(int));
*pointer = &variable;
*pointer = &variable means the address of variable is set as value of the pointee. Since *pointer is dereferencing so you are basically storing a value not setting a reference.

How to set pointers throught functions?

I have a question about C pointers. Because I was wondering if I could set pointers through functions.
I mean like this:
void initptr(int **ptr)
{
ptr = (int *) malloc(sizeof(ptr));
}
int main()
{
int *ptr;
initptr(ptr);
}
Let me know.
Yes this is possible in C, you're just missing a dereference and address of operator in your sample
void initptr(int **ptr)
{
*ptr = (int *) malloc(sizeof(int*));
}
int main()
{
int *ptr;
initptr(&ptr);
}
The deference operator in *ptr = ... converts the type of ptr from int** to int* thus making it compatible with the assignment. Note: the casting of malloc is uneedded here.
The address of operator in initptr(&ptr) reversely converts the type of ptr from int* to int** thus making it compatible with the argument slot.
EDIT
As B Mitch pointed out the malloc size needs updating as well. You appear to be allocating an int* value and hence want the size to be that of an int*.
I believe you want this:
*ptr = (int *) malloc(sizeof(**ptr));
yes, but you need dereference ptr in your function in order to change what it points to
e.g.
void initptr(int **ptr)
{
*ptr = ...
}
when you call the method write
initptr( &ptr );
ptr = (int *) malloc(sizeof(ptr));
You missed to dereference the pointer to pointer so that it can actually take a pointer.
*ptr = (int *) malloc(sizeof(ptr));
// * newly added.
And also call to initptr(ptr); is wrong.
void initptr(int **ptr) ;
The function has an pointer to pointer as an argument. So, the argument ptr needs to hold the address of a pointer. So, change it to -
int *ptr = NULL ; // Initialize pointers to NULL
initptr(&ptr); // Passing the pointers address

Resources