can anybody help me understand this code (in c)..
#include <stdio.h>
void main()
{
const int a =5;int b;
int *p;
p= (int *) &a;
b=a;
*p= *p +1;
printf(" value of p is = %d\n", *p);
printf(" value of b is = %d\n", b);
printf(" value of a is = %d\n",a);
}
result is
: value of p is = 6
: value of b is = 5
: value of a is = 6
With the instruction p = (int *)&a; you made p to point at a.
As a result expression *p refers to the variable a, hence *p = *p + 1; worked as equivalent to a = a + 1; – variable a got assigned its previous value (which was 5) incremented by 1.
So it's finally 6.
This, however, is an Undefined Behavior, as #interjay points out in this comment – the a variable is declared as const, which means it must not be modified. As a result the compiler might choose to allocate it in a read-only area of memory. It did not in your case, and an assignment succeeded, but in other case the modfication of the variable might silently fail (with a value remaining 5) or yield a memory access exception (and terminate the program) or whatever.
The intent of this code is to update the value of a through the pointer p. Let's strip away some things and start with the basics:
int a = 5;
int *p = &a;
We have an object named a that stores the integer value 5. We have another object named p that stores the address of a. After the two declarations above, the following conditions are true:
p == &a == some address value
*p == a == 5
The expression *p is equivalent to the expression a - assigning a new value to *p is the same as assigning a new value to a, so
*p = *p + 1
is the same as writing
a = a + 1
However, in the code you posted a has been declared as a const int. That means you are telling the compiler that the value of a is not supposed to change over its lifetime. The compiler will flag any statement like
a = a + 1
or
a++;
as an error. The compiler may also store a in read-only memory; if you never take the address of a (that is, if it's never the operand of unary &), the compiler may not reserve any storage for it at all and just replace any instance of it with the value (IOW, anywhere you would expect to see a reference to a in the machine code you would just see a literal 5), meaning there's nothing to write to at all.
But this code cheats - it declares p as a pointer to a non-const int. The type of the expression &a is const int * (pointer to const int), but the type of p is just int * (pointer to int). In the assignment
p = (int *) &a;
you are casting away the const qualifier on a. So when you write a new value to *p, the compiler doesn't know that you're trying to modify something that was declared as const so it won't flag it as an error.
The C language definition says that trying to update a const-qualified object through a non-const-qualified lvalue1 results in undefined behavior - the compiler is not required to handle the situation in any particular way. The result can be any one of:
a runtime error;
the value of a remaining unchanged;
behaving exactly as expected;
or something else entirely.
An lvalue is any expression that designates an object such that the object my be read or modified. Both a and *p are lvalues that refer to an integer object containing the value 5
Before the explanation, let me tell you that this is part is a bit problematic, and can lead to undefined behavior:
const int a =5;
p= (int *) &a;
You should remove const, because in this case you want to modify the contents of a through pointers. Some compilers (such as clang, as someone mentioned in the comments) might perform optimizations, like replacing where the const variable is used with its value, to reduce the number of memory access operations.
Let's imagine that each variable is a little box where you can put numbers. So you have 3 boxes:
+---+ +---+ +---+
| 5 | | | | |
+---+ +---+ +---+
a b p
Now let's go over each statement and see what is happening.
int *p;
p= (int *) &a;
p is defined as a pointer, which is a type of variable that can hold the address of something in memory. In this case, it is assigned the address of variable a. So our boxes now look like this:
+---------------+
v |
+---+ +---+ +----+
| 5 | | | | &a |
+---+ +---+ +----+
a b p
p simply contains the memory address of a. You can print it with printf("%u", a), and you will see some number. That is the address of a.
b=a;
Here we are copying the value of a into b, so our boxes become:
+---------------+
v |
+---+ +---+ +----+
| 5 | | 5 | | &a |
+---+ +---+ +----+
a b p
*p= *p +1;
Using the *p syntax, we can dereference the pointer, that means that we can access the memory that p is pointing to (follow the arrow). In this case, *p will allow us to get or set the contents of the a variable. Our boxes now become like this:
+---------------+
v |
+---+ +---+ +----+
| 6 | | 5 | | &a |
+---+ +---+ +----+
a b p
printf(" value of p is = %d\n", *p);
Here you are again dereferencing p, meaning that we are getting the contents of the memory at address p. In our case, this will get the contents of the a variable which is 6.
printf(" value of b is = %d\n", b);
Looking at the b box, we can see that it contains 5.
printf(" value of a is = %d\n",a);
We modified a using the pointer. Looking at the a box, we can see that it contains the value 6.
We go line by line
const int a =5;int b;
In this line, variable b is defined as int and variable a is defined as const int, which means that its value is constant at all lower steps and is equal to 5.
int *p;
p= (int *) &a;
In these two lines, a variable called p is defined as a pointer int, whose value (must be an address from memory cells) is equal to the address of the variable a.
This means that both variables a and p point to a common memory cell.
In other words:
(*p == a) //IS TRUE. Both are equal to 5
and next line:
b = a;
That is, the value of the variable b is also equal to a, which is equal to 5
*p= *p +1;
In this line, a unit is added to the value corresponding to the address p.
We know that the variables a and p point to a common cell of memory.
In fact, this means that we indirectly added a unit to the variable a, which means that both variables have a value of (5 + 1).
And finally, the reason for the output of the last three lines is clear
The problem is entirely in the following line:
p= (int *) &a;
Without the type cast, the line would read:
p = &a;
The type of a is const int.
The type of p is int *.
It is obvious that the compiler should warn about discarding the const qualifier:
warning: assigning to 'int *' from 'const int *' discards qualifiers
[-Wincompatible-pointer-types-discards-qualifiers]
This demonstrates why you should always try to avoid explicit type casting (unless strictly necessary). The author of this code shot themselves in the foot. They introduced undefined behaviour and the obvious problem was hidden, because the warning was discarded or suppressed
Related
int a;
int *p=&a;
a = 20;
*p = 40;
printf("%d",a);
Output:
40
Can anyone explain why the output is 40?
Lets draw it out:
+---+ +---+
| p | --> | a |
+---+ +---+
That is, the variable p points to the variable a.
When you use *p you follow the pointer to get a.
So *p = 40 is equivalent to a = 40.
In this code, the a variable is declared as an int, and it is initialized with the value 20. A pointer p is then declared, and it is initialized with the address of the a variable.
Next, the value of the a variable is modified by using the pointer p. The * operator is used to dereference the pointer, which means that it gives us the value stored at the address that the pointer points to. In this case, the pointer p points to the a variable, so when we dereference p and assign the value 40 to it, we are effectively assigning the value 40 to the a variable.
Since the value of the a variable was previously set to 40 using the pointer, the output of the printf statement is 40.
The output is 40 because the pointer is used to modify the value of the a variable, and the printf statement prints the modified value of a.
This program works in C:
#include <stdio.h>
int main(void) {
char a[10] = "Hello";
char *b = a;
printf("%s",b);
}
There are two things I would expect to be different. One is that we in the second line in the main write: "char *b = &a", then the program is like this:
#include <stdio.h>
int main(void) {
char a[10] = "Hello";
char *b = &a;
printf("%s",b);
}
But this does not work. Why is that? Isn't this the correct way to initialize a pointer with an adress?
The second problem I have is in the last line we should have: printf("%s",*b) so the program is like this:
#include <stdio.h>
int main(void) {
char a[10] = "Hello";
char *b = a;
printf("%s",*b);
}
But this gives a segmentation fault. Why does this not work? Aren't we supposed to write "*" in front of a pointer to get its value?
There is a special rule in C. When you write
char *b = a;
you get the same effect as if you had written
char *b = &a[0];
That is, you automatically get a pointer to the array's first element. This happens any time you try to take the "value" of an array.
Aren't we supposed to write "*" in front of a pointer to get its value?
Yes, and if you wanted to get the single character pointed to by b, you would therefore need the *. This code
printf("first char: %c\n", *b);
would print the first character of the string. But when you write
printf("whole string: %s\n", b);
you get the whole string. %s prints multiple characters, and it expects a pointer. Down inside printf, when you use %s, it loops over and prints all the characters in the string.
Expanding on Steve's answer (which is the correct one to accept)...
This is the special rule he's talking about:
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. If the array object has
register storage class, the behavior is undefined.
C 2011 Prepublication Draft
Arrays are weird and don't behave like other types. You don't get this "decay to a pointer to the first element" behavior in other aggregate types like struct types. You can't assign the contents of an entire array with the = operator like you can with struct types; for example, you can't do something like
int a[5] = {1, 2, 3, 4, 5};
int b[5];
...
b = a; // not allowed; that's what "is not an lvalue" means
Why are arrays weird?
C was derived from an earlier language named B, and when you declared an array in B:
auto arr[5];
the compiler set aside an extra word to point to the first element of the array:
+---+
arr: | | ----------+
+---+ |
... |
+---+ |
| | arr[0] <--+
+---+
| | arr[1]
+---+
| | arr[2]
+---+
| | arr[3]
+---+
| | arr[4]
+---+
The array subscript operation arr[i] was defined as *(arr + i) - given the starting address stored in arr, offset i elements from that address and dereference the result. This also meant that &arr would yield a different value from &arr[0].
When he was designing C, Ritchie wanted to keep B's array subscripting behavior, but he didn't want to set aside storage for the separate pointer that behavior required. So instead of storing a separate pointer, he created the "decay" rule. When you declare an array in C:
int arr[5];
the only storage set aside is for the array elements themselves:
+---+
arr: | | arr[0]
+---+
| | arr[1]
+---+
| | arr[2]
+---+
| | arr[3]
+---+
| | arr[4]
+---+
The subscript operation arr[i] is still defined as *(arr + i), but instead of storing a pointer value in arr, a pointer value is computed from the expression arr. This means &arr and &arr[0] will yield the same address value, but the types of the expressions will be different (int (*)[5] vs int *, respectively).
One practical effect of this rule is that you can use the [] operator on pointer expressions as well as array expressions - given your code you can write b[i] and it will behave exactly like a[i].
Another practical effect is that when you pass an array expression as an argument to a function, what the function actually receives is a pointer to the first element. This is why you often have to pass the array size as a separate parameter, because a pointer only points to a single object of the specified type; there's no way to know from the pointer value itself whether you're pointing to the first element of an array, how many elements are in the array, etc.
Arrays carry no metadata around, so there's no way to query an array for its size, or type, or anything else at runtime. The sizeof operator is computed at compile time, not runtime.
int a=10;
int *p=&a;
now looking at &*p we first look at *p which is 10 and then at &10
which is the address of 10 or the address of a
In the case of *&p we first look at the address of p and then at the value in this address which is 10
But I understand that both *&p vs &*p are the same, why?
Lets draw your variables:
+---+ +---+
| p | --> | a |
+---+ +---+
That is, p is pointing to a.
Now if you do &*p then you first dereference p to get a, then you get the address of a, which leaves you with a pointer to a.
If we take *&p then you get the address of p to get a pointer to p, then you dereference that pointer to get p. Which is a pointer to a.
So while the expressions do different things, the end result is the same: A pointer to a.
And a descent compiler would probably just do nothing at all, since the dereference operator * and address-of operator & together will always cancel each other out, no matter in which order they are.
Considering below example
int a=10;
int *p=&a;
this
*&p
means here both * and & gets nullified and it result in p which is nothing but &a.
And this
&*p
means first dereference p which gives a and then reference & i.e address of a which is nothing but p, same as the first case.
By the clockwise / spiral rule:
For *&p:
+-----+
| +-+ |
| ^ | |
* & p ; |
^ ^ | |
| +---+ |
+-------+
We first take the address of p, which is at this point the address of the address of a.
Then we dereference that, which gives the address of a.
For &*p:
+-----+
| +-+ |
| ^ | |
& * p ; |
^ ^ | |
| +---+ |
+-------+
We first dereference p, which gives us a.
We then take the address of that, which gives us the address of a, just like before.
In this context, & takes the address (i.e., informally "adds *" to the type of the expression). Meanwhile * dereferences a pointer (i.e., "removes a *" from the type of the expression). Therefore:
int *p = …;
p; // int *
*p; // int
&*p; // int *
&p; // int **
*&p; // int *
So, yes, in this context the result is the same: a pointer to int, because the & and the * cancel out. However, this is also why the combinations are pointless: the result is the same as p by itself.
*&p == *(&p). &p is an pointer to the pointer or int. *(&p) is a value to which pointer of pointer points, which is value of p. To continue, **&p will print '10'.
&*p == &(*p) where *p is the value at which the pointer points (value of a). Now & is an address of a, which is p again. And to go further, *&*p will print value of a (10).
I'm kinda confused:
int* p=1000;
printf("%d\n", (int)(p+sizeof(int))); // what is going on here?
does p point to 1000 or does p = the memory address 1000? If it is the former, could this be achieved achieved like this:
int dummyVariable = 1000;
int * p = &dummyVariable;
The declaration
int* p=1000;
makes p point to the address 1000.
While in the case of
int dummyVariable = 1000;
int * p = &dummyVariable;
you initialize dummyVariable to the value 1000 and make p point to dummyVariable.
Another way to look at it:
In the first case you have
Address 1000
|
v
+---+ +-----+
| p | --> | ??? |
+---+ +-----+
And in the second case you have
Address &dummyVariable
|
v
+---+ +----------------------------+
| p | --> | dummyVariable (value 1000) |
+---+ +----------------------------+
A third way of looking at it, is that the value of p is an integer (that just happens to be an address). In the first case p contains the value 1000, i.e. it's pointing to the address 1000.
In the second case the contents of p is &dummyVariable, i.e. it points to the location in memory where dummyVariable is stored.
As for the printout in the first example giving you the value 1016, that's because of how pointer arithmetic works: Whatever you add to a pointer is multiplied by the size of the base type. So if you have a pointer to int, then everything you add to that pointer will be multiplied by sizeof int.
In your case, the size of int is 4 bytes, so what you are doing is actually 1000 + 4 * 4 which is equal to 1016.
In your example, p is storing the memory address 1000, whatever that memory address is holding. In fact, p resides at another memory address, which, again stores the number 1000, which is a memory address, etc. Your second example is correct: The pointer p is assigned the memory address of dummyVariable, now if you modify dummyVariable or the *p (dereferencing the pointer), the changes will be applied to both (because they point to the same memory space).
int* p=1000;
p is a pointer pointing to memory location 1000.
printf("%d\n", (int)(p+sizeof(int)));
You are trying to access some memory here.( 1000 + sizeof(int))
Directly assigning some random address to a pointer as done here is not a good idea.
You should have got below mentioned warnings:
warning: initialization makes pointer from integer without a cast
warning: cast from pointer to integer of different size
The second part:
int dummyVariable = 1000;
int * p = &dummyVariable;
Here 1000 is a value and pointer p is pointing to a memory location holding 1000.
So both are diffrent.
Kinda of a noob so don't kill me here.
What's the difference between the following codes?
int *p; //As i understand, it creates a pointer to an variable of size int.
int *p[100]; //Don't really know what this is.
int (*p)[100]; // I have come to understand that this is a pointer to an array.
This is a pointer to an int:
int *p;
┌────┐
│int*│
└────┘
It should point at an int, something like this:
┌────┐
│int*│
└─┃──┘
▼
┌───┐
│int│
└───┘
This is an array of 100 pointers to int:
int *p[100];
That is, it gives you 100 pointers.
┌────┬────┬────┬────┬────┬────┬┄
│int*│int*│int*│int*│int*│int*│
└────┴────┴────┴────┴────┴────┴┄
Each pointer should point an int, perhaps like this:
┌────┬────┬────┬────┬────┬────┬┄
│int*│int*│int*│int*│int*│int*│
└─┃──┴─┃──┴─┃──┴─┃──┴─┃──┴─┃──┴┄
▼ ▼ ▼ ▼ ▼ ▼
┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐┌┄
│int││int││int││int││int││int││
└───┘└───┘└───┘└───┘└───┘└───┘└┄
Of course, there's no reason they can't all point at the same int, or whatever.
You may want to use an array of pointers if you want many pointers that you can easily
iterate over. You may, for example, dynamically allocate objects and have each pointer point at a different object:
p[0] = new int(0);
p[1] = new int(0);
// ...
Perhaps dynamically allocating ints isn't the best example, but I think the point is clear.
This is a pointer to an array of 100 int:
int (*p)[100];
That is, it gives you just 1 pointer:
┌───────────┐
│int(*)[100]│
└───────────┘
It should point at an array that contains 100 ints:
┌───────────┐
│int(*)[100]│
└─┃─────────┘
▼
┌───┬───┬───┬───┬───┬───┬┄
│int│int│int│int│int│int│
└───┴───┴───┴───┴───┴───┴┄
You will get a pointer to an array when you use the address-of operator (&) on the name of an array. For example:
int arr[100] = { /* some initial values */ };
int (*p)[100] = &arr;
Here, I've taken the address of the arr array, which gives me a pointer to that array. If you then want to access an element of the array, you have to dereference the pointer first: (*p)[3] will access element 3.
Side note:
Always remember that arrays are not pointers. As we have just seen, we can take the address of an array to get a pointer to it, just like any other (non-temporary) object in C++. The only special connection between arrays and pointers is that the name of an array can be implicitly converted to a pointer to the array's first element. That means the following is valid:
int arr[100] = { /* some initial values */ };
int* p = arr;
The pointer p will point at the first element in arr. Note that p is not a pointer to the array, but a pointer to an element of the array.
(Also note that there is no such thing as an array type function argument. If you write something like int p[] as a function argument, it is transformed by the compiler to be a int*.)
Sounds like you could use an introduction to the Spiral Rule.
Start at the variable and "spiral" your way around right to left:
+-------+
| +--+ | // So we have:
| | | | p // p
int * p | | * p // p is a pointer
^ ^ | | int * p // p is a pointer to an int
| +----+ |
+----------+
Next one:
+--------+
| +--+ | p // p
| | V | p[100] // p is an array of 100
int * p[100] | * p[100] // p is an array of 100 pointers
^ ^ | | int * p[100] // p is an array of 100 pointers to ints
| +----+ |
+-----------+
Finally, a new part of the rule, do anything in parenthesis first:
+-----+
| +-+ |
| ^ | | ( p) // p
int (* p) [100]; (*p) // p is a pointer
^ ^ | | (*p)[100] // p is a pointer to an array of 100
| +---+ | int (*p)[100] // p is a pointer to an array of 100 ints
+---------+
If you're online/have access to a computer, it's always usefule to use the cdecl.org site, but it's important to be able to read code offline as well, and this rule will let you do just that.
Kinda of a noob so don't kill me here
Working out what a type means in C can be tricky even for experts. No worries.
What's the difference between the following codes?
The other answers are good and I have no intention of contradicting them. Rather, here's yet another way to think about it. We need to define three things:
A variable is a thing that supports three operations. The fetch operation takes a variable and produces its current value. The fetch operation has no notation; you simply use the variable. The store operation takes a variable and a value, and stores the value in the variable. The address operation takes a variable and produces a pointer.
A pointer is a thing that supports one operation. The dereference operation, written as prefix *pointer, takes a pointer and produces a variable. (Pointers support other operations such as arithmetic and indexing -- which is a form of arithmetic -- but let's not go there.)
An array is a thing that supports one operation. The index operation takes an array and an integer and produces a variable. It's syntax is postfix: array[index]
OK, so now we come to your question. What does the declaration
int p;
mean? That the expression p is a variable of type int. Note that this is a variable; you can store things to p. What does the declaration
int *p;
mean? That the expression *p is a variable of type int. Now that we know that we can deduce what p is. Since *p is a dereference and produces a variable, p must be a pointer to int. What does the declaration
int *p[100];
mean? It means that *the expression *p[i] is a variable of type int provided that i is an integer value from 0 to 99. We got a variable out, but we could have gotten there from either the pointer or the array, so we have to figure out which. We consult the operator precedence table and discover that the indexing operator binds "tighter" than the dereferencing operator. That is:
*p[i]
is the same thing as
*(p[i])
and remember, that thing is a variable of type int. The contents of the parens are dereferenced to produce a variable of type int so the contents of the parens must be a pointer to int. Therefore
p[i]
is a pointer to int. How is that possible? This must be a fetch of a variable of type pointer-to-int! So p[i] is a variable of type pointer to int. Since this is an index operation, p must be an array of pointers to int.
Now you do the next one.
int (*p)[100];
means what?
int *p; --> Declares a pointer to an integer type.
int *p[100]; -->Declares an array of 100 pointers to integer type.
int (*p)[100]; --> Declares a pointer to an array of 100 integers.
Use cdecl for translating such types.