C: Pointer confusion - c

I understand this is part of the basic stuff, but i am stuck :-(
Can someone please help me?
Program 1:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a=1,b=2,c;
c=(a+b)++;
}
Why is the output an error? lvalue required?
Program 2:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *p1="name";
char *p2;
p2=(char*)malloc(20);
memset(p2,0,20);
while(*p2++=*p1++);
printf("%s\n",p2);
}
Why is the output, an empty string? And if i reverse the order of increment, that is: while(++*p2=++*p1);, why the lvalue error comes?

For the first question,(a+b)++ means "increment the value of a+b by 1".
You cannot increment a+b, though, for it's not a variable. What would you expect to happen in the following code?
int a = 1, b = 2;
printf("a = %d, b = %d, a+b = %d\n", a, b, a+b);
(a+b)++;
printf("a = %d, b = %d, a+b = %d\n", a, b, a+b);
Clearly the first printf should print
a = 1, b = 2, a+b = 3
But what about the second one?
a = ?, b = ?, a+b = 4
It's not clear what a or b should be if we increment the sum.
As for the second question, remember that you're changing p2 when you copy over the data, so when you ask to print out what it's pointing at, it's pointing at the end of the string, not the beginning.
An easier way to do the string copy would be to use strcpy, like so:
strcpy(p2, p1);
Note, this is only safe because you know that the size of the string in p1 isn't greater than the size of p2. If you're not sure about the size of the string (for instance, if you get the string from user input), you'll need to be careful, as is outlined on Wikipedia.
As for why while(++*p2=++*p1); doesn't work, while while(*p2++=*p1++); does:
Postfix-++ has higher precedence than *. This means, *p2++ means *(p2++).
So
*(p2++) = something;
is the same as
*p2 = something;
p2 += 1;
Meanwhile, ++*p2 means ++(*p2), or "whatever p2 points to, incremented by one".
Again, you get the problem, if you say:
int a = 5, *p2 = &a;
++*p2 = 10;
printf("a = %d\n", a);
What would you expect this to print? If anything, it should print 9, because you're telling the compiler that *p2+1 = 10.
You can't expect a C-compiler to solve that equation, however, so in order to keep the language simple and efficient, this sort of thing is forbidden.

c=(a+b)++;
a+b is not a lvalue - how would you want to assign something to the result of an addition (a rvalue) - and the ++/-- operators do assign the new value.
while(*p2++=*p1++);
You p2 points at the \0 at the end of the string. You need to store the original address p2 points to before your loop:
char *p3 = p2;
while(*p2++=*p1++)
;
printf("%s\n",p3);

c=(a+b)++;
The ++operator doesn't work with temporary variables. (a+b) forms a temporary.
while(*p2++=*p1++);
You're incrementing p2 here. After the loop, p2 no longer points to the beginning of the memory block returned by last malloc() call.

If you look at the while loop:
while(*p2++ = *p1++);
remember that an expression is "True" in C if it is non-zero, and false if it is zero. Even though the loop has no body, the flow of control is still:
check condition -> execute statement in body --> check condition
and here, "check condition" means "evaluate the statement and see if it is non-zero".
The while loop continues to operate until p1 points to zero, at which point control passes to printf.
e.g.
int main()
{
int array1[] = {2, 3, 1, 0, 3, 5};
int array2[20];
int * p2 = (int *)memset(array2, 0, 20*sizeof(int));
int * p1 = array1;
while(*p2++ = *p1++) {
printf("In while: p1 is %d\n", *p1);
}
printf("Out of while: %d\n",*p2);
return 0;
}
yields:
In while: p1 is 3
In while: p1 is 1
In while: p1 is 0
Out of while: 0

Related

How C static pointer guards repeating work?

I'm a C new learner,
when learning llvm, I met the following code
#include <stdint.h>
#include <stdio.h>
#include <sanitizer/coverage_interface.h>
// This callback is inserted by the compiler as a module constructor
// into every DSO. 'start' and 'stop' correspond to the
// beginning and end of the section with the guards for the entire
// binary (executable or DSO). The callback will be called at least
// once per DSO and may be called multiple times with the same parameters.
void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
static uint64_t N; // Counter for the guards.
if (start == stop || *start) return; // Initialize only once.
printf("INIT: %p %p\n", start, stop);
for (uint32_t *x = start; x < stop; x++)
*x = ++N; // Guards should start from 1.
printf("%p \n", x);
}
static uint64_t N; matters
Counter for the guards.
without it, the following for loop repeats.
I know what it can do.
How does it work ?
Here is what the above code prints:
INIT: 0x104351508 0x104351544
0x104351508
0x10435150c
0x104351510
0x104351514
0x104351518
0x10435151c
0x104351520
0x104351524
0x104351528
0x10435152c
0x104351530
0x104351534
0x104351538
0x10435153c
0x104351540
after uint32_t *x = start;
why *x = ++N; does not change x's position?
why *x = ++N; does not change x's position?
It seems you are confused about "the value of a pointer" and "the value a pointer points to" (aka the value of the pointed to object).
The value of the pointer x is initialized by
uint32_t *x = start;
\---------/ \------/
Defines Initializes the value of the pointer to equal the value of start
the
pointer x
Then the value of x is changed by this code:
x++
This part
*x = ++N;
will not change the value of x. Instead it change the value of the pointed to object.
If you change
printf("%p \n", x); --> printf("%p %u\n", x, *x);
you'll see output like
INIT: 0x104351508 0x104351544
0x104351508 1
0x10435150c 2
0x104351510 3
0x104351514 4
0x104351518 5
0x10435151c 6
0x104351520 7
0x104351524 8
0x104351528 9
0x10435152c 10
0x104351530 11
0x104351534 12
0x104351538 13
0x10435153c 14
0x104351540 15
where the first column is the value of the pointer x and the second column is the value of the pointed to object.
In the question you write:
static uint64_t N; matters
Counter for the guards.
without it, the following for loop repeats.
It's a bit unclear exactly what you are asking here but using the keyword static means that the object N preserve its value between calls. In other words, if you call the function again after the example above then N will have the value 15 to start with. So if you provide a new area (i.e. new start and stop values), you could see something like:
INIT: 0x104351600 0x10435160c
0x104351600 16
0x104351604 17
0x104351608 18

While-loop not breaking when extra 'int' keyword added?

I was doing some exercises on codewars, and had to make a digital_root function (recursively add all digits of a number together, up untill there's only one digit left).
I was fairly confident that I did it right, but for some reason my while-loop never broke, even though my prints showed that len was 1.
#include <stdio.h>
#include <string.h>
int digital_root(int n) {
char number[10];
sprintf(number, "%d", n);
int len = strlen(number);
printf("Outer print: %s %d %d\n", number, n, len);
int sum = 0;
while(len > 1)
{
sum = 0;
for(int i = 0; i<len; i++)
{
sum += number[i] - '0';
}
sprintf(number, "%d", sum);
int len = strlen(getal); //!!!
printf("Inner print: %s %d %d\n", number, sum, len);
}
return sum;
}
It took me a long time to figure out what was wrong. I noticed that I copy pasted the 'int' keyword when I recalculated the len in the while loop (line marked with !!!). When I removed that (because it was not needed to redefine it as an int, it already was), everything suddenly worked like it was supposed to.
This kinda confused me. Why would this matter? I understand that redefining it is bad practice, but I don't get how this would result in the while-loop not breaking?
The used compiler is Clan3.6/C11.
(Ps. When I tried the same code in TIO, it worked in both cases...)
You're not redefining an existing variable, you're defining a new variable.
Consider this example:
#include <stdio.h>
int main(void) {
int x = 42;
printf("Outside, start. x (%p) = %d\n", (void *)&x, x);
{
printf("Inner block, start. x (%p) = %d\n", (void *)&x, x);
int x = 123;
printf("Inner block, end. x (%p) = %d\n", (void *)&x, x);
}
printf("Outside, end. x (%p) = %d\n", (void *)&x, x);
return 0;
}
Sample output:
Outside, start. x (0x7ffd6e6b8abc) = 42
Inner block, start. x (0x7ffd6e6b8abc) = 42
Inner block, end. x (0x7ffd6e6b8ab8) = 123
Outside, end. x (0x7ffd6e6b8abc) = 42
[Live demo]
This program outputs the memory address and value of x. Most uses of x refer to the outer variable declared at the beginning of main. But within the inner block, after int x = 123;, all occurrences of x refer to a second, separate variable that happens to also be called x (but is otherwise independent).
When execution leaves the inner block, the outer x variable becomes visible again.
This is also referred to as shadowing.
In your code, the outer len is never modified, so while(len > 1) is always true.
By the way, shadowing is a very common concept in most languages that support block scoping:
Perl
JavaScript
Haskell
Common Lisp
Your second int len creates a second, parallel, variable that goes away at the end of the {} block. The original len then returns to life, completely unchanged. Without the second int the original variable is changed. With it the original len is effectively an unchanged constant and infinite loop.

C pointers - Reading values from absolute addresses vs AddressOf operator (&)

If I did not compile the code I'd say that 1 and 2 give the same result as both of them have an int pointer p pointing to variable age. Dereferencing age in both 1 and 2 should give the same result. I also understand that 3 will just give me the first byte of variable age as it's of type char. I can't explain why 1 and 2 give different results and why 2 and 3 give the same result.
1
int age = 20;
int* p = (int *)0x66FC9C;
printf("You're : %d\n", *p );
2
int age = 20;
int *p = &age;
printf("You're : %d\n", *p );
3
int age = 20;
char* p = (char *)0x66FC9C;
printf("You're %d\n", *p );
Follow-up
It's weird because when I do :
int age1 = 20;
int age2 = 19;
int* p = &age2;
printf("You're %d %d %d %d\n", *p, *(p+1), &age1, &age2 );
and I actually print the addresses I always get the p+1 right (meaning I can predict the address) but if I do :
int age1 = 20;
int age2 = 19;
int* p = &age2;
printf("You're %d %d\n", *p, *(p+1) );
I can never guess it. It's like C knows is being watched... cough cough double slit experiment
You are trying to cheat the compiler, and it looks to be smarter than you...
More seriously, except if you really know the internals of a compiler, never try to guess how it will translate your source. Typically in your last example, a compiler can easily see that the age1 variable is never used (at least never in a conformant way). So it can optimize it out. If you really want to better understand what happens here, you will have to ask the compiler to produce the assembly language that it has internally generated, and read it. You will see whether a variable has been optimized out (because it is not generated), or whether it was not consecutive to the other variable.
And anyway, it is nice to try to better understand what a compiler does, but please never do that in production code.
Who do you know that the address of age is 0x66FC9C? If it's not then you will not be guaranteed the same result in 1 and 2. Equivalent reasoning can be given to 2 and 3.

Pointers for 2D arrays

This is a question from Microsoft Test:
main()
{
int a[2][3]= { (1,2,3),(4,5,6)};
int (*ptr)[3] = &a[0];
printf("%d %d\n", (*ptr)[1],(*ptr)[2]);
ptr+=1;
printf("%d %d\n", (*ptr)[1],(*ptr)[2]);
}
Options given are:
segmentation fault
compiler error
bus error
run time error
I ran this code and I didn't get any of this. I got the following answer:
6 0
0 0
Can you please help me understand what's happening?
The main issue is this line:
int a[2][3]= { (1,2,3),(4,5,6)};
It is using parentheses instead of braces. The result of (1,2,3) is just 3, and the result of (4,5,6) is just 6. So this is equivalent to:
int a[2][3]= { 3,6 };
Which in turn is equivalent to
int a[2][3] = { {3,6,0}, {0,0,0} };
This line makes ptr point to a[0]:
int (*ptr)[3] = &a[0];
This line
printf("%d %d\n", (*ptr)[1],(*ptr)[2]);
is then equivalent to
printf("%d %d\n", (*&a[0])[1],(*&a[0])[2]);
which can be simplified to
printf("%d %d\n", (a[0])[1],(a[0])[2]);
or just
printf("%d %d\n", a[0][1],a[0][2]);
This line
ptr+=1;
makes ptr point to the next element of a, so it is equivalent to
ptr=&a[1];
so the next line simplifies to
printf("%d %d\n", a[1][1],a[1][2]);
The program effectively prints a[0][1], a[0][2], a[1][1] and a[1][2], so that's why you get 6,0,0,0.
Charles Baley points out that main() is missing the return type. This may be what they are getting at. The compiler would normally at least give a warning about that.
Are you sure you copied the text correctly?
(1,2,3) is an expression with two sequence or comma (,) operators; its value is 3. Likewise, the value of (4,5,6) is 6. This is the 6 that is being printed at a[0][1] (since ptr points to a[0] and you print (*ptr)[1]); the 0 is a[0][2], which has default initialization of 0. Then you increment ptr, pointing it to a[1], so you print a[1][1] and a[1][2], which also have default initialization of 0.

pointer movement what is difference between cs[1], and *cs++

I am trying to understand how the pointers are moving.
Following is the program and I am aware that
if
int cs={1,2,3};
then cs points to cs[0]
what I am not clear is what is *cs pointing to.
#include<stdio.h>
int main()
{
int array[] = { 1, 2, 3, 4, 5 };
int *arrptr1 = array;
int *arrptr = array;
int i;
for (i = 0; i < sizeof(array) / sizeof(int); i++) {
printf("%d, %d, %d\n", array[i], *arrptr1++, *arrptr + i);
}
}
the output of above program is
1, 1, 1
2, 2, 2
3, 3, 3
4, 4, 4
5, 5, 5
then my understanding *arrptr should increase the value stored at
*arrptr
should get incremented by 1.
Where as what I observe is the pointer is moving to next location.So just want to know what is wrong in my understanding?
UPDATE
As per the replies below I understand that
print("%d", *arrptr1++);
in such a statement evaluation of operators is from right to left.
Hence in *arrptr1++ the ++ will get evaluated first and then arrptr and then *
So to confirm the same I wrote another program
#include<stdio.h>
int main()
{
int array[] = { 10, 20, 30, 40, 50 };
int *q1 = array;
printf("q1 = %p\n",q1);
printf("*q1++ = %d\n",*q1++);
printf("q1 = %p\n",q1);
printf("*q1++ = %d\n",*q1);
}
The output of above program is different than the expected operator precedence by above logic.
The output I got is
q1 = 0x7ffffcff02e0
*q1++ = 10
q1 = 0x7ffffcff02e4
*q1++ = 20
So I was expecting in the 2nd line of output instead of *q1++ = 10 following *q1++ = 20
so did the operator precedence not happened right to left?
*arrptr1++ is parsed as *(arrptr1++), not (*arrptr1)++.
Whenever you use dereference operator * and pre-increment(pre-decrement) or post-increment(post-decrement) operator on a variable simultaneously ,the order of operation is from right to left (if parenthesis are not used).
What you want to do is
(*arrptr)++
because of higher precedence of (), it will force the compiler to first access the element pointed to by arrptr and then increment its value.
When you do this *arrptr++ , as I've said it first operates rightmost operator (i.e. ++)
and then the dereference operator.
If you will write
EDITED (only the comment): *++arrptr // increment the pointer then access
it will first advance the pointer and then access the value
stored in the address now pointed to by arrptr.
One more thing,The comma used for separation of function argument is not the comma operator so the order of evaluation of the arguments is undefined. (already been told)
What happens is that *arrptr1++ is interpreted as *(arrptr1++), which means that the pointer to the array is increased by one each time in the loop, and hence it will point to the same element as array[i]. *arrptr + i on the other hand is interpreted as "the value of the array element pointed to by arrptr plus the integer i". In this loop it means it will display the same thing as array[i], but it is not pointing at the same element (arrptr is always pointing to the first element in your array). If you change the values in the array to something more random, it should be obvious when you run the program again.
cs = &cs[0] ( cs is equal to the address of cs sub 0) ; *cs = cs[0] (cs pointer is equal to cs sub 0) ; You should remember that *'s hide the [].
// here is a print function with a pointer
int foo[5] = { 2, 9, 1, 3, 6};
int *walker, count;
walker = foo;
for (count = 0; count < 5; walker++, count++)
printf("Array[%d]: %d\n", count, *walker);
Recap: walker is equal to &foo[0], so when you increment walker (eg. walker++) you're moving the pointer to the next address which is foo[1]. And when we are printing the value we can't say ..., walker); since walker( &foo[whatever] ) is pointing to an address, we need to dereference the pointer to get the value. Again, the most important thing to remember
array = &array[0] AND *array = array[0]

Resources