Need help in understanding the solution to the C exercise involving pointers - c

I need help in understanding how we got the values in the table below for Loc3 and Loc4.
When I was making a table on my own I arrived to totally different entries for those columns.
Thank you!
int x = 42; /* x is at address 100 */
int y = 13; /* y is at address 104 */
int *p; /* p is at address 108 */
int **p2; /* p2 is at address 112 */
/* Location 1 */
p = &y;
p2 = &p;
/* Location 2 */
*p2 = &x;
**p2 = 11;
/* Location 3 */
*p = 12;
/* Location 4 */

For instance, x at loc3 becomes 11 because you set **p2 to 11, which modifies the value at that memory location. (double star is a pointer to a pointer). Ampersand gets the address.
To elaborate:
*p2 = &x;
**p2 = 11;
In Loc2 you set p2 = &p, which means p2 is now pointing to the address of p, which is 108.
But now in Loc3, you set what p2 is pointing to to the address of x. In other words, since p2 was pointing to the address of p, now you're saying that p should instead point to the address of x (which is also why p becomes 100).
Then **p2 modifies the value at that address of x to be 11 (through p), hence loc3's x value becomes 11.

Location 1:
int x = 42;
int y = 13;
int *p;
int **p2;
p or p2 don't point anywhere.
Location 2:
p = &y;
p points to y.
p2 = &p;
p2 points to p.
No changes to x or y.
Location 3:
*p2 = &x;
Since p2 points to p, dereferencing p2 and assigning a value to it changes p to point to x. Same as doing p = &x.
**p2 = 11;
Dereference once to get to p, dereference again to get to x, and assign 11 to it. Same as doing: x = 11 or *p == 11.
No change to y or p2.
Location 4:
*p = 12;
Dereference p to get to x and assing 12 to it. No change to y or p2 or p.

When you start out, p and p2 are uninitialized and contain indeterminate values, hence the ?? in both entries under Loc 1.
p = &y;
assigns the location of y (104) to p.
p2 = &p;
assigns the location of p (108) to p2. Note that the type of the expression &p is char **, which matches the type of the variable p2. So after these two statements, all of the following are true:
p2 == &p == 108 // all expressions have type char **
*p2 == p == &y == 104 // all expressions have type char *
**p2 == *p == y == 13 // all expressions have type char
x == 42
Next we execute
*p2 = &x;
From above we see that *p2 is equivalent to p, so this statement assigns the address of x (100) to p, so now we have
p2 == &p == 108
*p2 == p == &x == 100
**p2 == *p == x == 42
y == 13
Next we execute
**p2 = 11;
**p2 is equivalent to *p, which is equivalent to x, so we wind up assigning the value 11 to x:
p2 == &p == 108
*p2 == p == &x == 100
**p2 == *p == x == 11
y == 13
Finally we have
*p = 12;
*p is equivalent to x, so we're assigning the value 12 to x, leaving us with:
p2 == &p == 108
*p2 == p == &x == 100
**p2 == *p == x == 12
y == 13

Related

C: malloc of string showing unexpected behaviour with double pointer and function calls

This is a query to understand how the below code is working fine even with a mistake.
As per my knowledge, if I want to reallocate/ re-assign a pointer passed to a function, that pointer needs to be passed as a double pointer. By mistake, I passed a single pointer and the program is still working. I guess it has to do something with the pointer being a string.
Program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func2( char **x){
printf("befor func2 x = %u; *x = %u; **x = %s; x_size = %u\n", x, *x, *x, strlen(*x));
free(*x);
*x = (char *)malloc(20);
strcpy(*x, "zyxwvutsrqponmlkjih");
printf("\n\nafter func2 x = %u; *x = %u; **x = %s; x_size = %u\n", x, *x, *x, strlen(*x));
}
void func1( char *x){
printf("befor func1 &x = %u; x = %u; *x = %s; x_size = %u \n", &x, x, x, strlen(x));
func2(&x);
printf("after func1 &x = %u; x = %u; *x = %s; x_size = %u \n", &x, x, x, strlen(x));
}
int main(){
char *x;
x = (char *)malloc(10);
strcpy(x, "abcdefghi");
printf("befor main &x = %u; x = %u; x = %s; x_size = %u\n", &x, x, x, strlen(x));
func1(x);
printf("after main &x = %u; x = %u; x = %s; x_size = %u\n", &x, x, x, strlen(x));
free(x);
return 1;
}
OutPut:
befor main &x = 489275896; x = 20414480; x = abcdefghi; x_size = 9
befor func1 &x = 489275864; x = 20414480; *x = abcdefghi; x_size = 9
befor func2 x = 489275864; *x = 20414480; **x = abcdefghi; x_size = 9
after func2 x = 489275864; *x = 20414480; **x = zyxwvutsrqponmlkjih; x_size = 19
after func1 &x = 489275864; x = 20414480; *x = zyxwvutsrqponmlkjih; x_size = 19
after main &x = 489275896; x = 20414480; x = zyxwvutsrqponmlkjih; x_size = 19
I can understand the output till func1. But how the size and values are getting returned to main after being modified in func2? I've not passed x as a double pointer from main to func1. But somehow it's still working.
Is it because it is a char *?
Edit 1:
After suggested edits in the comments:
Program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func2( char **x){
printf("befor func2 x = %p; *x = %p; **x = %s; x_size = %u\n", x, *x, *x, strlen(*x));
free(*x);
*x = (char *)malloc(20);
strcpy(*x, "zyxwvutsrqponmlkjih");
printf("\n\nafter func2 x = %p; *x = %p; **x = %s; x_size = %u\n", x, *x, *x, strlen(*x));
}
void func1( char *x){
printf("befor func1 &x = %p; x = %p; *x = %s; x_size = %u \n", &x, x, x, strlen(x));
func2(&x);
printf("after func1 &x = %p; x = %p; *x = %s; x_size = %u \n", &x, x, x, strlen(x));
}
int main(){
char *x, *y, *z;
x = (char *)malloc(10);
z = (char *)malloc(100);
y = (char *)malloc(100);
strcpy(x, "abcdefghi");
printf("befor main &x = %p; x = %p; x = %s; x_size = %u\n", &x, x, x, strlen(x));
func1(x);
printf("after main &x = %p; x = %p; x = %s; x_size = %u\n", &x, x, x, strlen(x));
free(x);
free(y);
free(z);
return 1;
}
Output:
befor main &x = 0x7fff78cb09c8; x = 0x1c7a010; x = abcdefghi; x_size = 9
befor func1 &x = 0x7fff78cb09a8; x = 0x1c7a010; *x = abcdefghi; x_size = 9
befor func2 x = 0x7fff78cb09a8; *x = 0x1c7a010; **x = abcdefghi; x_size = 9
after func2 x = 0x7fff78cb09a8; *x = 0x1c7a010; **x = zyxwvutsrqponmlkjih; x_size = 19
after func1 &x = 0x7fff78cb09a8; x = 0x1c7a010; *x = zyxwvutsrqponmlkjih; x_size = 19
after main &x = 0x7fff78cb09c8; x = 0x1c7a010; x = zyxwvutsrqponmlkjih; x_size = 19
The program still works after introducing multiple mallocs.
What you have is undefined behavior.
Here follows the important parts of your program (with renamed variables to be able to differ between them in the functions):
void func2(char **x)
{
free(*x);
*x = malloc(SOME_OTHER_SIZE);
}
void func1(char *y)
{
func2(&y);
}
int main(void)
{
char *z = malloc(SOME_SIZE);
func1(z);
}
In the main function you allocate some memory, and make z point to it.
Then you call func1 passing the pointer z by value, meaning that the pointer is copied into the func1 argument variable y. Now you have two pointers pointing to the same memory: z in the main function and y in the func1 function.
Then func1 calls func2, but it emulates pass by reference by passing not a copy of the value in y but a pointer to the variable y itself. When func2 free's the memory pointed to by *x, it invalidates the pointers *x, y and z. It then reassigns *x to point to some new memory. This will change where y is pointing but not z, which will still be invalid.
When func1 returns the pointer z is no longer valid, any attempt to dereference it will lead to said undefined behavior.
Somewhat graphically it could be seen like this:
The main function allocates memory and makes z point to it:
+---+ +-----------+
| z | --> | Memory... |
+---+ +-----------+
The function func1 is called, passing a copy of z:
+---+
| z | -\
+---+ \ +-----------+
>-> | Memory... |
+---+ / +-----------+
| y | -/
+---+
The function func2 is called, passing a pointer to y:
+---+
| z | -\
+---+ \ +-----------+
>-> | Memory... |
+---+ +---+ / +-----------+
| x | --> | y | -/
+---+ +---+
The function func2 free's the memory pointed to by *x:
+---+
| z | -\
+---+ \
>-> ???
+---+ +---+ /
| x | --> | y | -/
+---+ +---+
The function func2 allocates new memory and makes *x (and therefore y) point to it:
+---+
| z | --> ???
+---+
+---+ +---+ +---------------+
| x | --> | y | --> | New memory... |
+---+ +---+ +---------------+
From the above it should hopefully be easy to see why free(*x) in func2 will invalidate z from the main function as well.
Now the interesting part, which is why the memory pointed to by z in the main function seems to be changed: It's seems to be a quirk of the memory allocator in your system, where it maps the new allocation to the same location as the old allocation. The important point is that z is still invalid.
You seem to think that using char *x (a single pointer) as an argument for func1 was a mistake. However, I think it's perfectly fine. func1 is expecting a pointer to char as an argument, or basically a memory address that when dereferenced gives a char or bunch of chars. When you write func1(x); in main, you are passing x, the address of a bunch of chars, which is just the type of argument func1 was expecting.
Why is x the address of a bunch of chars?
In this case, the pointer x is storing the address of an array (of characters). Now, you might know that if you just write the name of an array, you get the base address of the array. See the below code:
#include <stdio.h>
#include <stdlib.h>
int main () {
int arr[5] = {1, 2, 3, 4, 5};
printf ("%d\n", arr); // address of the first element (1) of the array
// or, the base address of the array
printf ("%d\n", &arr[0]); // same as above
printf ("%d\n\n", *arr); // gives the first element of the array
int *x = malloc (5*sizeof (int));
*x = 1;
*(x+1) = 2;
*(x+2) = 3;
*(x+3) = 4;
*(x+4) = 5;
printf ("%d\n", x); // address of the first element (1) of the array
// or, the base address of the array
printf ("%d\n", &*(x+0)); // same as above
printf ("%d\n\n", *x); // gives the first element of the array
return 0;
}
The output is as follows:
6356712
6356712
1
9768168
9768168
1
Now, why are we able to modify the values in the character array pointed to by x? Because we have passed the base address of that array. We can dereference that address to get to the array and do whatever we want with it.

In C, I am having trouble tracing a code and not sure how the value is being computed?

I am tracing a code but I don't understand how the values are being calculated. My question is on the comments beside the code.
I am tracing code and I understand all the parts except 2. I posted those 2 part below. I will be really glad if someone could help me.
#include <stdio.h>
int function1(int *m, int n)
{
*m = *m + n;
return(*m);
}
int function2(int n, int *m)
{
n = *m + 2;
return(n);
}
int main()
{
int x = 1, y = 3;
int *xptr = &x,*yptr = &y;
x = 1; y = 3;
y = function1(xptr,x);
printf("x = %d, Y = %d\n",x,y);//x=2 but why? shouldn't it be x=1? y=2
x = 1; y = 3;
x = function1(yptr,function2(2,yptr));
printf("x = %d, y = %d\n",x,y);//x=8 y=8 but why? shouldn't y=3?
return 0;
}
So, inside function1:
int function1(int *m, int n) {
*m = *m + n;
return(*m);
} /*
... */
y = function1(xptr,x);
n holds a copy of the value of x,
m holds a copy of the value of xptr, which is the address of x.
*m refers to the contents of the address held by m
...*m = *m + n
That's 'assign to the contents of the address of x: the contents of the address of x, plus the value of x'.
The contents of the address of x (aka it's value) is 1. So we assign 1 + 1 to the contents of address holding the value of x.
In the first printf, x == 2 because when calling function1 the first time *m is a pointer to x, so you assign to the location pointed by m (that is the location of x), *m + n == x + x == 1 + 1 == 2.
In the second printf, y == 8 because in function2 you return its value incremented by 2 (so 3 + 2 == 5) but without updating y, so in function1 you sum the resulting value of function2 to the old value of y (3 + 5 == 8). function1 return also that value, so also x == 8.

subtracting two pointers(arrays), (C language) [duplicate]

This question already has answers here:
Pointer Arithmetic In C
(2 answers)
Pointer subtraction confusion
(8 answers)
Closed 4 years ago.
int vector[] = { 28, 41, 7 };
int *p0 = vector;
int *p1 = vector + 1;
int *p2 = vector + 2;
I know result of
printf("%p, %p, %p\n", p0, p1, p2);
is ex) 100, 104, 108
but why is the result of
printf("p2-p0: %d\n", p2 - p0);
printf("p2-p1: %d\n", p2 - p1);
printf("p0-p1: %d\n", p0 - p1);
is 2, 1, -1
not 8, 4, -4????????
when you subtract to pointers (of the same type else no sense) that computes the difference as indexes, not the difference of the addresses :
type * p1 = ...;
type * p2 = ...;
(p1 - p2) == (((char *) p1) - ((char *) p2)) / sizeof(type)
It is the same when you do vector + n, that gives the address of the element rank n, not ((char *) vector) + n. So
type * p = ...;
int n = ...;
((char *) (p + n)) == (((char *) p) + n * sizeof(type))

How to print pointer to pointers

I am a newbie trying to understand the working of double pointers and to print double pointers. I increment m by one but it's always pointing to the last value pointed by p. Can someone please help me?
#include <stdio.h>
int main () {
/* an array with 5 elements */
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double *p;
double **m;
int i;
p = balance;
m = &p;
/* output each array element's value */
printf( "Array values using pointer\n");
for ( i = 0; i < 5; i++ ) {
printf("*(p + %d) : %f\n", i, *(p+i) );
}
for ( i = 0; i < 5; i++ ) {
printf("**(m + %d) : %f\n", i, *m);
m++;
}
printf( "Array values using balance as address\n");
for ( i = 0; i < 5; i++ ) {
printf("*(balance + %d) : %f\n", i, *(balance + i) );
}
return 0;
}
Your array balance is like this
+--------+--------+--------+--------+--------+
| 1000.0 | 2.0 | 3.4 | 17.0 | 50.0 |
+--------+--------+--------+--------+--------+
After you initialize p and m it is like this:
+---+
| m |
+---+
|
v
+---+
| p |
+---+
|
V
+--------+--------+--------+--------+--------+
| 1000.0 | 2.0 | 3.4 | 17.0 | 50.0 |
+--------+--------+--------+--------+--------+
That is, m points to the location of p, and p points to the first value of the balance array.
When you dereference m (i.e. when you do *m) you get the value of where m is pointing. This value is another pointer (p) that you need to dereference to get to an element in the array.
Using m the second element in balance (i.e. balance[1]) is (*m)[1].
Now if you increment m (with e.g. m++) it will point to the next element of p:
+---+
| m |
+---+
|
v
+---+
| p |
+---+
|
V
+--------+--------+--------+--------+--------+
| 1000.0 | 2.0 | 3.4 | 17.0 | 50.0 |
+--------+--------+--------+--------+--------+
You can clearly see the problem here: It no longer points to p and you can no longer us it to access the balance array. Dereferencing m after the increment will lead to undefined behavior.
Also, for any pointer or array, the array-indexing expression and the pointer arithmetic expression are equal. So for balance, the expression balance[i] is equal to *(balance + i). There is really no difference between them.
So after you execute
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double *p;
double **m;
p = balance;
m = &p;
the following are all true:
m == &p // double **
*m == p == &balance[0] // double *
**m == *p == balance[0] // double
(*m)[i] == p[i] == balance[i] // double
Remember that the expression a[i] is defined as *(a + i); given the address a, offset i elements (not bytes1) from that address and dereference the result.
This means that *p is equivalent to *(p + 0), which is equivalent to p[0]. Thus, you can use p[i] in place of balance[i]. Since *m == p, you can also use (*m)[i] in place of p[i]. The parentheses are necessary - unary * has lower precedence than postfix [], so *m[i] would be parsed as *(m[i]), which is not what you want here.
You can increment p directly to "walk" through the balance array:
p = balance; // p == &balance[0];
for ( i = 0; i < 5; i++ )
printf( "%f\n", *p++ );
Each time through the loop, p is incremented to point to the next element of balance.
You can do something similar with the expression (*m):
p = balance; // p == &balance[0]
m = &p;
for ( i = 0; i < 5; i++ )
printf( "%f\n", (*m)++ );
Again, the parentheses around *m are necessary; since postfix ++ has higher precedence than unary *, the expression *m++ would be parsed as *(m++), which is not what we want. We don't want to change the value of m, we want to change the value of what m points to, which in this case is p.
Now, suppose we leave p out of the picture completely; can we do something like:
double balance[5] = { ... };
double **m;
*m = balance;
No. In this example, m is an invalid pointer; it hasn't been initialized to point anywhere meaningful, so *m will invoke undefined behavior (which can include, but is not limited to, a segfault). m has to point to an object of type double * before you can dereference it. There has to be a middleman like p in order for that scheme to work.
Pointer arithmetic always takes the size of the pointed-to type into account - if a points to an object of type T, then a + 1 yields the address of the next object of type T, which may be more than 1 byte away from the current address.

How does the int and char pointer affect my print out here?

so here is the code, till the 4th print out I easily followed it, but at the 5th print out, I don't understand
why its "5: a[0] = 200, a[1] = 128144, a[2] = 256, a[3] = 302 "?
I have commented the line in the code which I don't understand. I look forward to your response.
"#include <stdio.h>
#include <stdlib.h>
void
f(void)
{
int a[4];
int *b = malloc(16);
int *c = 0;
int i;
printf("1: a = %p, b = %p, c = %p\n", a, b, c);
c = a;
for (i = 0; i < 4; i++)
a[i] = 100 + i;
c[0] = 200;
printf("2: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
c[1] = 300;
*(c + 2) = 301;
3[c] = 302;
printf("3: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
c = c + 1;
*c = 400;
printf("4: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
//I DONT UNDERSTAND WHAT THIS LINE BELOW DOES
c = (int *) ((char *) c + 1);
*c = 500;
printf("5: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
b = (int *) a + 1;
c = (int *) ((char *) a + 1);
printf("6: a = %p, b = %p, c = %p\n", a, b, c);
}
int
main(int ac, char **av)
{
f();
return 0;
}
output:
1: a = 0x7fff65fdcb90, b = 0x1065007e0, c = 0x0
2: a[0] = 200, a[1] = 101, a[2] = 102, a[3] = 103
3: a[0] = 200, a[1] = 300, a[2] = 301, a[3] = 302
4: a[0] = 200, a[1] = 400, a[2] = 301, a[3] = 302
5: a[0] = 200, a[1] = 128144, a[2] = 256, a[3] = 302
6: a = 0x7fff65fdcb90, b = 0x7fff65fdcb94, c = 0x7fff65fdcb91
Let's start with the basics.
c is a pointer to an array of ints.
Let this be a:
[00000000][00000000][00000000][00000000]
Every two digits is a byte, and we assume that sizeof(int) is 4 in our example, so every element in a has 4 bytes, or 8 digits.
Now, c is a pointer to the first element in a.
Let's have a look at the expression in question:
c = (int *) ((char *) c + 1);
Obviously, c is changed here, but what exactly happens is:
c is cast from int* to char*
the result of the cast is incremented, resulting in sizeof(char) being added to c. Since sizeof(char) is 1, c is incremented by 1 and points to the second byte of an element in a.
the result is cast back to int*, and reassigned to c. This second cast is actually not needed.
So, ignoring all the other code, we start from this:
a : [00000000][00000000]...
^
c -|
And go to this:
a : [00000000][00000000]...
^
c ---|
As Daniel pointed out below, if c is not correctly aligned for a pointer of type int*, you get undefined behaviour, which should be avoided.
c is a pointer-to-int, so normally c+1 refers to the address which is sizeof(int) further along in memory - usually 4 bytes on a 32-bit system.
But you cast c to char* - that is, pointer-to-char. Now, char is only 1 byte long, so (char *)c + 1 refers to the memory location 1 byte further on than c; which is in the middle of the int at c.
You then cast the result back to an int* and write 500 into it. So what you're doing is (probably) writing the 4-byte representation of 500 over the last 3 bytes of a[1] and the 1st byte of a[2]. Exactly what effect that will have depends on the endianness of your system, but that's basically what's going on.

Resources