issue in double pointer address addition - c

I have got one issue from a open source code in pointers side, which i have tried to replicate in this below small snippet.
int main()
{
int **a=0x0;
printf ("a = %d Add = %d\n", a, a+75);
return 1;
}
Expectation is to get 75/0x4B but this code gives 300 in 32 bit and 600 in 64 bit machines.
Output:
a = 0 Add = 600
But the ideology behind to access the added position i.e 75th position in Hash table.
So it should be
printf ("a = %d Add = %d\n", a, sizeof (a)+75);
But i couldn't able to guess why this 300 or 600 output. could anyone please point out?
I went till a point where there is some left shift internally happening since:
75 - 1001011
600 - 1001011000.
Solutions are appreciated. Thanks in advance.

Pointer arithmetic is always done using the size of what is pointed to. In your case a is a pointer to a pointer to int, so the unit size is sizeof(int*) which in your case seems to be 4 (32 bits). 4 * 75 = 300.
More precisely, a + 75 adds the byte offset sizeof(*a) * 75 (note the dereferencing of a) to the pointer. What happens is that you are effectively doing &a[75], i.e. you're getting a pointer to the 75:th element.
On a slightly related note, when you print pointers with printf you should be using the format "%p", and casting the pointers to void *. See e.g. this printf (and family) reference.
As for the different size on 32 and 64 bit systems, it's to be expected. A pointer on a 32-bit system is typically 32 bits, while on a 64-bit system its 64 bits.

The program behaviour is undefined:
The format specifier %d is not valid for pointer types: use %p instead.
Pointer arithmetic is only valid within and one past the last element for arrays, or one past the address of the scalar for scalars. You can't read a + 75.

First of all, use %p for printing pointers and %zu for a sizeof result.
That said, check the type of a, it is int **, which is the size of a pointer. And, it depends on the platform / compiler.
Pointer arithmetic honors the data type, so the initial pointer is always incremented based on the LHS data type.

Related

Why address of i+2 is not 653064?

I'm learning pointers in C. I'm having confusion in Pointer arithmetic. Have a look at below program :
#include<stdio.h>
int main()
{
int a[] = 2,3,4,5,6;
int *i=a;
printf("value of i = %d\n", i); ( *just for the sake of simplicity I have use %d* )
printf("value of i+2 = %d\n", i+2);
return 0;
}
My question is if value of i is 653000 then why the value of i+2 is 653008 As far as I know every bit in memory has its address specified then according to this value of i+2 should be 653064 because 1 byte = 8 bit. Why pointer arithmetic is scaled with byte why not with bit?
THANKS in advance and sorry for my bad English!
As far as I know every bit in memory has its address specified
Wrong.
Why pointer arithmetic is scaled with byte why not with bit?
The byte is the minimal addressable unit of storage on a computer, not the bit. Addresses refer to bytes - you cannot create a pointer that points to a specific bit in memory1.
Addresses refer to *bytes*
|
|
v _______________
0x1000 |_|_|_|_|_|_|_|_| \
0x1001 |_|_|_|_|_|_|_|_| > Each row is one byte
0x1002 |_|_|_|_|_|_|_|_| /
\_______ _______/
v
Each column is one bit
As others have explained, this is basic pointer arithmetic in action. When you add n to a pointer *p, you're adding n elements, not n bytes. You're effectively adding n * sizeof(*p) bytes to the pointer's address.
1 - without using architecture-specific tricks like Bit-banding on ARM, as myaut pointed out
You should read about the pointer arithmetic.link given in the comment.
While incrementing the position of pointer , that will incremented based on the data type of that pointer.In this case i+2 will increment the byte into
eight bytes.
Integer is four bytes.(system defined). So i+2 will act as i+(2*sizeof(int)). So it will became i+8. So the answer is incremented by eight.
Addresses are calculating by the byte. Not the bit. Take a character pointer. Each byte having the 255 bits.
Consider the string like this. `"hi". It will stored like this.
h i
1001 1002
Ascii value of h is 104. It will be stored in one byte. signed character we can store positive in 0 to 127. So storing the one value we need the one byte in character dataype. Using the bits we cannot store the only value. so the pointer arithmetic is based on bytes.
When you do PTR + n then simple maths will be like
PTR + Sizeof(PTR)*n.
Here size of integer pointer is 4 Byte.

formatter size in printf()

Regarding question Why do I have to specify data type each time in C? and my earlier question how to read memory bytes one by one in hex(so without any format) with printf()
Is it possible to clarify the below question for me?
int32_t a[3]={21,3,1000031};
char* p1=&a[0]; /* char is 1-bye and &a[0] is 0x0004 for example */
printf("p1 in hex=%x\n",*p1); /* 4 bytes starting from word-aligned address p1 */
printf("(p1+3)=%d",(p1+3)); /* 4 bytes starting from a NON word-aligned address?* line 2 printf */
printf("p1+3=%p",p1+3) /* line 3 print*/
%x and %d ALWAYS tell printf to use int format which in my pc is a 4-byte? am i right?
(p1+3) is a non-word aligned address Ox004+3=0x007,so what does printf() show in this case?in another way, which bytes are concerned by line 2 printf?
also, %p formatter(void *) does it need 1 byte to read(because of char)or since we talk about pointers and they always take 4 bytes(one-word)?
to sum up my questions, %d %x %p,.. do they read a constant size(depending on pc) from memory or it depends on what are the size of their corresponding arguments?
Variadic parameters, just like all other parameter passing in C, is pass-by-value only. There's no address of anything going on in your case. In some cases you're printing the value of a pointer variable, though. I'll try to explain in order:
First:
printf("p1 in hex=%x\n",*p1);
Prints whatever *p1 is as a hex number. That's either 15 or 0, depending on whether you have a little- or big-endian machine, respectively.
Next:
printf("(p1+3)=%d",(p1+3));
Will try to print whatever p1 + 3 is as a decimal number. Since p1 is a pointer, that's not really a sane thing to do, and technically this statement causes undefined behaviour. You should be using %p to print a pointer. Assuming pointers and int are the same size on your machine, you'll probably get some number, but probably not a really meaningful one.
Last:
printf("p1+3=%p",p1+3)
%p prints a pointer type, so this line is correct. You'll (probably) get the same value as in #2, except in hexadecimal format. That's all machine/implementation-specific, though.
As to your other questions:
%x and %d ALWAYS tell printf to use int format which in my pc is a 4-byte? am i right?
%x is for unsigned int and %d is for int. The %x will give you hexadecimal output, and the %d decimal output. If int is a four-byte type on your machine, they'll both print the corresponding 4 bytes-worth of arguments that you passed.
(p1+3) is a non-word aligned address Ox004+3=0x007,so what does printf() show in this case?in another way, which bytes are concerned by line 2 printf?
Since you're printing the pointer value itself, the alignment is meaningless. You shouldn't be using %d to do it though (as mentioned above). The address in question is probably not 7, either... I'm not really sure where you got that from.
also, %p formatter(void *) does it need 1 byte to read(because of char)or since we talk about pointers and they always take 4 bytes(one-word)?
%p must be paired with a void * argument, as you say. It will will print the appropriate size for the pointer type on your machine (sounds like 4 bytes in your case).
to sum up my questions, %d %x %p,.. do they read a constant size(depending on pc) from memory or it depends on what are the size of their corresponding arguments?
They don't necessarily read anything from memory - that depends on how your ABI works and what the calling convention is for variadic functions your machine. You have to match types between the format specifiers and the corresponding variables, or else you'll cause undefined behaviour.
I don't think your code shows clearly what you want to ask, but to answer your sum-up question:
%d %x %p,.. do they read a constant size(depending on pc) from memory or it depends on what are the size of their corresponding arguments?
They read the size depends on the size of specific type on the machine. For example, for a 32-bit machine, %d will read 4 bytes, because it assumes the variable is an int.
I think this piece of code shows the general idea:
int a = 1089;
printf("%c\n", a); // prints "A" on a little-endian machine
printf("%d\n", a); // prints "1089"

How are pointers stored in memory?

I'm a little confused about this.
On my system, if I do this:
printf("%d", sizeof(int*));
this will just yield 4. Now, the same happens for sizeof(int). Conclusion: if both integers and pointers are 4 bytes, a pointer can be safely "converted" to an int
(i.e. the memory it points to could be stored in an int). However, if I do this:
int* x;
printf("%p", x);
The returned hex address is far beyond the int scope, and thus any attempt to store the value in an int fails obviously.
How is this possible? If the pointer takes 4 bytes of memory, how can it store more than 232?
EDIT:
As suggested by a few users, I'm posting the code and the output:
#include <stdio.h>
int main()
{
printf ("%d\n", sizeof(int));
printf ("%d\n", sizeof(int*));
int *x;
printf ("%d\n", sizeof(x));
printf ("%p\n", x);
}
The output:
4
4
4
0xb7778000
C11, 6.3.2.3, paragraphs 5 and 6:
An integer may be converted to any pointer type. Except as previously specified, the
result is implementation-defined, might not be correctly aligned, might not point to an
entity of the referenced type, and might be a trap representation.
Any pointer type may be converted to an integer type. Except as previously specified, the
result is implementation-defined. If the result cannot be represented in the integer type,
the behavior is undefined. The result need not be in the range of values of any integer
type.
So the conversions are allowed, but the result is implementation defined (or undefined if the result cannot be stored in an integer type). (The "previously specified" is referring to NULL.)
In regards to your print statement for a pointer printing something larger than what 4 bytes of data can represent, this is not true, as 0xb7778000 is within range of a 32 bit integral type.
The returned hex address is far beyond the int scope, and thus any attempt to store the value in an int fails obviously.
4
4
4
0xb7778000
And 0xb7778000 is a 32-bit value, so an object of 4 bytes can hold it.
No, they cannot be "safely" converted. Certainly they use the same amount of storage space, but there is no guarantee that they interpret a number of set bits in the same manner.
As for the second question (and one question per question please), there is no guaranteed size for int, or for a pointer. An int is roughly the optimum size of data transfer on the bus (also known as a word). It can differ on different platforms, but must be relatively (equal or) larger than a short or char. This is why there are standard definitions for MAX_INT, but not a standard "value" for the definition.
A pointer is roughly the number of bits wide as necessary to access a memory location. The old original PC's had a 8 bit bus, but a 12 bit pointer (due to some fancy bit-shifting) to extend it's memory range past its bus size.

Pointer Arithmetic In C

Consider the following code fragment:
int (*p)[3];
int (*q)[3];
q = p;
q++;
printf("%d, %d\n", q, p);
printf("%d\n", q-p);
I know that pointer arithmetic is intelligent, meaning that the operation q++ advances q enough bytes ahead to point to a next 3-integers-array, so it does not surprises me that the first print is '12, 0' which means that incrementing q made it larger in 12.
But the second print does surprises me. It prints 1!
So why would it print 1 instead of 12? it just puzzles me.
Like the ++ increment operator, the - subtraction operator with pointers also takes into account the size of the objects being pointed to. Specifically, the result returned is the number of bytes difference in the pointer values divided by the size of the pointed-to object (12, in your example). So the difference is 12 bytes, divided by size 12, or 1.
If you really want to know the difference cast each pointers to a (char*) and then to (int) and then subtract. That should give you the answer.
This code gives you the absolute value:
printf("%d\n", abs((int)((char*)q) - (int)((char*)p)));
Remember to include math.h.
Edit:
As pointed out in a comment we don't need a double cast. Casting each pointerpointer to an int and then subtracting gives the same answer as the (unecessary) double casting above.
printf("%d\n", abs((int)(q) - (int)(p)));

C array address confusion

Say we have the following code:
int main(){
int a[3]={1,2,3};
printf(" E: 0x%x\n", a);
printf(" &E[2]: 0x%x\n", &a[2]);
printf("&E[2]-E: 0x%x\n", &a[2] - a);
return 1;
}
When compiled and run the results are follows:
E: 0xbf8231f8
&E[2]: 0xbf823200
&E[2]-E: 0x2
I understand the result of &E[2] which is 8 plus the array's address, since indexed by 2 and of type int (4 bytes on my 32-bit system), but I can't figure out why the last line is 2 instead of 8?
In addition, what type of the last line should be - an integer or an integer pointer?
I wonder if it is the C type system (kinda casting) that make this quirk?
You have to remember what the expression a[2] really means. It is exactly equivalent to *(a+2). So much so, that it is perfectly legal to write 2[a] instead, with identical effect.
For that to work and make sense, pointer arithmetic takes into account the type of the thing pointed at. But that is taken care of behind the scenes. You get to simply use natural offsets into your arrays, and all the details just work out.
The same logic applies to pointer differences, which explains your result of 2.
Under the hood, in your example the index is multiplied by sizeof(int) to get a byte offset which is added to the base address of the array. You expose that detail in your two prints of the addresses.
When subtracting pointers of the same type the result is number of elements and not number of bytes. This is by design so that you can easily index arrays of any type. If you want number of bytes - cast the addresses to char*.
When you increment the pointer by 1 (p+1) then pointer would points to next valid address by adding ( p + sizeof(Type)) bytes to p. (if Type is int then p+sizeof(int))
Similar logic holds good for p-1 also ( of course subtract in this case).
If you just apply those principles here:
In simple terms:
a[2] can be represented as (a+2)
a[2]-a ==> (a+2) - (a) ==> 2
So, behind the scene,
a[2] - a[0]
==> {(a+ (2* sizeof(int)) ) - (a+0) } / sizeof(int)
==> 2 * sizeof(int) / sizeof(int) ==> 2
The line &E[2]-2 is doing pointer subtraction, not integer subtraction. Pointer subtraction (when both pointers point to data of the same type) returns the difference of the addresses in divided by the size of the type they point to. The return value is an int.
To answer your "update" question, once again pointer arithmetic (this time pointer addition) is being performed. It's done this way in C to make it easier to "index" a chunk of contiguous data pointed to by the pointer.
You may be interested in Pointer Arithmetic In C question and answers.
basically, + and - operators take element size into account when used on pointers.
When adding and subtracting pointers in C, you use the size of the data type rather than absolute addresses.
If you have an int pointer and add the number 2 to it, it will advance 2 * sizeof(int). In the same manner, if you subtract two int pointers, you will get the result in units of sizeof(int) rather than the difference of the absolute addresses.
(Having pointers using the size of the data type is quite convenient, so that you for example can simply use p++ instead of having to specify the size of the type every time: p+=sizeof(int).)
Re: "In addtion,what type of the last line should be?An integer,or a integer pointer??"
an integer/number. by the same token that the: Today - April 1 = number. not date
If you want to see the byte difference, you'll have to a type that is 1 byte in size, like this:
printf("&E[2]-E:\t0x%x\n",(char*)(&a[2])-(char*)(&a[0]))

Resources