Suppose a and b are pointers,
My understanding is *--a = *--b means subtract 1 from a and b using pointer arithmetic, then dereference a and b and set them equal.
Is this equivalent to
--a;
--b;
*a=*b
Similarly, what is
*a++ = *b++;
equivalent to?
*––a = *––b
is logically equivalent to
tmpa = a - 1
tmpb = b - 1
*tmpa = *tmpb
a = a - 1
b = b - 1
with the caveat that the updates to a, b, and *tmpa can occur in any order, and those updates can even be interleaved. It’s also possible for the implementation to skip the temporaries and update the pointer values immediately:
a = a - 1
b = b - 1
*a = *b
but that’s not required or guaranteed. Similarly,
*a++ = *b++
is logically equivalent to
tmpa = a
tmpb = b
*tmpa = *tmpb
a = a + 1
b = b + 1
with the same caveats about the ordering of the updates to a, b, and *tmpa. Again, the implementation may skip using temporaries and evaluate it as
*a = *b
a = a + 1
b = b + 1
but again that’s neither required nor guaranteed.
*a++ = *b++;
dereference b and assign it to where a points. The ++ is the postfix operator, so the current value of *b will be assigned to *a, then both will be incremented.
If you keep this in a while loop, all the characters from b will be copied to a including the \0. This continues as long as *a++ = *b++ is not \0, at which time loop terminates.
while(*a++ = *b++);
Example :
#include <stdio.h>
int main()
{
char a_arr[30] = {0};
char b_arr[] = "Hello,World";
char *a = a_arr;
char *b = b_arr;
while(*a++ = *b++);
puts(a_arr);
puts(b_arr);
return 0;
}
Example
uint8_t *a = 1030; // POINTS TO ADDRESS 1030
uint8_t *b = 1020; // POINTS TO ADDRESS 1020
printf("%d", *(--a)); // PRINTS VALUE ON ADDRESS 1029
printf("%d", *(b++)); // PRINTS VALUE ON ADDRESS 1021
*(--a) subtracts one byte(one address) because pointer a points to one byte(it is uint8_t). After subtraction, it will read value from address.
*(--something) you can write as
uint32_t *c = 1050;
c -= 1; // SUBCTRACTS 4 BYTE ADDRESS FROM POINTER c
print("%d", *c);
Why 4 bytes you may ask? Because pointer c points to four byte(uint32_t or int32_t) data. You can get size of data in bytes with sizeof(variable).
In your case, lets say pointer a points to address 40. Pointer b points to address 50.
Address 39 holds value 1
Address 40 holds value 2
Address 50 holds value 10
Address 51 holds value 11
uint8_t *a = 40;
uint8_t *b = 50;
printf("%d", *(--a));
printf("%d", *(b++));
First printf will print value 1. Second printf will print value 50.
After printf pointer a points to address 39 and pointer b points to address 51
Reason? In first printf, it will first subctract one address(again, one because it points to one byte value), and then it will dereference value(that is why we use * for reading the value from pointer address).
In second printf, it will first dereference value and then move pointer one address up.
Related
So, I was messing around with pointers in C
int o = 10;
int x = 20;
int *pA = NULL;
pA = &o;
and after adding an integer to the
pointer
pA += x;
the address stored in the pointer changed from
000000000061FE18
to
000000000061FE68
After checking the value the address was pointing to using *pA the value was 0 and I could add an integer to this address using
*pA += x;
and *pA became equal to 20, but the value stored in variable o was still 10.
Could anyone explain what happened here?
pA += x; - The pointer pA itself is incremented by the value of x multiplied by the size of type pA is pointing to and is equal to the size of x, which is int.
So, assume sizeof(int) or sizeof(x) is 4 and x has the value of 20, you end up multiplying the pointer value of pA by 80 because 4 * 20 = 80, which is matching to your test results.
0x61FE68 - 0x61FE18 = 0x50 = 80d.
After adding an integer to the pointer
pA += x; .... (and) checking the value the address was pointing to using *pA the value was 0...
Since you incremented the pointer pA itself by 20 * sizeof(int) with pA += x;, pA points no longer to any valid object and beyond the bounds of the object it should point to.
To increment the pointer in this way invokes undefined behavior as well as dereferencing this pointer.
That it displayed 0 is just happen arbitrary to the situation. You can't rely on anything. The value can change already at the next execution.
... and I could add an integer to this address using *pA += x; and *pA became equal to 20.
The behavior is undefined as said above. pA does not point to any legally referenced object.
...but the value stored in variable o was still 30.
o isn't changed at all. With the first statement pA += x; you incremented the pointer itself, not the object o pA pointed to at the first place.
Could anyone explain what happened here?
You incremented the pointer pA by sizeof(int) * 20 with the first pA += x;. Everything else can't be really explained, because the behavior is just undefined.
Here you have a small program which should explain pointer arithmetic a bit.
#include <stdio.h>
#define PRINTDIFF(type, p1, p2) printf("sizeof(%s) = %zu p1=%p p2 = %p diff(bytes) = %zi \ndiff(objects) = %zi diff(bytes)/sizeof(%s) = %zi\n\n", \
#type, sizeof(type), \
(void *)(p1), \
(void*)(p2), \
((char *)(p2) - (char *)(p1)), \
(p2) - (p1),\
#type, \
((char *)(p2) - (char *)(p1)) / sizeof(type))
int main(void)
{
short s;
char c;
int i;
long long ll;
long double ld;
short *sp = &s;
char *cp = &c;
int *ip = &i;
long long *llp = ≪
long double *ldp = &ld;
PRINTDIFF(short, sp, sp + 10);
PRINTDIFF(char, cp, cp + 500);
PRINTDIFF(int, ip, ip + 5);
PRINTDIFF(long long, llp, llp + 5);
PRINTDIFF(long double, ldp, ldp + 5);
}
https://godbolt.org/z/4eP3rc
And the result:
sizeof(short) = 2 p1=0x7ffe0660eb76 p2 = 0x7ffe0660eb8a diff(bytes) = 20
diff(objects) = 10 diff(bytes)/sizeof(short) = 10
sizeof(char) = 1 p1=0x7ffe0660eb75 p2 = 0x7ffe0660ed69 diff(bytes) = 500
diff(objects) = 500 diff(bytes)/sizeof(char) = 500
sizeof(int) = 4 p1=0x7ffe0660eb70 p2 = 0x7ffe0660eb84 diff(bytes) = 20
diff(objects) = 5 diff(bytes)/sizeof(int) = 5
sizeof(long long) = 8 p1=0x7ffe0660eb68 p2 = 0x7ffe0660eb90 diff(bytes) = 40
diff(objects) = 5 diff(bytes)/sizeof(long long) = 5
sizeof(long double) = 16 p1=0x7ffe0660eb50 p2 = 0x7ffe0660eba0 diff(bytes) = 80
diff(objects) = 5 diff(bytes)/sizeof(long double) = 5
BTW when you learn you should experiment yourself writing the short programs which will help you understand the C language. There is no easy, effortless way of learning C
The new address pointed by a pointer, after a constant value is added to it, depends on the type it points to:
NewAddress = OldAddress + ConstantValue * sizeof ( Type )
So, in plain math, with pA += x, you have
new_address_pointed_by_pA = old_address_pointed_by_pA + x * sizeof( int )
And since x=20 and an integer in your machine is 4 bytes big, this becomes
new_address_pointed_by_pA = old_address_pointed_by_pA + 20*4 =
= old_address_pointed_by_pA + 80
That's exactly what you experience, as 0x61FE68 - 0x61FE58 = 0x50. Your addresses, in fact, are represented in hexadecimal format. So the new address is 0x50=80 beyond the old one, and that fits with the simple calculation I showed above.
What does that new address contain? Well, we don't know. It depends on the history of that specific memory location.
If it was never used, it's not surprising it contained 0. And it was also expected that after *pA = x it contained 20. And, again, it is not surprising at all that the location it was originally pointing remains unchanged.
But... with that assignment you could have raised a segmentation fault exception. An OS usually raises this signal when a memory location not assigned to your task is accessed.
So, pay attention when you play with pointers, making sure that any arithmetics performed on them leads to legal new values.
As per multiple sources, a pointer p points to a value when it is dereferenced. Thus, we may say that a pointer contains an address as it's value, and when the dereference operator (*) is used, the value at the address is returned.
A pointer may be assigned a value as follows:
int a = 90;
int *p = &a;
if we assign a pointer it's value as follows:
int *p;
*p = 60;
60 is alloted to p and causes undefined behavior upon dereferencing since 60 is not a valid address. (As per the answer to this question).
However, for the following code:
int a = 90;
int *p = &a;
printf ("p is %d \n",*p);
printf ("a is %d \n", a);
printf ("address is %p \n",p);
*p = 100;
printf ("p is %d \n",*p);
printf ("a is %d \n", a);
printf ("address is %p \n",p);
The following output is recieved :
p is 90
a is 90
address is 0028FED8
p is 100
a is 100
address is 0028FED8
ie, the expression *p = 100 changes the value at a, and not the value contained by p.
HOW ??????
*p = &a doesn't even compile. p is a pointer to int. It currently has an undefined value, therefore assigning anything to *p is undefined behaviour and would most likely crash. However, even if p did point to an int, you could only assign an int to *p, &a is a pointer to int, not an int, so this doesn't compile.
In your second example, *p = 60, the value of p is undefined, so you are trying to store 60 to an undefined location in memory. Instant crash. p isn't modified by this, so your explanation is wrong. p is not set to 60. You can't set p to an int. You can only set it to a pointer to int.
Correct:
p = &a;
*p = 60;
the code you wrote at the begining:
int *p;
int a = 90;
*p = &a;
is not valid, The asterisk (*) in line 1 indicate that it is a pointer, it is not the dereference operator as in line 3.
the following code:
int a = 90;
int *p = &a;
is equivalent to:
int a = 90;
int *p;
p = &a;
(p) is a pointer , and now is pointing at address of (a)
*p = 100;
so, you just assign a value to a, a = 100 .
and you are printing the same value from the same address.
You had asked:
ie, the expression *p = 100 changes the value at a, and not the value contained by p.
You can read the comment section for explanation of each line of C code and I'm not using exact address locations but using arbitrary ones for demonstration purposes:
int *p; // Stack variable pointer to integer type w/ p's address being 4 bytes # 0x00000000
int a = 90; // Stack integer variable `a` and initializing it to the value of 90 located # 0x00000040
*p = &a; // Dereferencing the pointer `p` to be equal to the address of `a` ... One would think
// that the address value of `a` 0x00000040 in hex would be stored into `a` which
// has the value of 64 in decimal, however this is not always the case and this should be
// undefined behavior, but can still compile and run depending on the compiler and architecture.
// It may run or crash or not even compile or build at all. Most compilers should throw an error.
*p = 100; // 'p' is located at 0x00000000 and contains the value 0x00000040 and by dereferencing it
// it will assign the value of 100 to the stack address location of 0x00000040. Thus this
// changes the value of `a` to 100
// These two statements are in a sense equivalent
*p = 100; a = 100;
// If one was to assign the address of `a` to `p` as such:
p = &a;
EDIT
// Therefor the statement `*p=100` will only work if the statement
// `p=&a` is defined and evaluated beforehand.
EDIT
Now as for the question based on the Title: "what does *p contain?" with the op's original code provided *p actually contains garbage or what ever was assigned to it upon declaration.
As per multiple sources, a pointer p points to a value when it is dereferenced.
Not quite. A pointer points to an object. Dereferecing a pointer produces that object. Using an object in a context where a value is needed produces the stored value.
int *p = &a;
The object that p now points to is a.
*p = 100;
Dereferencing p produces the pointed-to object, namely a. Since this is not a context where the stored value is needed, a's value isn't read, it remains the object a which is assigned the value 100.
Or, simply put, *p means a, therefore *p = 100 means a = 100.
I found an example of a pointer to array which to me doesn't make much sense, I was wondering if anybody would be able to help me?
int a[5] = 0,1,4,89,6;
int *p = a; 'p points at the start of a'
p[3] = 1; 'a[3] is now 6'
I'm not sure how the third line, p[3] = 1, works and how it causes a[3] = 6. Thanks for the help in advance.
It is bit incorrect. a[3] is 1, not 6.
Here are explanation line by line:
int a[5] = 0,1,4,89,6;
int *p = a; //'p points at the start of a'
p[3] = 1; //'a[3] is now 1 not 6'
First line initialize the array. I think there should be {} around numbers, but if compiles with you then is OK. This is how I believe it should be:
int a[5] = {0,1,4,89,6};
Second line create pointer to int p and initialize it to the address of a. Arrays and pointers are closely related in C, so now, you have 2 variables a and p pointing to one and same memory address.
Third line - you set p[3] to 1, this time you access p as array of int (it is possible because of that relationship between arrays and pointers). Because p and a points in same memory address, this means a[3] is now 1
Also remarks are incorrect, must be /* */ or //.
UPDATE :
David's comment is very important.
Arrays are sequential reserved memory capable to store several array values, in your case 5 int's.
A pointer is a pointer and may point everywhere they can point to int variable:
int a = 5;
int *b = &a;
or they can point to array as in your case. In both cases you will be able to use [], but in case it points to single value, any array subscript greater than zero will be wrong, e.g.
int a = 5;
int *b = &a;
*b = 4; // OK.
b[0] = 4; // OK.
b[1] = 4; // compiles correctly, but is **wrong**.
// it will overwrite something in memory
// and if program not crash,
// it will be security hole.
int x[10];
int *y = x;
*y = 4; // works correctly for y[0],
// but makes it difficult to read.
y[0] = 5; // OK
y[9] = 5; // OK
y[10] = 5; // compiles correctly, but is **wrong**.
// it is after last element of x.
// this is called **buffer overflow**.
// it will overwrite something in memory
// and if program not crash,
// it will be security hole.
UPDATE :
I recommend you check this article
http://boredzo.org/pointers/
#define N 20
int a[2N], i, *p, sum;
p = a;
/* p=a is equivalent to p = *a[0];
• p is assigned 300.
• Pointer arithmetic provides an alternative to array indexing.
• p=a; is equivalent to p=&a[=]; (p is assigned 300)
Here I am not getting how p=*a[0] and p=&a[0] are same? *a[0] references the element at the memory address.
Point 1
Do your understand, here int a[2N] is invalid code?
This 2N does not mean 2*N, rather this N is considered as a suffix (to integer literal 2) which is invalid.
Thanks to Mr # Lưu Vĩnh Phúc for the comment below.
If you wanted something like int a[40], write int a [2*N]
Point 2
p=*a[0] and p=&a[0] are same
No, they're not same. Actually, with the current code snippet, *a[0] is invalid.
FWIW, p = a; and p = &a[0]; are same, because the array name represents the base address, i.e., the address of the first element in the array.
p = a and p = &a[0] are indeed equivalent. In this case, you assign the address of the first element in the array to p (because the name of the array = pointer to its first element). p=*a[0] and p=&a[0] are not the same; *a[0] requires that a be an array of pointers, and dereferences its first member.
The meaning of p = &a[0] is as follows
For example :
int a[4];
a[0] a[1] a[2] a[3]
a --------> [ ][ ][ ][ ]
Equivalents
// Reference
&a[0] = a;
&a[1] = a+1;
...
&a[3] = a+3;
// Value
a[0] = *a
a[1] = *(a+1)
..
a[3] = *(a+3)
In arrays of C programming, name of the array always points to the first element of an array. Here, address of first element of an array is &a[0]. Also, a represents the address of the pointer where it is pointing i.e., base address . Hence, &a[0] is equivalent to a, so p = a or p = &a[0] both are same.
I have a piece of code written in C where some pointer arithmetic is performed. I would like to know how the output comes to be this?
#include <stdio.h>
int main()
{
char arr[] = "gookmforgookm";
char *ptr1 = arr;
char *ptr2 = ptr1 + 3;
printf ("ptr2 - ptr1 = %d\n", ptr2 - ptr1);
printf ("(int*)ptr2 - (int*) ptr1 = %d", (int*)ptr2 - (int*)ptr1);
getchar();
return 0;
}
Output is below:
ptr2 - ptr1 = 3
(int*)ptr2 - (int*) ptr1 = 0
Strictly speaking, you're invoking undefined behaviour and any result that the program produces is OK according to the C standard.
However, you're probably on a machine where sizeof(int) == 4 (as opposed to say, 2). Since there are 4 bytes to an integer, two addresses which are 3 bytes apart are part of the same integer, so the difference between the addresses is 0 * sizeof(int). You might find a different answer if you chose ptr1 = arr + 1;, or you might not. But that's the beauty of undefined behaviour - it would be 'right' either way.
After the subtraction you need to divide the result in the size of the pointed type.
(int*)ptr2 - (int*)ptr1 == (0x1000003 - 0x1000000) / sizeof(int)
(int*)ptr2 - (int*)ptr1 == (0x1000003 - 0x1000000) / 4 == 0
ptr1 and ptr2 are both char * type, that means one byte one pointer.
char *ptr2 = ptr1 + 3;
so
ptr2 - ptr1 = 3
Next, you cast both pointer to type int *, int type need 4 byte, so both pointer aim at the same int, both pointer have the same value through the memory align, you get the 0 result.
When you subtract two pointers, as long as they point into the same array, the result is the number of elements separating them.
Pointer Subtraction and Comparison
The memory addresses of the elements of the same array are always sequential. i.e
if the memory adress of myarray[0] is:
0x4000000
then the memory address of myarray[2] will definitely be
0x4000002
So when you store the address of arr into ptr1 assume it to be x
, and then when you make the address of ptr2, three units higher than ptr1, it will be x+3. So when you subtract ptr1 from ptr2 the answer will be:
(x+3) - x = 3
Hence the answer.
In the second printf() statement, if you want it to display the same result as above (3), you have to convert the pointer to int and not int*.
char *myvar; // given contents somewhere
int addr = (int)myvar; // addr now = the char pointer
So In your case:
printf ("(int)ptr2 - (int) ptr1 = %d", (int)ptr2 - (int)ptr1);