Operator and Pointer precedence - c

Below is the problem I found on the internet.
int main()
{
int a[4] = { 10, 21, 32, 43};
int *p = a + 3;
++*--p;
++*p--;
p[2] += p[1];
for (int i = 0; i < 4; ++i)
printf("%d - %d\t", a[i]);
return 0;
}
//What will be the output?
answer : 10 21 34 77
I understood a lot of things, but the only thing I'm stuck on:
What is the difference between (++*--p) and (++*p--) ?
Shouldn't these two give the same result? Because (*p--) and (*--p) give the same result in the compiler. The compiler I use is Code::Blocks

Because (*p--) and (*--p) give the same result in the compiler.
No, they do not. *p-- decrements p but applies * to the value of p before the decrement. *--p applies * to the value of p after the decrement.
What is the difference between (++*--p) and (++*p--) ?
++*--p decrements p and increments the object it points to after the decrement.
++*p-- decrements p but increments the object it points to before the decrement.

What is the difference between (++*--p) and (++*p--) ?
The difference is that --p decrements p and resolves to the new value of p, whereas p-- decrements p and resolves to the old value of p.
++* works identically on both - performing indirection on p, incrementing the value p points to, and resolving to this new value.
#include <stdio.h>
int main(void)
{
int a = 10;
int b = 10;
/* This prints 9, and `a` is now 9 */
printf("%d\n", --a);
/* This prints 10, and `b` is now 9 */
printf("%d\n", b--);
/* This prints 9 and 9 */
printf("%d %d\n", a, b);
}
Shouldn't these two give the same result? Because (*p--) and (*--p) give the same result in the compiler.
The order here matters, using (*--p) before (*p--) would resolve to the same element twice. Using (*p--) before (*--p) resolves to different elements.
#include <stdio.h>
int main(void)
{
int a[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
int *p = a + 4;
/* 4 then 4 */
printf("%d ", *--p);
printf("%d\n", *p--);
p = a + 4;
/* 5 then 3 */
printf("%d ", *p--);
printf("%d\n", *--p);
}

Related

Pointer arithmetic in C not pointing to the correct variables if I don't print the address of the variables

So I'm doing pointer arithmetic homework and I need to decrement and increment pointers with this as its expected outcome. This is what I did
#include <stdio.h>
void main(void){
int d = 10;
int c = 8;
int b = 6;
int a = 4;
int *ptr; //these lines are given
printf("decrement \n");
for (ptr = &d; ptr >= &a; ptr--)
{
printf("%d \n",*ptr);
}
printf("increment \n");
for (ptr = &a; ptr <= &d; ptr++)
{
printf("%d \n",*ptr);
}
}
But the results skip 8 and 6:
decrement
10
4
increment
4
10
And so I decided to print the addresses at the beginning to help debug
printf("%p\n",(void*)&d);
printf("%p\n",(void*)&c);
printf("%p\n",(void*)&a);
printf("%p\n",(void*)&b);
But after running it, it just works
000000fc6a9ffb34
000000fc6a9ffb30
000000fc6a9ffb28
000000fc6a9ffb2c
decrement
10
8
6
4
increment
4
6
8
10
So I know that the logic works out, but it just doesn't work without printing first and I don't know why
I'm using Vscode and GCC
So I know that the logic works out, but it just doesn't work without printing first
Undefined behavior (UB), anything may happen.
int d = 10;
int a = 4;
int *ptr = &d;
ptr >= &a
ptr >= &a is undefined behavior (UB).
Order comparisons of pointers in C are UB when not part of the same array (or one after).
ptr-- is also UB as that attmepts to form the address before d. Pointer math only good within an array/object (or one after)
In your first example, you are not using variables b and c, just a and d - therefore (I suspect) the implementation is optimizing them away
In the second example, you are using variables all four variables a, b, c and d therefore they cannot be optimised away
your program have four different variables not an array of size four. So address of variables is unpredictable.
int d = 10;
int c = 8;
int b = 6;
int a = 4;
in Array memory is allocated contiguously, so use array if you want to do so.
#include<stdio.h>
int main(){
int arr[4] = {1, 2, 3, 4};
// increment
for(int i=0; i<4; i++)
printf("%d\n",*(arr + i));
// decrement
printf("-------------------------------\n");
for(int i=3; i>=0; i--)
printf("%d\n",*(arr + i));
return 0;
}

Trying to load an array using pointers in C

I am trying to load an array using pointers. I am assigned my x[0] the value of 2, and the desired output is 2, 4, 8, 16, 32, 64, 128.
For some reason, my loop starts at index 4 or it starts at index 2 and only prints 2, 4, 8, 16.
#include <stdio.h>
#include <math.h>
int main() {
int x[7] = {}, *ip;
ip = &(x[0]);
*ip = 2;
for(int i = 0; *ip < sizeof x; *ip *= 2) {
printf("value of x: %d\n", x[i]);
}
}
This loop:
for(int i = 0; *ip < sizeof x; *ip *= 2) {
printf("value of x: %d\n", x[i]);
}
will print x[i] till the value at memory location pointed by pointer ip is less than the size of object x in bytes. Note that i is initialised with 0 but it is nowhere altered.
Assume that size of int on your system is 4 bytes, the sizeof x will yield 28 because x is an array of 7 integers (7 * 4 = 28).
Iteration I:
i = 0 //initialized
*ip = 2, 2 < 28 ----> true
print x[0] ----> 2
*ip *= 2 ----> *ip = 4
Iteration II:
*ip = 4, 4 < 28 ----> true
print x[0] ----> 4
*ip *= 2 ----> *ip = 8
Iteration III:
*ip = 8, 8 < 28 ----> true
print x[0] ----> 8
*ip *= 2 ----> *ip = 16
Iteration IV:
*ip = 16, 16 < 28 ----> true
print x[0] ----> 16
*ip *= 2 ----> *ip = 32
Iteration V:
*ip = 32, 32 < 28 ----> false
loop exits
Hence, you are getting output - 2, 4, 8, 16.
Correct way to get the size of an array is - sizeof (x) / sizeof (x[0]). This will result in number of elements of array x.
This
ip = &(x[0]);
can also written as
ip = x;
because when you access an array, it is converted to a pointer to first element (there are few exceptions to this rule). Moreover,
From C Standards#6.5.2.1
The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))..
by this definition
&(x[0]) -> &(*(x + 0)) -> &(*(x)) -> x
You are initialising the array x with an empty initialiser:
int x[7] = {}
Empty initialiser is non-conforming in C, though some C compilers accept it. Instead, you should do:
int x[7] = {0}
Your desired output is 2, 4, 8, 16, 32, 64, 128 i.e. the first element of array should be 2 and every successive element in the array should be multiple of 2 of its previous element. Since, you want to calculate the value of every element of array using pointer pointing to that array element, one things you should know -
A pointer can point to one past the last element of array but dereferencing it will invoke undefined behaviour.
Putting these altogether, you can do:
#include <stdio.h>
int main (void) {
int x[7] = {0}, *ip;
ip = x;
*ip = 2;
for (size_t i = 0; i < sizeof (x) / sizeof (x[0]); ++i) {
printf ("value of x: %d\n", x[i]);
// make pointer point to next element in array
++ip;
// make sure that the element that ip pointer pointing to is valid to deference
if (ip < x + (sizeof (x)/sizeof (x[0]))) {
// calculate the element value using the previous element value
*ip = *(ip - 1) * 2;
}
}
return 0;
}
If you want to avoid the pointer comparison, you may do something like this:
#include <stdio.h>
int main (void) {
int x[7] = {0}, *ip;
ip = x;
for(size_t i = 0; i < sizeof (x) / sizeof (x[0]); ++i, ++ip) {
*ip = (i ? *(ip - 1) : 1) * 2;
printf("value of x: %d\n", x[i]);
}
return 0;
}
Following the perceived intent of your code, that is, to fill an array by using a pointer, I corrected it to the below.
#include <stdio.h>
int main()
{
int x[7] = {0};
int *p, counter;
for (p = &x[0], counter = 0; counter < 7;) {
*p++ = (1 << ++counter);
}
for (counter = 0; counter < 7; counter++)
printf("%d\n", x[counter]);
}
I initialise x and declare a pointer int *p. I also declare a variable counter to count to the number of elements in the array.
At the start of the loop I point p to the address of the first element of the array x and initialise counter to 0.
In each loop iteration I set the value at the address pointed by p to the result of a left-shift (or l-shift) operation and increment pointer p (that is, advance it by sizeof(int) bytes). The l-shift operation has the effect of raising 2 to the power of n, where n is the number of l-shift positions. For example:
(1 << 0) = 1
(1 << 1) = 2
(1 << 2) = 4
(1 << 3) = 8
I use the post-increment operator for p (that is, *p++) because I want to set the value before advancing it. But I use the pre-increment operator for counter (that is, ++counter) because I want the first l-shift to be by 1 position so that the result stored in the first element of the array is 2 -- refer to example above.
int x[7] = {}, *ip;
ip = &(x[0]);
In C, arrays are just pointers that you've told the proprocessor and compiler about so it can do the memory allocation on the stack for you. There's nothing special about the pointer itself with an array. In the above, ip and x are both int*, so you can just say ip = x;
*ip = 2;
x[0] now is 2
for(int i = 0; *ip < sizeof x; *ip *= 2){
Your middle condition *ip < sizeof x; in English is "until the int pointed to by ip is less than the number of bytes used by x (7 * sizeof(int); probably 7 * 4 or 28)" It's valid in that it will compile and execute, but I don't think it's what you want looking at the rest of your code. You never increment ip, so it's always changing x[0].
Assuming you just don't want ip to go past the end of x[], You could write this as i < sizeof(x)/sizeof(x[0]) which is "counter i is less than the total bytes used by x[] divided by the size in bytes of one element used by x (the number of elements in x[])" or if you want to use ip and not i for some reason ip <= &x[6] which is "ip is less than or equal to the address of the last element of x[] (because we know x is a fixed length of 7; [0...6]"
*ip *= 2
Your for incrementor is "the integer pointed to by ip is multiplied by 2". Normally you would increment your counter i here, but it's acceptable in C to do something else like you have here. However, since you never change ip, this is going to multiply the same x[0] by 2 over and over until x[0]'s value is more than sizeof(x). You probably want to increment ip or i here, so it steps through X[]. Normally the manipulation of your array would happen inside the for block and not in the for control statements.
printf("value of x: %d\n", x[i]);
This will always print the value of x[0], since i never changes.
Everything you've written is valid C code. Some of the things you're doing are unusual, but there are edge cases where you would want that in C, for example incrementing something other than your counter in the for loop control. However, you've got a extra code that isn't doing anything useful. I see what you want as output from your question details, but from your code I'm unsure how you want to accomplish that, so this is just a guess:
int x[7];
x[0] = 2;
printf("x[0] starts with: %d\n",x[0]);
for(int i = 1; i<sizeof(x)/sizeof(x[0]); i++) { //i start at 1 because we already set x[0]
x[i] = x[i-1]*2; //the current x[] = double the previous x[]
printf("value of x[%d]: %d\n",i,x[i]);
}
This version fills x with [2,4,8,16,32,64,128]. The int *ip isn't needed- there are times you'll want to control a loop with pointer math, but it's not needed here.

Why is p[0]++ different from *(p)++ in C

When I tried to execute these codes in C
#include <stdio.h>
int main(void)
{
int arr[] = {10, 20};
int *p = arr;
p[0]++; // *(p)++;
printf("arr[0] = %d, arr[1] = %d",arr[0], arr[1]);
return 0;
}
output: arr[0] = 11, arr[1] = 20
on replacing p[0]++; by *(p)++;
output : arr[0] = 10, arr[1] = 20
Please explain why this is. I know a[i] is equivalent to *(a + i)
The expression:
p[0]++;
basically increments the value at index 0.
While
*(p)++
Increments the pointer to the next address .
Example :
int arr = {10,20};
int *p = arr; // p points to the first element of array, i.e 10
*(p)++; // now p points to the next element i.e 20.
below code can be used:
p[0]++ means = p[0] + 1;
p[0]++ = 10 + 1;
p[0]++ = 11;
You can't do with this same thing with an array, so be careful.
I hope it helps!

Printing pointer value with increment of the address in C

#include <stdio.h>
#include <stdlib.h>
int main()
{
int k,*ptr=NULL;
int arr[]={1,2,3,4,5,6,7,8,9,10};
ptr=arr;
printf("%d ",*ptr++);
printf("%d ",*(ptr++));
printf("%d ",(*ptr)++);
printf("%d ",*++ptr);
printf("%d ",++*ptr);
}
Why does the second printf print the number 2 ? It should print 3.
As everyone else said, the distinction is between pre-incrementing (where the increment occurs before the value is fetched) and post-incrementing (where the value is fetched and then the increment occurs). The value 2 should be printed, of course.
Maybe this assertion-laden code will help. The assert() macro stops the program if the condition specified is false when it is executed. The assertions do not fire.
The assertions show how the value of ptr changes, and also how the values in the array change.
#include <assert.h>
#include <stdio.h>
int main(void)
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int *ptr = arr;
assert(ptr == &arr[0]);
printf("%d\n",*ptr++); // print 1; ptr = &arr[1]
assert(ptr == &arr[1]);
printf("%d\n",*(ptr++)); // print 2; ptr = &arr[2]
assert(ptr == &arr[2]);
assert(*ptr == 3);
printf("%d\n",(*ptr)++); // print 3; ptr = &arr[2]; arr[2] = 4
assert(ptr == &arr[2]);
assert(*ptr == 4);
printf("%d\n",*++ptr); // print 4; ptr = &arr[3]
assert(ptr == &arr[3]);
assert(*ptr == 4);
printf("%d\n",++*ptr); // print 5; ptr = &arr[3]; arr[3] = 5
assert(ptr == &arr[3]);
assert(*ptr == 5);
printf("Offset: %d\n", (int)(ptr - arr));
for (int i = 0; i < 9; i++)
printf("a[%d] = %d\n", i, arr[i]);
return 0;
}
Output:
1
2
3
4
5
Offset: 3
a[0] = 1
a[1] = 2
a[2] = 4
a[3] = 5
a[4] = 5
a[5] = 6
a[6] = 7
a[7] = 8
a[8] = 9
post increment operator increments the variabl after accessing the value.
So, after getting *ptr, which is 2, ptr increases itself.
Not, because ptr++ return the value BEFORE the incrementation, so the value is 2.
*ptr++ first dereferences the pointer which gives 2, then increments the pointer
The expression *(ptr++) is a post increment expression so the value of of that expression is ptr and then it is incremented. So the result of the expression is that it still points to the 2
the * operator applies to the result of p++, which is the value of original p (prior to the increment). So it prints 2. I you want 3 to be printed you should do (++p) which returns the incremented value.
It should print 2, because the postfix operator ++ first returns the value and then increments it.
The fact that you added brackets around it (*(ptr++)) does not influence the increment.
The value will be incremented after the whole line.
Looking at disassembly might help you to see what happens at that line.
The *ptr++ returns the value at ptr and then increments it,so in the second printf() statement it only returns 2 and then increments it to 3.

assigning a compound literal to an array pointer gives both the expected result and rubbish at the same place and time?

#include <stdio.h>
int main(void) {
int a[5], *p, i;
p = a;
p = (int []){1, 2, 3, 4, 5};
for (i = 0; i < 5; i++, p++) {
printf("%d == %d\n", *p, a[i]);
}
return 0;
}
Lo and behold (YMMV):
$ gcc -O -Wall -Wextra -pedantic -std=c99 -o test test.c; ./test
1 == -1344503075
2 == 32767
3 == 4195733
4 == 0
5 == 15774429
Printing the array through pointer arithmetic shows that it indeed holds an integer sequence of 1 to 5, yet printing again what is supposedly the same array expressed through indeces gives uninitialized crap. Why?
You only assign to p, never to a, so a is never initialized.
int a[5], *p, i;
// a uninitialized, p uninitialized
p = a;
// a uninitialized, p points to a
p = (int []){1, 2, 3, 4, 5};
// a uninitialized, p points to {1, 2, 3, 4, 5}
You never initialize a's elements. Both assignments to p change where p points; neither assignment does anything to a or its elements.
You assign the value of a to p, and then immediately override it with the value of another array of ints. In printf("%d == %d\n", *p, a[i]) *p and a[i] no longer reference the same place in memory, and a remains uninitialized (hence the garbage).
You're assigning to an array pointer, you do not copy the data to array. So you get the data from one source and rubbish from the other.
Your code is equivalent to this:
int a[5];
int b[5] = { 1, 2, 3, 4, 5 };
for (i = 0; i < 5; i++)
printf("%d == %d\n", b[i], a[i]);
Since a is uninitialized, you get unpredictable values (in fact it is undefined behaviour to even read those variables).

Resources