using pointers that have ** in c - c

I am very new to C and currently having some trouble with pointers and I am not sure if my logic is correct on this question clarification would be great.
Is the second expression legal? Why or Why not? What does it mean?
int** x = ....;
... **x ...
This is all the question gives and I came up with the following answer (I think its in the ballpark)
The int** x will initialize a pointer x to whatever address/value that is after the equal sign.
**x ... will dereference the pointer to a value/variable
The question link that was proposed in the edit was just showing the difference between int* p and int *p which is nothing what i asked i understand this already.

int *x is a pointer to int. int** y defines y as a pointer to pointer to int, so it points to a pointer, and the latter points to an int. Example:
int n = 42;
int* x = &n; // points to n
int** y = &x; // points to x, which points to n
In this case y is a pointer to pointer. First indirection *y gives you a pointer (in this case x), then the second indirection dereferences the pointer x, so **y equals 42.
Using typedefs makes everything looks simpler, and makes you realize that pointers are themselves variables as any other variables, the only exception being that they store addresses instead of numbers(values):
typedef int* pINT;
int n = 42;
pINT x = &n;
pINT* y = &x; // y is a pointer to a type pINT, i.e. pointer to pointer to int

If you use double * you are telling the compiler you want a pointer pointing to another pointer:
int x = 4;
int *pointer = &x;
int **pointer_pointer = &pointer;
printf("%d\n",**pointer_pointer); // This should print the 4

Related

New to pointers in C

In the following code I would like to understand better what is happening with int *z = malloc(sizeof(int);
To me that creates a pointer to an int. Then *z gets the sum of the value that x points to (2) and the value that y points to (4).
Now *z = 6. Does that mean *z does not point to anything? It just stores an int? I thought *z was a pointer and a pointer is an address? Thank you for any help understanding.
int *add(int *x, int *y)
{
int *z = malloc(sizeof(int));
*z = (*x) + (*y);
return z;
}
int main(void)
{
int a = 2;
int b = 4;
int *ptr = add(&a, &b);
printf("sum = %i\n", *ptr);
}
Now *z = 6. Does that mean *z does not point to anything? It just stores an int? I thought *z was a pointer and a pointer is an address? Thank you for any help understanding.
You are correct with *z = 6 however you are wrong with how this happens.
z is a pointer and so it point somewhere into the memory. Earlier in your program, with int *z = malloc(sizeof(int)); you have allocated a space the z points to.
Then when you did *z = (*x) + (*y); you've basically put the result of the addition into that allocated space.
z still points to that space (because it is a pointer). *z is called dereferencing and has a meaning of reaching directly for the value the pointer points to.
In other words: the 6 is stored in a place the z points to and *z is a way to grab that value.
*z = 6 assigns 6 to the location pointed at by ptr. That's what a pointer does, it points to things, but in order to put a value at where it's pointing as opposed to changing the pointer you need to de-reference with the * operator.1
Imagine your memory as, conceptually, a number of bytes each of which has a number. A pointer to an int represents a particular location in memory which is presumed to hold an int, or 4 bytes worth of data.
*z = 6 means "put an integer value of 6 in the memory location described by z", which translates into machine instructions that are largely the same.
z absolutely does not "store an int", it stores a location. That location may exist, or may be NULL, or may be invalid. There's no guarantees unless you've checked your code carefully to ensure the pointer is valid. That's your responsibility as a programmer.
That's also why pointers can be tricky and frustrating. They introduce indirection in your code.
1 In C pointers are also largely interchangeable with arrays so you can do z[0] = 6, though as z only points to a single int, any index other than 0 is invalid.
int *z = malloc(sizeof(int));
this will envoke a system call for allocating one integer on the heap. z is the address of this integer return from malloc (if malloc fails to allocate z will be null)
z is a pointer to buffer allocated on the heap (if malloc success). in your case this buffer hold one integer so its a pointer to this integer.
see malloc description in man pages. malloc_man_pages
*z = (*x) + (*y);
you are right. you are assigning the value that sets in the address x and the value that sets in the address y to the place that z points to.
you dont check the return vale from malloc and this is a very bad thing. always check if malloc successd! see below. maybe you need to check the pointers that you get in x and y ?! (thats up to you, but i recommend to check).
int* add(int *x, int *y)
{
int *z = NULL;
if(x && y)
{
z = malloc(sizeof(int));
if(z)
{
*z = (*x) + (*y);
}
}
return z;
}

Why can't I set a value of a pointer int *x to, say, 10?

I'm severely misunderstanding pointers, so hopefully someone can clarify this please.
int *x; is a pointer to an int. x refers to the pointer itself, and *x refers to the value (or target) stored at x's memory location.
If I want x to point to an int, who's value is 10, why can't I do int *x = 10;?
I don't quite understand why when we do something like printf("%d", *x);, it prints out the value stored at x but we can't do int *x = 10;
Your confusion has to do with the difference between an initialization and an assignment. These are examples of initialization:
int a = 5; // valid; "a" is an int which is initialized with the value 5
int *b = &a; // valid; "b" is an int * which is initialized with the address of "a"
int *c = 10; // invalid; "c" is an int * which is initialized with the value 10
While these are assignments:
a = 5; // valid; "a" is assigned the value 5
b = &a; // valid; "b" is assigned the address of "a"
*b = 10; // valid; "b" points to "a", and the value "b" points to is set to 10
Note that the use of * differs between the two. In an initalization * means that the given variable is a pointer, while * in an assignment (or any expression) means that the pointer is dereferenced.
int* x -> x is a memory adress for an Integer, type (int*).
if you do *x it displays the content because * is a operand, a memory operand that shows what is stored in that memory adress, and (int*) is a type of data,a pointer to something in the memory, very different.
Hope I explained it quickly. Good coding.
int *x means ---- x is integer pointer type.
and 10 is a integer type.
in your case, you are trying to assign an "integer" type to " integer pointer" type, which is not valid because of two different types.

Pointers and Memory Allocation in C

Program:
int x;
int *y;
int **z;
z = (int **) malloc (sizeof(int *));
y = (int *) malloc (sizeof(int));
x = 1;
*z = &x;
*y = x;
.
.
.
Question:
What is the difference between:
*z = &x;
*y = x;
From what I understand *z points to the address of x and *y points to x, but for *y to point to x doesn't that require the address of x? I don't really understand what's going on with these two variables.
Edit:
I also want to know when do we know when a variable is allocated on the stack or on the heap?
Why is x,y, and z allocated on the stack?
Why is *y, **y, *z, **z, allocated on the heap?
Finally, does changing *z, change **z?
z is a pointer to a pointer (which will typically point to a dynamically allocated array of pointers).
y is a pointer to int. Again, more often than not it'll point to a dynamically allocated array of ints.
So, the *z = &x; is setting the pointer that z refers to to point at x. I.e., z points at a pointer, which (in turn) points to x.
*y = x; is taking the value of x and assigning it to the int pointed to by y.
For things like this, a picture is often helpful. So, our basic definitions give us this:
The we do:
z = (int **) malloc (sizeof(int *));
y = (int *) malloc (sizeof(int));
Which gives us this:
Then we do:
*z = &x;
*y = x;
Which gives us this:
In all of these, a dashed line signifies a pointer from one place to another, while the solid line indicates copying a value from one place to another.
We can then consider the long-term differences between them. For example, consider what happens if we add x=2; after all the assignments above.
In this case, *y will still equal 1, because we copied the value 1 from x to *y. **z will equal 2 though, because it's just a pointer to x -- any change in x will be reflected in **z.
This line stores the address of variable x in the memory pointed to by z:
*z = &x;
This line stores the value of x into memory pointed to by y:
*y = x;
The two assignment statements are unrelated: the second one makes a copy, while the first one does not. If you change the value of x and then retrieve **z, you will see the new value of x; however, retrieving *y would give you back the old value of x (i.e. 1).

Pointer value of *x &x and x

suppose this code:
main()
{
int *x;
*x = 3;
printf("%d %d %d\n", *x, &x, x);
// output 3 5448392 2293524
}
if *x is the value; &x the addres; what does mean that value of x?
*x is the value (correct)
x is the address of the value. EDIT In your case, this address is uninitialized, so it is not pointing anywhere in particular (thanks Keith Nicholas for mentioning this).
&x is the address of the [pointer that should contain the] address of the value.
(it's worth pointing out that your program may crash :)
Adr value expression
----------------------------------------------
5448392 2293524 &x address of x
2293524 3 x place where you assigned 3
x gives you the address in memory where value of *x, i.e. 3 is located. &x gives the address where value of x, i.e. 2293524 is located.
It is the address that x contains. Having been declared as a pointer, x stores an address, while &x is in a sense a pointer to a pointer.
EDIT: So I wasn't as precise as perhaps I should have been. &x is strictly speaking not a pointer to a pointer. It is the address of a pointer. In the following line of code, y is a pointer to a pointer:
int **y = &x;
x is a pointer to an int, its not an int itself, its not the address of an int, its a pointer.
a pointer contains an address of an int.
so, a missing step you have ( your program doesn't point x to anything! very dangerous)
int y = 5;
int *x;
x = &y // put the memory location of y into the pointer
if you now print the contents of the pointer...
printf("%d\n", x); // prints out the memory location of y;
now to get to the value of what your pointer points to ( at the moment, y)
printf("%p\n", *x); // prints out 5;
now, just like y has a memory location, x also has a location in memory
so &x is where the pointer 'x' is in memory
x is uninitialized so it points to nowhere and dereferencing it with * is undefined behaviour.
The following would be a more correct (and useful) program
main()
{
int x; //declare an int variable
int *xp; //declare a pointer to an int variable
xp = &x;
*xp = 3;
printf("%d %d %d %d %d\n", x, &x, xp, *xp, &xp);
}
x is a value, xp and &xp point to that value, *xp can be used to access and change the value and &xp is a pointer to that pointer...
&x is the address of the pointer object.
The value of the pointer is the address of an int.
Also, you shouldn't assign to *x as in your example: x doesn't point anywhere valid.
x and &x values are of pointer types so you should use p conversion specifier to print their values.
printf("%d %p %p\n", *x, (void *) &x, (void *) x);
Don't forget to cast to void * otherwise the call to printfis undefined behavior. (p conversion specifier requires an argument of type void *).
int *x;
int y = 0;
x = &y;
*x = 3;
x is a pointer to int. *x is an int and its value is 3. And &x is a pointer to a pointer to int. Note that your pointer has to point to a valid object object (like above) otherwise it has an invalid value.

Arrays decaying into pointers

Please help me understand the programs below.
#include<stdio.h>
int main()
{
int a[7];
a[0] = 1976;
a[1] = 1984;
printf("memory location of a: %p", a);
printf("value at memory location %p is %d", a, *a);
printf("value at memory location %p is %d", &a[1], a[1]);
return 0;
}
&a[1] and &a+1. Are they same or different?
#include <stdio.h>
int main()
{
int v[10];
int **p;
int *a[5];
v[0] = 1234;
v[1] = 5678;
a[0] = v;
a[1] = v+1;
printf("%d\t%d\t%d\t%d\n", *a[0],*a[1],a[0][0],**a);
printf("%d\n", sizeof(v));
return 0;
}
I wanted to know how *a[5] is represented in memory. Is *a a base pointer that points to a[0],a[1],a[2],a[3],a[4]?
#include<stdio.h>
int main()
{
int v[10];
int **p;
int (*a)[10];
a=&v;
printf("%d\n",*a);
return 0;
}
a=v; // gives error why? does v here decay into *v. Then does &v get decayed into (*)[]v? & means const pointer. Here, how is it possible to set a const pointer to a non-const pointer without a typecast?
Where does the array get stored in the memory. Does it get stored onto the data segment of the memory.
#include<stdio.h>
int main()
{
int carray[5]={1,2,3,4,5};
printf("%d\n",carray[0]);
printf("%d\t%d\t%d\n",sizeof(carray),sizeof(&carray),sizeof(&carray[0]));
return 0;
}
EDITED:
I have gone through some of the articles which stated that the only two possible situations where an array name cannot be decyed into pointer is the sizeof and &. But in the above program sizeof(&carray) gives the size as 4. and &carray decays into (*)[]carray as its an rvalue.
Then the statement that array name cannot get decayed into pointers on two conditions sizeof and & becomes false here.
&a[1] and &a+1. Are they same or different?
Different. &a[1] is the same as (a+1). In general, x[y] is by definition equivalent to *(x+y).
I wanted to know how *a[5] is represented in memory. Does *a is a base
pointer that points to a[0],a[1],a[2],a[3],a[4].
In your second example, a is an array of pointers. *a[i] is the value of the object, the address of which is stored as the ith element in your array. *a in this case is the same as a[0], which is the first element in your array (which is a pointer).
a=v //why this gives error
Because a (in your last example) is a pointer to an array. You want to assign to a, then you need to assign the address of the array v (or any other array with correct dimensions);
a = &v;
This is very good that you've commited to understanding things, but nothing will help you better than a good C book.
Hope this helps.
Stuff you are gonna need to know when dealing with pointers is that:
int *a and int a[]
is a declaration of an Array, the only diffrence is that in a[] youre gonna have to declare its constant size, *a gives you flexability, it can point at an array size 1 to infinity
int *a[] and int **a
is a declaration of an Array of Array,sometimes called Matrix, the only diffrence is that in *a[] youre gonna have to declare how many Arrays a[] gonna contain pointers of, **a gives you flexability, it can point at any Array of arrays that you want it to be assigned to.
IN GENERAL:
When adding & to a variable, your adding a * to its Type definition:
int a;
&a -> &(int)=int*
when adding * to a variable, you decrase a * from its Type definition
int *a;
*a -> * (int * )=int
int *a;
&a - the Address given to the pointer a by the system(pointer of pointer = **a)
&a+1 - the Address to the beginning of the array + 1 byte
&a[1] == &(a+1) - the Address to the beginning of the array + 1 size of int
int **a;
*a == a[0] - the Address of the first Array in the array of arrays a
*a[0]==a[0][0] - the first int of first array
int *a, b[5];
*a=*b - ERROR because a points at garbage to begin with
a=b - a points at array b
ask me what else you want to know and ill edit this answer.

Resources