Add operation on pointer - c

int a[3];
int *j;
a[0]=90;
a[1]=91;
a[2]=92;
j=a;
printf("%d",*j);
printf("%d",&a[0])
printf("%d",&a[1]);
printf("%d",*(j+2));
here the pointer variable j is pointing to a[0],which is 90;and address of a[0] is -20 is on my machine. So j is holding -20.
And the address of a[1] is -18. So to get next variable I should use *(j+2). because j+2 will result in -18. but this is actually going on. To access a[1]. I have to use *(j+1). but j+1=-19. Why is j+1 resulting in -18 ?

Addresses are unsigned. You're printing them as if they were an int, but they're not an int. Use "%p" as the format specifier. That's how you print the address of a pointer.
Additionally, pointer arithmetic is different than the arithmetic you are used to. Internally, adding one to a pointer p increments the address by sizeof *p bytes, i.e., it increments the to the next object.
This is convenient as it saves the programmer from having to always use sizeof when performing arithmetic on a pointer (rarely do you actually want to increment by something other than sizeof *p. When you do, you cast to a char* first.)

pointer addition is not same as simple addition.
It depends on what type of variable the pointer is pointing.
In your case it's an int whose size is machine dependent (you can check of doing sizeof(int)).
So when adding a number to pointer like (j+i) it internally converts to (j+i*sizeof(datatype)) so when you type (j+2) the address is increased the 4 times (assuming int to be 2 bytes) which is not the intended result.
(j+1) will give you the right result (it's like saying point to the next element of int type of data)

Actually the pointer logic works on the basis of the pointer type since integer pointer type moves by size of integer on your machine it moves by the 2 bytes on your machine so p+1 = p+(sizeof(type of pointer))

*(x+y) is always exactly equivalent to x[y] (or y[x]). So to print a[1], you want *(j + 1) (or just j[1]). Note that, in a[1], a is converted to a pointer ... there's no difference between the way a is handled and the way j is handled here.

Related

Get Product without using * operator hack-y way

Can someone please help me understand how does following logic resolves in obtaining product of a and b?
int getProd(int a, int b){
return (uintptr_t)&((char (*) [a])0x0)[b];
}
Suppose we have a pointer p, which points to objects of size a.
If we then say p + b, we're asking for a pointer to the b'th object past where p points.
So the actual new pointer value (on a byte-addressed machine, anyway), is going to be scaled by a, that is, the size of the pointed-to objects. That is, "under the hood", the compiler is going to do something more like p + b * a.
So we can see the multiplication a * b is happening -- but then it's getting added to the original value of p.
So if we use an initial value of 0, we'll get just a * b. And that's what the hacky getProd function is doing.
Let's break it down:
0x0
The value 0, also known in pointer contexts as a null pointer. [Footnote: there's more complexity to this definition, but let's not worry about that for the moment.]
char (*) [a]
This is a type: "pointer to char array of size a.
(char (*) [a])0x0
This is a cast: take that null pointer, cast it to the type "pointer to array [a] of char".
((char (*) [a])0x0)[b]
Take that pointer, imagine it points to an array, and fetch the b'th element of that array. Since array indexing is the same as pointer arithmetic, this will end up computing 0 + a * b.
&((char (*) [a])0x0)[b];
We had a reference to the b'th element of the "array". Now compute a pointer to that element. That pointer should literally have the value 0 + a * b.
(uintptr_t)&((char (*) [a])0x0)[b];
Finally, take that pointer and cast it to an integer type.
Now, with all of this said, it must be pointed out that this is a hack. Writing code to perform arithmetic on null pointers in this way is highly problematic. It might be almost-but-not-quite-legal; it might be legal-but-just-barely-legal. You could argue for hours about which side of the line the answer falls on.
In this case, of course, it's an academic argument, because no one would ever seriously propose doing multiplication this way.
This code invokes undefined behavior by performing pointer arithmetic on an invalid pointer. That being said, here's what it's attempting to do.
(char (*) [a])0x0 is casting the value 0 to a pointer to an array of size a of char, giving you a pointer to an object that takes up a bytes.
Then with &((char (*) [a])0x0)[b] it uses array indexing to get the b element this pointer points to and takes its address.
Also, because an expression of the type E1[E2] is exactly the same as *(E1 + E2), this means the prior expression is the same as &(*((char (*) [a])0x0) + b), and because & followed by * cancel out this is the same as ((char (*) [a])0x0) + b. So there's no dereferencing of an invalid pointer.
Because pointer arithmetic increments the value of a pointer by the offset times the element size, you now have a pointer whose numeric value is a*b. That value is then converted to an integer type and returned.
Where the undefined behavior comes into play is in the implicit + operator in the array indexing. Pointer arithmetic is only valid if the original pointer and the result of the addition both point to valid object (or one element past the end of an array of objects). Since 0 is not a valid address, this is UB.
Technically this is undefined behavior. But the intended functionality that this code might resolve assuming a naive compiler logic is as following.
((char (*) [a])0x0) - this takes an address 0x0 and is casting it to a pointer to array of a char elements, that is a pointer to an object of size a bytes.
Now, according to C pointer arithmetic any operation (addition/subtraction) with this pointer will be performed in the multiples of a.
Next, it is taking the b offset of this pointer. As we know, p[b] is equivalent to *(p + b) for any pointer p. In our case p is equal to 0x0 and is a pointer to an object of size a. Therefore p + b will have a numerical value of 0x0 + b * sizeof(*p) or 0x0 + a * b. Which is exactly a * b.

Why does this expression come out to 4 in C?

So this expression comes out to 4:
int a[] = {1,2,3,4,5}, i= 3, b,c,d;
int *p = &i, *q = a;
char *format = "\n%d\n%d\n%d\n%d\n%d";
printf("%ld",(long unsigned)(q+1) - (long unsigned)q);
I have to explain it in my homework and I have no idea why it's coming out to that value. I see (long unsigned) casting q+1, and then we subtract the value of whatever q is pointing at as a long unsigned and I assumed we would be left with 1. Why is this not the case?
Because q is a pointer the expression q+1 employs pointer arithmetic. This means that q+1 points to one element after q, not one byte after q.
The type of q is int *, meaning it points to an int. The size of an int on your platform is most likely 4 bytes, so adding 1 to a int * actually adds 4 to the raw pointer value so that it points to the next int in the array.
Try printing the parts of the expression and it becomes a bit clearer what is going on.
printf("%p\n",(q+1));
printf("%p\n",q);
printf("%ld\n",(long unsigned)(q+1));
printf("%ld\n",(long unsigned)q);
It becomes more clear that q is a pointer pointing to the zeroth element of a, and q+1 is a pointer pointing to the next element of a. Int's are 4 bytes on my machine (and presumably on your machine), so they are four bytes apart. Casting the pointers to unsigned values has no effect on my machine, so printing out the difference between the two gives a value of 4.
0x7fff70c3d1a4
0x7fff70c3d1a0
140735085269412
140735085269408
It's because sizeof(int) is 4.
This is an esoteric corner of C that is usually best avoided.
(If it doesn't make sense yet, add some temporary variables).
BTW, the printf format string is incorrect. But that's not why it's outputting 4.

How do variable types affect pointer arithmetic work in C?

I'm having trouble understanding pointer's arithmetic.
Let int B=0, *p=&B, **V=&p and sizeof(int)=4, sizeof(*int)=8
What does the instruction (*V)[1] do?
To me, what I see is that (*V)[1] is equivalent*(*V+1), so what should happen is, we dereference V (which is a pointer to a pointer to an int) and sum 1 to the content of that variable, which is an address. That variable is a pointer and we're assuming sizeof(*int)=8, so in theory we should sum 1 * sizeof(*int) (which is 8) to whatever address is stored in the pointer p to which the pointer V points.
The solution, however, says to sum 4 (1 + sizeof(int)). Is it wrong or is my thinking wrong?
The solution you reference is correct.
The expression *V has type int *, so it points to an array of 1 or more int. So because it points to an int, when pointer arithmetic happens the size of the datatype it point to (sizeof(int), i.e. 4) is multiplied by the given value (1). So if you were to print the values of *V and *V + 1 you would see that they differ by 4.
There is however a problem with (*V)[1], equivalently *(*V + 1). Since *V points to B, *V + 1 points one element past B. This is legal since a pointer can point to one element past the end of an array (or equivalently a single object which is treated as an array of size 1). What is not legal however is to dereference that pointer. Doing so invokes undefined behavior.
(*V)[1] is indeed equivalent to *(*V+1).
Since V is &p (by initialization), *V is p. So we have *(p+1).
Note that both *V and p have type int *. They point to an int, so p+1 points to “the next” int.
Since p points to B (by initialization), and B is a single int, p+1 points just past the end of B (where the “next int” would be if we had an array of int there instead of a single int).
This “just past the end of B” is allowed for a pointer, and it is the location your source refers to for the solution that (*V)[1] effectively adds four bytes to the location that *V points to.
However, while it is allowed to refer to one past the end of B, the C standard does not define the behavior of attempting to access an object there. (*V+1) is a defined pointer, but *(*V+1) is not a defined expression for an object at that location. Its behavior is not defined by the C standard.

C - What does int *p; p=15; does?

What is the difference between these two code samples? When I print the variable p, it prints the assigned value like below.
int *p;
p = 51;
printf("%d",p);
Output: 51
When I try to assign p=15, am I making memory address "15" in the ram as a pointee to the pointer p? When I try to add int c = 5 +p; it gives output as 71. Why am I getting 71?
I thought that the memory address "15" could store any information of the OS, programs, etc. But it exactly stores int for precise. Though I change the value p = 150; it gives int . How is that possible? What's happening under the hood?! I really don't understand.
Your code is illegal. Formally, it is not C. C language prohibits assigning integral values to pointer types without an explicit cast (with the exception of constant 0)
You can do
p = (int *) 51;
(with implementation-defined effects), but you cannot do
p = 51;
If your compiler allows the latter variant, it is a compiler-specific extension that has nothing to do with standard C language.
Typically, such assignment makes p to point to address 51 in memory.
On top of that, it is illegal to print pointer values with %d format specifier in printf. Either use %p or cast pointer value to proper integer type before using integer-specific format specifiers.
So you're telling that pointer that it points to 0x15. Then, you tell printf to print it as a decimal integer, so it treats it as such.
This reason this works is that on a 32 bit system, a pointer is 4 bytes, which matches the size of an int.
p points to a place in memory. *p is the contents of that space. But you never use the contents, only the pointer.
That pointer can be viewed as just a number, so printf("%d",p) works. When you assign a number to it, it interprets that as an offset into memory (in bytes). However, the pointer is supposed to contain ints, and when you add a number to a pointer, the pointer advances by that many spaces. So p+5 means "point to the int 5 spaces past the one you're pointing at now", which for 4-byte ints means 20 bytes later, hence the 71.
Otherwise, you've said you have a pointer to an int, but you're actually just doing all your stuff to the pointer, not the int it's pointing to.
If you actually put anything into the place you were pointing, you'd run into all kinds of trouble. You need to allocate some unused memory for it (e.g. with malloc), and then read and write values to that memory using *p.

How does pointer incrementation work?

We have an array: int p[100].
Why p[i] is equivalent to *(p+i) and not *(p+i*sizeof(int)) ?
Why p[i] is equivalent to *(p+i) and not *(p+i*sizeof(int)) ?
Because *(p+i) is also the same as *((int *) ((char *) p + i * sizeof (int))). When you add an integer i to a pointer, the pointer is moved i times the size of the pointed object.
Why p[i] is equivalent to *(p+i) and not *(p+i*sizeof(int)) ?
Because some processor architectures cannot dereference a pointer that does not point to an address that is aligned by the size of its type. That basicly means that a pointer to a
4 byte integer should always point to an adress that is the multiple of 4.
When a program tries to dereference a misaligned pointer it might cause a "Bus error". You can read more about it here on Wikipedia.
What you are asking for is that p + 1 should increment the pointer by one byte instead of one element. If the language was designed that way writing p++ would no longer be valid for pointers of other types than char. It would also cause big problems with pointer alignment when a programmer forgets to write * sizeof(*p) to make the addition.
It might be confusing but there are very valid reasons for why the language was designed this way.
This is because before adding i to p compiler calculates internally the size of data type p points to and then add it i times to p.
Array elements are stored contiguously.
*(p+i)
Here p has the base address of array p and i ranges from 0 to 99.
So you can iterate over the elements of p by incrementing i.
Why p[i] is equivalent to *(p+i) and not *(p+i*sizeof(int))?
This is because of the way pointer arithmetics work: adding an integer n to a pointer yields a pointer to the nth element (not byte) from the first on (0-based).

Resources