I have problem solving this problem, so if anyne had a similar problem it would help me a lot.
short y[2][3]={{0123},{0x12345}},*p=y[1];
printf("01:%x\n", y);
printf("02:%x\n", p);
printf("03:%x\n", sizeof(y));
printf("04:%x\n", sizeof(y[0]));
printf("05:%x\n", sizeof(&y[0]));
printf("06:%x\n", sizeof(*p));
printf("07:%x\n", sizeof(p++));
printf("08:%x\n", *p++);
printf("09:%x\n", *p);
return 0;
Can anyone explain to me why the printout is like this?
01:61ff10
02:61ff16
03:c
04:6
05:4
06:2
07:4
08:2345
09:0
My opinion:
01:Prints the address where the array y begins.
02:Prints the address of the pointer, which points to the second element of the array. Since we have 2 * 3 elements that are of type short, each subsequent element of the zero element will increase by 6.
03:Since we have 2 * 3 elements, which is equal to 6, but the elements of the type are short, so it will print hexadecimal c
04:the number of elements in the zero position is 3, but they are of the short type, so it prints 6
05:prints the sizeof addresses of the first element of the array which is 4
06:I don't know why it prints 2 here
07:Prints the sizeof of the pointer address which is 4, it will increase after printing
08:I do not understand
09:I do not understand
Can anyone explain why it prints like this?
OK, let's see:
#01: The address of y.
#02: The value of p, which holds the address of y[1], which is the second element of type short[3]. The size of a short is apparently 2 on your system, so the offset to #01 is 6.
#03: The size of the array y, 2 * 3 * sizeof (short) give 12, in hex c.
#04: The size of the element y[0], which is of type short[3]. 6, as you found.
#05: The size of the address of y[0], and apparently the size of an address is 4 on your system.
#06: The size of the object that p points to. This is a short, so 2.
#07: The size of the expression p++, which is an address, so 4. And no, p is not incremented, since the expression is not evaluated.
#08: The value of the object that p points to, which is y[1][0]. Since the initializing value of 0x12345 is an int too big to be stored in a short, it is truncated to 0x2345. After reading the value, p is incremented.
#09: The element p points to, which is y[1][1]. It was initialized to 0.
Notes:
You should have got warnings from your compiler:
The mentioned initializer is truncated.
The format for pointers/addresses is %p.
The type of the result of sizeof might not match the format %x.
You should take warnings seriously, they are always a hint that you most probably made an error.
N6) Sizeof(*p) is size of datatype pointed by p. p is pointer to short: so 2 bytes.
N8) p is pointer to short, it`s pointing to array element y[1][0].
y[1] and y[1][0] have the same memory address.
All array elements are short, 0x12345 truncates to 0x2345 upon array initialisation. So output is 2345.
Also, p++ increases pointer value to point to next short y[1][1].
N9) Because of p++ in step N8, pointer now points to y[1][1], which was initialised to 0 (by default, because init value not provided) - output is 0.
Related
I want to get the address difference between two elements in an array.
int vector[] = { 28, 41, 7 };
printf("%d\n", &vector[2]); // 1703652
printf("%d\n", &vector[1]); // 1703648
printf("%d\n", &vector); // 1703644
printf("%d\n", &vector[1] - &vector); // 1
The result I expect(Last Line) is 4 because the data type was int.
Further, each result of address has 4 differences.
But why is the result of
&vector[1] - &vector
1 and not 4?
And how do I get 4 by using subtraction operator?
pointer arithmetics in C language works on the type of the object. It does not matter how big the object is. The reference to the next object minus reference to the previous is always one object
So if we add 5 to the pointer it will point 5 objects ahead. If we increment the pointer it will reference the next object. It helps indexing and iterating across the objects.
When you printf the address (your format is wrong - you should use %p instead) it is printed in bytes. So the difference between the consecutive objects will be equal the size of the object (plus the optional padding).
And How to I get 4 by using subtraction operator???
Cast the pointers to the type which sizeof is one for example char.
(char *)&vector[1] - (char *)&vector
You can calculate the difference of pointers to byte-sized values by casting the pointers to char *:
printf("%d\n", (char*)&vector[1] - (char*)vector);
#include<stdio.h>
int main(){
int a1[]={6,7,8,18,34,67};
int a2[]={23,56,28,24};
int a3[]={-12,27,-31};
int *y[]={a1,a2,a3};
int **a= y;
printf("%d\n",a[0][2]);
printf("%d\n",*a[2]);
printf("%d\n",*(++a[0]));
printf("%d\n",*(++a)[0]);
printf("%d\n",a[-1][1]);
return 0;
}
When I run the above code output is 8,-12,7,23,8. But if i change the last 3 lines to
printf("%d\n",*(++a[2]));
printf("%d\n",*(++a)[1]);
printf("%d\n",a[-1][1]);
output is 8,-12,27,27,7. I'm unable to understand last printf statement. How does a[-1][something] is calculated ? And according to me *(++a)[1] should print 56 instead of 27 !
Pointers and array bases are in fact addresses in virtual memory. In C, they can be calculated into new addresses. Since the compiler knows the size of memory the pointer points to (e.g. int * points to 4 Bytes), a pointer +/- 1 means the address +/- the size (e.g. 4 Bytes for int).
The operator * means to get the value stored in the specified address.
Another trick here is the priorities of the operators. [] is calculated before ++.
If you understand what I mean above, your problem should be resolved.
according to me *(++a)[1] should print 56 instead of 27 !
++a increments a to the next int *, so after it pointed to y[0] equal to a1, it points to y[1] equal to a2. Then [1] in turn designates the next int * after y[1], i. e. y[2] equal to a3+1 (due to the preceding ++a[2]). Lastly, * designates the int which y[2] points to, i. e. a3[1] equal to 27.
#include <stdio.h>
int main(void){
int* p = NULL;
int y = 1;
p = &y;
printf("%p\n",p);
*(p+1) = 10;
printf("%p\n",p);
return 0;
}
outputs:
0x7ffe2368f2e4
0x7ffe0000000a
I do not know why p was changed here and the second one has "0000000a" which is 10 in the end, could you help me with that? thank you. I compiled it with gcc in linux.
The two variables y and p are allocated on the stack. Their storage is adjacent to each other, and looks like this:
y: <addr1> <val1> 4 bytes
p: <addr2> <val2> 8 bytes
Note that <addr2> is <addr1> + 4.
For your example, the actual addresses look like this:
y: 0x00007ffe2368f2e4 <value1> 4 bytes
p: 0x00007ffe2368f2e8 <value2> 8 bytes
After y = 1 and p = &y, the memory looks like follows:
y: 0x00007ffe2368f2e4 0x00000001 4 bytes
p: 0x00007ffe2368f2e8 0x00007ffe2368f2e4 8 bytes
p + 1 is value of p + sizeof(int), which is 0x00007ffe2368f2e4 + 4, which is 0x00007ffe2368f2e8, which is the address of p.
*(p + 1) = 10 sets 4 bytes at 0x00007ffe2368f2e8 to 10.
This is overwriting 4 bytes of a 8 byte value at 0x00007ffe2368f2e8, which is 4 bytes of the value of p.
0x7ffe 2368f2e4
0x7ffe 0000000a ------> this is the lower 4 bytes set to 10 i.e. 0xa
What cause the change of address the pointer points to?
TL;DR - undefined behavior.
To elaborate, in your code,
*(p+1) = 10;
invokes undefined behavior as you try to access a a memory out of bound. Kindly note, segmentation fault in only one of the many possible side-effects of UB.
Once your code invokes UB, nothing, absolutely nothing is guaranteed.
Also, FWIW, to print a pointer, you should be casting the pointer to void* before using that as an argument to %p.
As others have said, this statement invokes undefined behavior:
*(p+1) = 10;
Since prior to this statement, p contains the address of y, which is of type int. So the above statement writes to an area of memory which is not y.
As for an explanation of what actually happened, it appears that p appears right after y on the stack. So when you do *(p+1) = 10;, it writes to the sizeof(int) bytes after y on the stack, which happens to be where p lives.
Based on the fact that the initial value of p is 0x7ffe2368f2e4, that tells us that sizeof(int *) is at least 6 bytes, most likely 8 (i.e. 64 bit). With the value changing to 0x7ffe0000000a after the assignment, we see that the 4 low-order bytes of p were modified. This would make sense if sizeof(int) is 4 and you're working in a little-endian architecture. So the assignment ends up setting the first 4 bytes of p (the low order bytes) to the value 10 while leaving the rest (the high order bytes) unchanged.
That's what happened in your particular case. There is no guarantee that this behavior will be consistent across different machines, compilers, or operating systems. In other words, undefined behavior.
This statement
*(p+1) = 10;
changes the pointer because it overwrites the memory occupied by the pointer.
As you can see from the output values
0x7ffe2368f2e4 0x7ffe0000000a
this part 0x0000000a of the value 0x7ffe0000000a exactly equal to 10 that is assigned to the memory at address p + 1
So at the address p + 1 there is the pointer p itself.
If the sizeof( int ) is equal to 4 then 0x7ffe2368f2e4 is the address of y and 0x7ffe2368f2e8 is the address of the memory occupied by pointer p itself that is overwritten.
Another way to think about this is as y being like an array of 1 integer (that is only y[0] exists. The code:
*(a+i) equals a[i]
by definition. So, since:
p = &y
then:
*(p+1) equals y[1]
and accessing that which does not exist is undefined behavior. That means anything can happen, but the two most likely things are (1) you access some other variable (what happened to you) or (2) the program gets a segmentation fault.
Consider the following programm,
#include<stdio.h>
int main()
{
int marks[]={20,65,45,68,89};
int *x,*y;
x=&marks[2];
y=&marks[4];
printf("%p\n%p\n"x,y);
printf("%p\n%p\n",y-x,*y-*x);
return 0;
}
When I want to print out the value of y-x, the console should give me a output equal to the difference between the addresses of the corresponding pointers. After all, we know that x and y are having addresses ('some integer value'). However it is not so. Why?
Pointer subtraction does not simply subtract the addresses but rather return the distance between two array elements (in terms of arary elements).
So y - x is not a pointer but an integer of the value 2 - and to printf it, you shold use %d formatting, now %p.
If you print the differences using %p, you will probably get something that's a bit hard to read.
The proper way is probably to use %lu, and cast:
printf("%lu\n", (unsigned long) (y - x));
Printing the integer quantity *y - *x as %p seems totally confused.
The result of subtraction of 2 pointers in the same array is the distance between those pointers in array, so y-x should equal 2 in your example.
To get difference between addresses cast them to some integer before substracting:
printf("%d",(size_t)y-(size_t)x);
y-x will evaluate to 2 - since the distance in between them is 2 ints.
If you print e.g. (char *) y - (char *) x you will get the distance in characters
the console must give me a output equal to the difference between the addresses of the corresponding pointers
... and it does. For me, it outputs 2. If you compare the addresses, you see that they are separated by 8 bytes, which is 2 ints, which is the answer you sought.
I have an array as:
int x[3][5]={
{1,2,3,4,5},
{6,7,8,9,10},
{11,12,13,14,15}
};
What does *x refer to?
*(*x+2)+5 refer to "8".How does that happen?
Is *(*x+2) same as *(*x)+2?
What if I do:
*n=&x;
Where is the pointer n pointing to? if it would have been only x and not an & then it would have been the base address.What for now?
*x is a dereference operation. In other words, "give me what x is pointing at". Since this is an array (of arrays), dereferencing x will give you the first array. This is equivalent to the array access syntax of x[0].
*(*x+2)+5 is equivalent to x[0][2] + 5, which gives you 8. This is because:
*x is the same as x[0] (see #1) and *(x + 2) is the same as x[2]. Once you've done two dereferences, you've gone from an array of arrays (similar to a double-pointer) to an array (single pointer) to an actual number (the third item in the first array). Then, it's just 3 + 5 = 8.
*(*x+2) is equivalent to x[0][2] (see #2), which is 3 (third element in array). However, *(*x) + 2 gives you x[0][0] + 2 (first element in array plus 2), which is 1 + 2 = 3. Same answer, but very different way of getting it.
*x refers to the first array ({1,2,3,4,5}), and is equivalent to x[0]. Adding one to x move to the next array, so *(x+1) would refer to the second array, and would be equivalent to x[1].
*(*x + 2) is therefore the third element in the first array, which is 3. This means that *(*x + 2) + 5 is equal to 8.
The parentheses matter a lot, for example *(*(x+2)) would be the first element in the third array.
*(*x + 2) results in the same value as *(*x) + 2, but does not use the same element of the array.
x is a int** so it's like if you have a first layer of pointers and everyone of them point to a int* (so an array of int).
When you write *x you obtain the address that contains the address which points to the first row of your multi dimensional array.
So if you take (*x + 2) if it's like referencing to first row of you array and then add 2 to the address: you obtain the address of the third element of first row. But since this is still a pointer you add an external *(*x+2) to exactly obtain third element of first row.
Think of it this way:
typedef int Int5[5];
Int5 x[3];
x is an array with 3 elements. Each of those three elements is a array of 5 ints.
What does *x refer to?
x is the same as '&x[0]so*xis the same asx[0]` which is the first 5-element array.
*(*x+2)+5 refer to "8". How does that happen?
*x is x[0], and x+2 is &x[2] so *x+2 is &x[0][2] and *(*x + 2) is x[0][2] which happens to be 3. Add five to that for 8.
Is *(*x+2) same as *(*x)+2?
*(*x+2) is x[0][2] as we've seen. *(*x) would be x[0][0], so *(*x)+2 is x[0][0]+2. So both *(*x+2) and *(*x)+2 end up equaling 3, but that is merely a coincidence.
All the answers are 100% correct and I will just generally explain this part *n=&x in general terms
&x generates a pointer (variable containing an address of another variable) and stores it in n and to get the value pointed to by n, you *n called de referencing or indirection.
To really understand this pointer business, you need to study how computers store values in memory.