What is the difference between the following two assignments?
int main()
{
int a=10;
int* p= &a;
int* q = (int*)p; <-------------------------
int* r = (int*)&p; <-------------------------
}
I am very much confused about the behavior of the two declarations.
When should i use one over the other?
int* q = (int*)p;
Is correct, albeit too verbose. int* q = p is sufficient. Both q and p are int pointers.
int* r = (int*)&p;
Is incorrect (logically, although it might compile), since &p is an int** but r is a int*. I can't think of a situation where you'd want this.
#include <stdio.h>
int main()
{
int a = 10; /* a has been initialized with value 10*/
int * p = &a; /* a address has been given to variable p which is a integer type pointer
* which means, p will be pointing to the value on address of a*/
int * q = p ; /*q is a pointer to an integer, q which is having the value contained by p, * q--> p --> &a; these will be *(pointer) to value of a which is 10;
int * r = (int*) &p;/* this is correct because r keeping address of p,
* which means p value will be pointer by r but if u want
* to reference a, its not so correct.
* int ** r = &p;
* r-->(&p)--->*(&p)-->**(&p)
*/
return 0;
}
int main()
{
int a=10;
int* p= &a;
int* q = p; /* q and p both point to a */
int* r = (int*)&p; /* this is not correct: */
int **r = &p; /* this is correct, r points to p, p points to a */
*r = 0; /* now r still points to p, but p points to NULL, a is still 10 */
}
Types matter.
The expression p has type int * (pointer to int), so the expression &p has type int ** (pointer to pointer to int). These are different, incompatible types; you cannot assign a value of type int ** to a variable of type int * without an explicit cast.
The proper thing to do would be to write
int *q = p;
int **r = &p;
You should never use an explicit cast in an assignment unless you know why you need to convert the value to a different type.
Related
I have the following code:
void change_adrs(int **q)
{
int * otheraddess;
*q = otheraddress;
}
I can't understand this assignment: *q = otheraddress;
Could anybody help me to explain this. Why can't we use another assignment, such as:
**q = otheraddress;
*q = *otheraddress;
q = &otheraddress;
void change_ptr(int **q)
{
*q = malloc(somemem);
}
void foo()
{
int *ptr;
change_ptr(&ptr);
}
in this example it will change the value of the ptr itself. When you pass a single star pointer you can only change the referenced object.
Look at the assignment of *q = otheraddress; the same as you look at the following:
int x = 4;
int y = x;
you take 2 vairables of the same type and make an assignment between both of them.
In your case, you use the address of int vairables.
int *otheraddress; is a vairable who can get an address (& operator) to int vairable such as:
int x = 4;
int *p = &x; //p<=the address of x
and int **q; can get an address of a vairable which can get int address. such as you 3rd assignment (which should work fine):
int x = 4;
int *p = &x;//p<=the address of x
int **q = &p;//q<=the address of p
for the other assignmets:
**q = otheraddress; you try to assign int* into int**
*q = *otheraddress; you try to assign int into int *
After declaring the variables, * dereferences them.
For example after declaring something like int **a;, when using it we have:
**a value in value in location stored in a(which is ultimately an int)
*a value in location stored in a (which is another location)
a location stored in a
&a location of a itself
Lets take a look and see why each of your examples don't work:
**q = otheraddress; assigning a location to an int ×
*q = *otheraddress; assigning an int to a location ×
Edit: Lets take a look at these two examples:
q = &otheraddress; assigning a location to a location ✓
*q = otheraddress; assigning a location to a location ✓
Lets look at it this way:
Suppose we have:
int *a;
int **q;
in order to prevent segmentation faults in the future, lets first assign some address to a:
int t = 5
a = &t;
Lets look at the addresses afterq = &a:
//first snippet
0x7fffc3a2b338 // &a
0x5596853c98c0 // a
5 // *a
0x7fffc3a2b340 // &q
0x7fffc3a2b338 // q
0x5596853c98c0 // *q
5 // **q
As expected, &a is put into q, and a holds &t, so **(&a) and **(q) will both hold a value of 5.
Now lets look at the addresses after*q = a:
//second snippet
0x7fffc3a2b338 // &a
0x5596853c98c0 // a
5 // *a
0x7fffc3a2b340 // &q
0x7fffc3a2b345 // q
0x5596853c98c0 // *q
5 // **q
Here, a is put into *q, and a itself is &t, so *(a) and *(*q) with both hold a value of 5.
To understand the difference, we look at an example:
int b = 3;
a = &b;
Using this after the first snippet, a is given another address, and q was declared &a(which hasn't changed), therefore **(q) has the same value as **(&a), which is now 3.
This is just like saying:
int a = 3;
int *b = &a;
a = 5; //even though a has changed, b retains its old value of &a, thus *(b) == *(&a) == 5
However on the second snippet, *q was already declared as a before it had changed, so even though a now has a new address, the address inside *q still hasn't changed. Thus trying to access *(*q) will use the old address and give us 5 again.
This is just like saying:
int a = 3;
int b = a;
a = 5; //even though a has changed, b still retains it's old value of 3
#include <stdio.h>
int main()
{
int a, b, c, d;
char *p = (char *)0;
int *q = (int *)0;
float *r = (float *)0;
double *s = 0;
a = (int) (p+1);
b = (int) (q+1);
c = (int) (r+1);
d = (int) (s+1);
printf("%d %d %d %d", a, b, c, d);
return 0;
}
As I've run it, it gives the output
1 4 4 8
From the output I assume it gives the sizes of data types(char, int, float and double) as output. But I don't understand how. Can someone please explain this program. What does (char *)0 means? What does (int)(p+1) do?
Thanks in advance.
What does (char *)0 means?
It casts 0 to a pointer. It is not necessary though. You could have used
char *p = 0;
or
char *p = NULL;
What does (int)(p+1) do?
p+1 evaluates to a pointer value. The (int) part casts the pointer to an int. It works on some platforms because the numerical difference between p and p+1 is sizeof(*p).
However, please note that this is undefined behavior. Don't use it in production code. Use the standard supported mechanism to get the size of a type -- sizeof(type).
int a = sizeof(char);
int b = sizeof(int);
int c = sizeof(float);
int d = sizeof(double);
printf("%d %d %d %d", a, b, c, d);
You could preserve the type that sizeof evaluates to by using size_t for the variables.
size_t a = sizeof(char);
size_t b = sizeof(int);
size_t c = sizeof(float);
size_t d = sizeof(double);
printf("%zu %zu %zu %zu", a, b, c, d);
In C, pointers and integers are interchangeable. So:
(char *)0 tells the compiler to look at the int 0 as if it were the address of a pointer to char. It then assigns that to p, a pointer to char.
C allows pointer arithmetic, so the expression p+1 computes the address where the compiler would put another char after p. The difference between the addresses of p and p+1 should be the size of 1 char in bytes.
To make sure C recognizes that as an int when it prints it out, the assignment a = (int) (p+1); casts p+1 (an address) to an int. Effectively, that's the size of a char.
Let's analyse each parts:
char *p = (char *)0;
A chart pointer is created and initialized to 0. The (char *) is here to cast the 0 to a char adress. So the pointer p points to the adress 0.
a = (int) (p+1);
(p+1) is the next adress after the current one (0) for a char* (p's current type). the (int) is there for the cast once again. For each type it will give the size because its value is the distance between the 1st adress and the second one.
code:
int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr;
printf("p:%p\n",p);
printf("*p:%p\n",*p);
result: p = *p = arr = 0x7ffee517c830 they are all the address of the array
The right way to use p to visit arr[i] is *(*p+i)
The type of pointer p is int(*)[5], so p point to an array which type is int [5]. But we can't say that p point to an invisible shell of arr, p is a variable after all. It stores the address of arr, which is also the address of arr[0], the first element of arr.
I thought *p will get me 1, which is the first element of arr.
The dereference operation means take the value in p as address and get the value from this address. Right?
So p stores the address of arr,which is 0x7ffee517c830 here, and 1 is stored in this address. Isn't **p illegal? The first dereference give us 1, and second dereference will use 1 as address which is illegal.
What I am missing?
The result of *p is an lvalue expression of array type. Using (*p) is exactly the same as using arr in any expression you could now think of.
For example:
&*p means &arr
**p means *arr (which is legal).
(*p)[i] means arr[i].
sizeof *p means sizeof arr.
Arrays are not special in this regard. You can see the same phenomenon with int x; int *q = &x;. Now *q and x have exactly the same meaning.
Regarding your last paragraph, I think you are confusing yourself by imagining pointers as glorified integers. Some people teach pointers this way but IMO it is not a good teaching technique because it causes the exact confusing you are now having.
If you dereference an int(*)[5] you get an int[5] and that's all there is to it. The data type matters in dereferencing. It does not make sense to talk about "dereferencing 0x7ffee517c830". Again this is not peculiar to arrays; if you dereference a char ***, you get a char ** etc.
The only way in which arrays are "different" in this discussion is what happens if you try to do arithmetic on them, or output them, etc. If you supply an int[5] as a printf argument for example, there is implicit conversion to int * pointing at the first of those 5 ints. This conversion also happens when applying the * operator to an int[5], which is why you get an int out of that.
p is declared as a 'pointer to int[5]'.
arr is declared as an 'int[5]`
so the initializer p = &arr; is not really that strange. If you substituted any primitive type for int[5] you wouldn't bat an eye.
*p is another handle on arr. so (*p)[0] = 1.
This really only comes up in wierd cases. It's most natural where you dereference the pointer-to-array using the subscript operator. Here's a contrived example where I want to pass a table as argument.
#include <stdio.h>
int print_row_range(int (*tab) [2], int first, int last)
{
int i;
for(i=first; i<= last; i++)
{
printf("{%d, %d}\n", tab[i][0], tab[i][1]);
}
}
int main(int argc, char *argv[])
{
int arr[3][2] = {{1,2},{3,4},{5,6}};
print_row_range(arr,1,2);
}
This example treats the table as an array of rows.
Dereferencing doesn't give you a value. It gives you an object, which can be used as a value of its type if it can be converted to.
*p, being identical to arr, is an object of an array of 5 ints, so if you want to get an integer from the array, you must dereference it again like (*p)[3].
Consider a bigger example:
int arr[5][5];
int (*p)[5] = arr;
Now you get arr[0] with *p, which itself is an array of 5. Here comes the difference:
*( p+1) == arr[1];
*(*p+1) == arr[0][1];
^ ^^^
Got the point?
One use case is to be able to allocate with malloc an 2D (or more) pointer of arrays with only one malloc:
#include <stdio.h>
#include <stdlib.h>
static int (*foo(size_t n))[42] {
return malloc(sizeof *foo(0) * n);
// return malloc(sizeof(int [n][42]); works too
}
int main(void) {
size_t n = 42;
int (*p)[42] = foo(n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}
I think this very funny.
One more with VLA:
#include <stdio.h>
#include <stdlib.h>
static void *foo(size_t elem, size_t n, size_t m) {
return malloc(elem * n * m);
}
int main(void) {
size_t n = 42;
int (*p)[n] = foo(sizeof **p, n, n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}
I am trying to swap the value of two integers using pointers, see code below: swapping number using pointer in c:
{
int a = 10;
int b = 20;
swapr(&a, &b);
printf("a=%d\n", a);
printf("b=%d\n", b);
return 0;
}
void swapr(int *x, int *y) //function
{
int t;
t=*x;
*x=*y;
*y=t;
}
In the code why is swap(&A, &B); used when *x and *y point to a value not an address
When you say (int *x, int *y) you're just declaring x and y as pointers. In all future usages, when you say x, it means the pointer and when you say *x, it means the value it points to.
In a declaration, the * in the declarator indicates that the object has pointer type. Take the declaration
int *p;
The type of p is "pointer to int". This type is specified by the combination of the type specifier int and the declarator *p.
Pointer-ness, array-ness, and function-ness are all specified as part of the declarator:
T *p; // p is a pointer to T
T a[N]; // a is an N-element array of T
T f(); // f is a function returning T
T *ap[N]; // ap is an array of pointers to T
T (*pa)[N]; // pa is a pointer to an array of T
T *fp(); // fp is a function returning pointer to T
T (*pf)(); // pf is a pointer to a function returning T
etc.
In C, declaration mimics use - if you have a pointer to an int named p and you want to access the value it points to, you dereference it with the * operator, like so:
x = *p;
The expression *p has type int, so the declaration of p is
int *p;
In main, the expressions &a and &b have type int *, so the corresponding parameters have to be declared as int *.
x == &a // int * == int *
y == &b // int * == int *
*x == a // int == int
*y == b // int == int
Basically the way var declarations work is if you declare a variable
int c;
You've just declared an integer and you can assign values to it or retrieve its value like this
int a;
int b;
a = 10; // assign 10
b = a; //assign value of a to b
Pointers are a bit different though. If you declare a pointer and you want to assign a value to it then you must dereference it with the * operator
int * a; // declare a pointer
int b; // declare a var
b = 10; // assign 10 to b
*a = b; // assign 10 as the value of a
b = 20; // b is now 20 but the var a remains 10
But you can also assign a pointer to point at a memory address
int * a;
int b;
b = 10; // assign 10 to b
a = &b; // assign address of b to a (a points at b)
b = 20; // value of b changes (thus value of a is also 20 since it is pointing at b
So if you have a function signature
int func (int * a, int * b);
All this is means is that the function takes the address of two variable
int a;
int b;
int * x;
int * y;
func(&a, &b); // send it the address of a and b
func(x, y); // send it the address of x and y
func(x, &b);
Basically a normal var's address can be accessed with the & operator.
Why is
int i;
int *p = &i;
right, while
int i, *p;
*p = &i;
is wrong?
Is there any difference between * operator used in declaration (int *p = &i) and expression (*p = &i)?
In your second code block, this:
int i, *p;
*p = &i;
can be fixed to:
int i, *p;
p = &i;
p is still declared as a pointer to an int, but you want to store the address of i to p.
In your code, *p = &i stores the address of i to some area in memory that p points to (since you didn't initialize it).
Yes there is difference - in the first form * is part of the type definition int *.
In the second form its an unary dereference operator. Also there is an error with the second expression - when you are assigning to a pointer, there is no need to dereference it.
(*p) evaluates to type int while p evaluates to type int *; &i evaluates to type int *. Hence assinging the address of int variable i to pointer p should read p=&i;