Understand pointers in C - c

I'm reviewing my C skills, and I'm struggling to understand some bits.
Here's my understanding of C and pointers.
Every time I declare a variable, C stores the value in memory.
int num = 12; // The 12 is stored somewhere in memory, let's say has address 0x54
To get the memory address of variable "num" we do:
printf("%p", &num); // this returns the 0x54
if I want to create a pointer, that points to the same value of "num", I do:
int *ptr = # // create a pointer and point him to 0x54
If I check both address:
printf("%p\n", &num); // prints 0x54
printf("%p\n", ptr); // prints 0x54
printf("%p\n", &ptr); // prints 0x94 is the address of the pointer itself
After the above...
I don't understand the output of my program.
I'm reading this book, and the author says that we can treat pointers as arrays and vice versa (except in some cases [if I understood correctly]).
int ages[] = { 23, 43, 12, 89, 2 };
printf("1-%d\n", ages[0]);
printf("1-%d\n", ages[1]);
printf("2-%p\n", &ages[0]);
printf("2-%p\n", ages);
printf("2-%p\n", &ages);
printf("3-%d\n", *(&ages[1]));
printf("4-%p\n", *(&ages));
printf("5-%p\n", &ages[1]);
printf("6-%p\n", &ages+1);
printf("7-%d\n", *(*(&ages)+1));
printf("8-%ld\n", sizeof(1));
Output with questions in comments:
1-23 // value of position 0, OK
1-43 // value of position 1, OK
2-0x7fff1fd500f0 // adress of the beginning of array, OK
2-0x7fff1fd500f0 // same as above, OK
2-0x7fff1fd500f0 // because ages is not a pointer, same as above, OK
3-43 // get address of ages, advance 4 bytes and then give me the value that is in that address, OK
4-0x7fff1fd500f0 // give me the address of ages, and then give the value that is in that address. The address I have in the print number 2, why doesn't return the value and show me the address? **NOT OK**
5-0x7fff1fd500f4 // give me the address of the position 1 of the array, the address that contains the number 43, OK
6-0x7fff1fd50104 // why I don't get the same number of the print 5? How I jump from f0 to 104? **NOT OK**
7-43 // why I need pointer of pointer, **NOT OK**
8-4 // this was just trying to understand print 6, OK
Can someone explain me prints 4, 6 and 7, and let me know if I'm thinking correctly on the other prints.

Your confusions all boil down to two things: how operator precedence works and what &ages means.
Let's look at the latter first. Obviously &ages is a pointer. But what is it a pointer to? It's not a pointer to int. Instead, it's a pointer to the type int[5].
So let's look at this:
printf("4-%p\n", *(&ages));
If you have a pointer to int[5], and you use * on it, you get what it points to: int[5]. This then decays to a pointer when being passed to printf. Specifically, a pointer to the first element of the array.
This:
printf("5-%p\n", &ages[1]);
Is a matter of operator precedence. Using explicit parenthesis, this is &(ages[1]); [] has higher precedence than &. Well, we know that ages[1] is the second int in the array. Using & on it will return a pointer to the second element in the array.
In a similar way:
printf("6-%p\n", &ages+1);
Operator precedence tells us that this is really (&ages) + 1. And remember, what is &ages? That's right, a pointer to int[5].
When we perform pointer arithmetic, we add the size of the object being pointed to to the address. That object is int[5], whose size is 20. Or in hex, 0x14. Therefore, you get an address 0x14 bytes from the start of the array.
As for:
printf("7-%d\n", *(*(&ages)+1));
Operator precedence tells us that this expression is really *((*(&ages)) + 1). So you get a pointer to int[5], turn it back into an int[5], then add 1 to it. That requires decaying the int[5] into an int*, then using pointer arithmetic. Then you access the value at that address.

A pointer is not just an address, it's an address with an associated type, which has a size.
Thus when you increment a pointer to array type, it skips the whole array.
Another issue in the code is array decay, where an expression that denotes an array, such as a or *&a, decays to a pointer to the first item of the array.
It's an unfortunate implicit conversion that made sense at the time of early C.
In C++ it causes much trouble.

arrays are too much efficient but the overhead of an array is the size which cannot be changed at runtime.
pointer is a variable of some type which has its address and type of data it points to eg:
//int* iPtr = 7; error pointers stores addresses not values
int* iPtr = 0x00000000 //(NULL) points to this address (correct);
above a pointer points to an integer is initialized to point to 0x00000000 which is NULL
int a = 7;
int* iPtr = &a;
cout << "a: " << a << endl; // printing value of a; result is a: 7
cout << "&a: " << &a << endl; // printing address of a: result is: &a: 0x0018FF44
cout << "iPtr: " << iPtr << endl; // printing the address iPtr points to as you guess it is the address of a so the result: iPtr: 0x0018FF44
cout << "*iPtr: " << *iPtr << endl; // printing the value stored in the address the iPtr points to so the result is as you guess: *iPtr: 7
the powerful use of pointers: they are too much flexible but dangerous they can point to an array, variable, changing the address, size at runtime...
they are used by linked-list, oop (polymorphism...)
*** don't mess with pointers

For #4, it's likely the result of compiler optimization. Taking the address and then immediately dereferencing the resulting pointer is effectively a no-op, so the optimizer's likely simply eliding those operations leaving just ages as the argument and that's the value you're seeing.
For #6, you're finding the address of the ages array and adding 1 to it, which in pointer arithmetic means "add 1 * the size of the variable pointed at". A 5-element array, assuming 4-byte integers, is 20 bytes long and if you check 0x7FFF1FD500F0 + 0x14 you get the result 0x7FFF1FD50104 that you see.
An array isn't a pointer, exactly. It acts a lot like one, but &(ages) isn't identical to &(ages[0]). Both have the same apparent value, but the former is a pointer to a 4-byte integer and the latter is a pointer to a 20-byte array of 4-byte integers. You have to keep that in mind when working with pointers to array elements, remembering to take the address of an element when you want to work within the array and need eg. the address of element 0 of the array and not the address of the array itself.

Related

Change the address of a pointer

I have an Array of integers called bufferA[] and a pointer *ptr which points to the first integer in this Array bufferA[0]. Now, i would like to Change the pointer to point to the second value bufferA[1]. As i debbug the Code i can see that the address of the first integer in this Array is 0x1702 and now i would like to Change the pointer so it Points to 0x1704 which is the address of bufferA[1].
There is probably some way to make this without the pointer and just read the values of the Array, but this Array is passed from the ADC-module to the DMA-module and instead of just taking the Arrays (which makes storing them in the DMA useless) i would like to just take the address of the first value and change it up to read the following values.
i hope this somehow explains my Problem...
How about ptr = ptr + 1;? (Or equivalently in this context ptr += 1; or ptr++; or ++ptr;?) The C compiler knows how many bytes are taken up by the item that ptr points to, because of its declared type, and will automatically increment the pointer by the right number of bytes.
Arrays in C are always passed by reference, there is no copy operation of you pass it as an argument to a function! (This is a first gotcha of beginner C programmers)
Read something about pointers in C, first, but in short:
int a = 5; // declares a integer-type of value 5
int* pta; // declares a pointer-to-integer type
pta = &a // assigns the **address** of a to pta (e.g. 0x01)
int b = *pta // assingns the **value** of the address location that pta is pointing to into b
// (i.e. the contents of memory address 0x01, which is 5)
*pta = 4 // assigns 4 to the content of the memory address that pta is pointing to.
// now b is 5, because we assigned the value of the address that pta was pointing to
// and a is 4, because we changed the value of the address that pta was pointing to
// - which was the address where variable a was stored
The variable bufferA is itself a pointer to the address of the first element. bufferA + 1 gives you the address of the second element, because arrays are stored in memory sequentially.
Or if you want a more readable format:
&bufferA[0] is the same as bufferA (address of the first element(e.g 0x11)
&bufferA[1] is the same as bufferA + 1 (address of the second element(e.g 0x12)
buffer[2] is the same as *(buffer + 2) (value at the address of the third element)

Stack vs. heap pointers in C

I'm currently learning C and I'm confused about memory layout and pointers.
In the following code, it is my understanding that the array is allocated on the stack.
#include <stdio.h>
int main () {
int x[4];
x[0] = 3; x[1] = 2; x[2] = 1;
printf("%p\n",x);
printf("%p\n", &x);
}
My question is, why do the two print calls output the same value?
I tried a similar snippet using malloc (allocate on the heap), and the values differ.
#include <stdio.h>
#include <stdlib.h>
int main () {
int *x = malloc(sizeof(int) * 4);
x[0] = 3; x[1] = 2; x[2] = 1;
printf("%p\n",x);
printf("%p\n", &x);
}
The reason is that unlike you were probably taught, arrays are not pointers. Arrays in C decay into pointers1 under some circumstances. When you pass an array to a function, it decays into a pointer to the first element. The address of that element is the same as the address of the entire array (an address is always to the first byte of an object).
What you get from malloc is not an array, but the address of a chunk of memory. You assign the address to a pointer. But the pointer and the chunk are separate entities. So printing the value of the pointer, as opposed to its address, yields different results.
(1) Decay is a fancy term for a type of implicit type conversion. When an array expression is used in most places (such as being passed as an argument to a function that expects a pointer), it automatically turns into a pointer to its first element. The "decay" is because you lose type information, i.e. the array size.
Your two print calls print the same value because one tries to print the array, which decays to a pointer to the array, and the other prints the address of the array. A pointer to the array contains the address of the array, so they're the same value.
In the second case, one prints the value of x, the other prints the address of x. Since x is a pointer to the block of memory you allocated, these must be different values.
So in the first case, all you have is an array (x). In the second case, you have an allocated block of memory (unnamed) and a pointer to that allocated block (x).
It is perhaps surprising that one can indeed take the address of a whole array, partly because one doesn't need to very often. The array in a sense is a single object, which has one address, which is the address of its first byte. Like with all objects, the address is obtained with the address operator, &.
The first element of an array (like all of its elements) has an address, too, which is the address of its first byte. A pointer to its first element is what the array type is "adjusted" to when it is passed as an argument to a function.
These two bytes are identical, and have the same address. But they have different types, which becomes obvious if you add 1 to them and print them again.
The pointer y, by contrast, is its own distinct object (probably 4 or 8 bytes in size; enough to store an address in it). Like any object it has an address which can be obtained with the & operator. Perhaps confusingly, it also contains an address, in this case the address of the first byte of the array. The two are of course not equal: The pointer object resides at a different location than the array (namely next to it on the stack, even if Olaf doesn't like that).
Minor remark: You use %p for printing pointers, which is good. If you do that, you should strictly spoken cast the pointer which you print to a void pointer: printf("%p\n", (void *)x);.

what is special of the array name in c

int a[5] = {1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d", *(a+1),*(ptr-1));
the result is 2,5.
here is my question: why &a equal to a? a pointer to the first element in the array,so is it right to think &a is get the address of the pointer a? why type of &a is int(*)[5] ? this means &a<=> a[0][5]?
if i write this:
int b = 1;
int *cx = &b;
int *dx = (int *)(&cx + 1);
printf("%d %d", *(cx), *(dx -1));
there will have a question.
what is special of the array name in c?
a[0][5] is not valid. You are assuming that a is a pointer. a is not a pointer. It is an array. It decays to a pointer in expressions.
&a is a constant address value that points to the array a.
Array is a collection of similar datatypes stored in contiguous memory location.
case 1: Normally array name represents the Base Address of the array. According to this a and gives the base address. You Know &a gives The base address
case 2: A pointer to the first element in the array, Gives you the Base address of the array.
int a[5] = {1,2,3,4,5};
int *ptr;
ptr=a; // Here p holds the address of the first element in the array
ptr=ptr+1; // address incremented to next element. now it will point to 2
printf("%d\n",*ptr); // it prints 2.
case 3: From your code
Normally a and &a are starting address. a+1 means in will point to the second element in the array. But &a+1 means it will point to the next array. it will increment the whole array size(that means in your case 20 bytes).
int a[5] = {1,2,3,4,5}; // consider base address is 1000. so &a+1 is 1020. that is next array(but here you did not have).
int *ptr=(int *)(&a+1); // you are assigning 1020 address to ptr. for checking print the address of ptr
printf("%d,%d", *(a+1),*(ptr-1)); // as i told a+1 will point to 2nd element. so it prints 2.
//ptr is pointing to 1020, you are decreasing one element so it point to 1016. the value at 1016 is 5.
//(how? 1 is 1000 means, 2 is 1004, 3 is 1008..... 5 is 1016(because integer needs 4 bytes of address for each elements)).
Remember in array elements are stored in Contiguous memory locations.
int b = 1; // consider address of b is 1000
int *cx = &b; // assingning to *cx
int *dx = (int *)(&cx + 1); // &cx is pointer address(it is not 1000, so consider &cx is 2000)
// &cx+1 means it points to 2004, and you are assigning to *dx
printf("%d %d", *(cx), *(dx -1)); // here *(cx) will print 1. but *(dx-1) means it point to 2000. we dont know what value is there.
// so it will print some garbage value.
First off a is array name which is nothing but a pointer (Address) to the first element of the array, a would contain value of memory location where first element of array is stored.
&a and a will give you same value as it is just a pointer.
Consider you are a class teacher and have gone to museum with students, you have to keep track of 100 students, in the same way there are more teachers with more students in the museum.
So after spending a while when you have get them all together. It would be difficult to identify children and pull them together. In the same way if array name does not exist then it would always be difficult to keep track of your elements.
Luckily, there is always a mentor boy in class who always keep the students together and if you find him you will find all 100 students :).
Same way we have pointer name which stores the address of the first element. Only using that you can get all the elements of array. It means to keep track of 100 elements (Students) I only need to keep one address (array name or mentor name) in my mind rather than all. Hence tracking and accessing becomes really simple.
Sorry to bore you with my story but It could give you a feel as to how special arrays are.
You can run the below code to get a clear idea about how it works in memory level:
int a[5] = {1,2,3,4,10};
int *ptr=(int *)(&a+1);
printf("%d\n",a);
printf("%d\n",&a[0]);
printf("%d\n",&a[1]);
printf("%d\n",&a[2]);
printf("%d\n",&a[3]);
printf("%d\n",&a[4]);
printf("%d\n",(&a+1));
printf("%d\n",(ptr-1));
printf("%d,%d", *(a+1),*(ptr-1));
Hope it helps

equating two 2d pointers-2d Arrays

I was trying the following code
#include<stdio.h>
int main()
{
int A[3][4] = {{1,2,3,4},{5,6,7,8,},{9,10,11,12}};
int **t = &A[0]; //I do this or **t = A,I guess both are equivalent
printf("%d %p\n\n",*t,A[0]);
return 0;
}
What I expected to happen:
Now t is a 2d pointer (pointer to pointer) holding the address of A[0] which in turn holds the address of A[0][0]. So *t should give me the value of A[0] ,that is the address of A[0][0] and **t should give me the value of A[0][0] ,which in this case is 1.
What I got:
*t gave the value of 1. And trying to find **t was not possible as it resulted in a Segmentation Fault.
Can anyone please tell why this is happening ?
I tried the following explanation,but not sure whether it is the "correct" explanation.
t holds the address of A[0] ,but since A is an array and A[0] is an Array Pointer (which is "not exactly" a pointer),C doesn't allocate memory for pointer A or A[0] specially UNLIKE other pointer variables. It allocates memory only for the array as a whole . So the address of A[0] and A[0] (which is the address of A[0][0]) are essentially the same ,both belong under one roof and are not like 'separate' entities . As a result t in-turn indirectly holds the address of A[0][0] and *t gives the value of A[0][0],which is 1.
Is the above explanation correct ?Kind of looks weird.
Arrays are not pointers.
Well, even more...
Multiple-dimensional arrays are not double, triple, etc. pointers.
So all you have is wrong, your program invokes undefined behavior several times, and there's nothing you can expect.
Given that arrays are contiguous in memory, you can rewrite your example like this:
int A[3][4] = {{1,2,3,4},{5,6,7,8,},{9,10,11,12}};
int *p = &A[0][0];
printf("%d %d %p\n", A[0][0], *p, (void *)p);
I tried the following explanation,but not sure whether it is the "correct" explanation.
Not quite, but it's somewhat close.
t holds the address of A[0] ,but since A is an array and A[0] is an Array Pointer
A[0] is an array, specifically, its type is int[4].
(which is "not exactly" a pointer),C doesn't allocate memory for pointer A or A[0] specially UNLIKE other pointer variables.
Arrays and pointers are fundamentally different types of entities. Don't confuse them.
The fact that in most circumstances an expression of type array of T is converted into a value of type pointer to T (pointing to the array's first element) sure contributes to the confusion, but one must not forget that it is a conversion. In particular, for higher-dimensional arrays, or arrays of arrays, the element type of the array is itself an array type, so the result of the conversion is a pointer to an array.
It allocates memory only for the array as a whole. So the address of A[0] and A[0] (which is the address of A[0][0]) are essentially the same,
No, they are essentially different, one - A[0] - is an array, int[4], the other - &A[0] - is a pointer to an array of four int, int(*)[4]. Neither is &A[0][0].
But when A[0] is converted to a pointer to its first element, &A[0][0], the resulting address usually is the same as the address of A[0] (usually, a pointer to an object holds the address of the byte with the lowest address belonging to the object, and since A[0] belongs to (is part of) the object A, the one with the lowest address, the first byte that is part of A[0] is the first byte that is part of A).
So &A[0] and &A[0][0] usually have the same representation, but one is an int(*)[4], the other an int*.
both belong under one roof and are not like 'separate' entities . As a result t in-turn indirectly holds the address of A[0][0] and *t gives the value of A[0][0], which is 1.
That part is, apart from the type mismatch that makes dereferencing t undefined behaviour, more or less correct. Formally, the undefined behaviour allows anything to happen.
In practice, if sizeof(int) == sizeof(int*), dereferencing t interprets the int 1 that is A[0][0] as an address, and if you print that as an int (yet another undefined behaviour), you get 1 printed. If sizeof(int*) == 2*sizeof(int), as is common on 64-bit systems, dereferencing t would usually interpret the two ints A[0][0] and A[0][1] together as an address - 0x200000001 or 0x100000002 depending on endianness probably.

Why do "a+1" and "&a+1" give different results when "a" is an int array?

int main()
{
int a[]={1,2,3,4,5,6,7,8,9,0};
printf("a = %u , &a = %u\n",a,&a);
printf("a+1 = %u , &a+1 = %u\n",a+1,&a+1);
}
how a and &a are internally interpreted?
Both statements print out addresses and are probably meant to explain pointer arithmetic.
a and &a are NOT the same, they have different types, but hold the same memory address.
&a is of type int (*)[10] (which acts like a pointer to an array)
a is of type int [10] (which acts like a pointer to a single element)
So when you add 1 keep those types in mind. The pointer will be offset by the size of the type that the address contains. a+1 offsets by the size of int, i.e. to the second element in the array. &a+1 offsets completely past the whole array.
Well, a is the address of the first element of the array, and &a is the address of the array, but obviously they both have the same address.
However when you add (or subtract) a number from a pointer the compiler takes the size of the data into consideration thus in your case (assuming the size of int is 4 bytes) a+1 will be bigger than a by 4 because you move the pointer one integer ahead, but &a+1 would be bigger by 40 because you more the pointer one ARRAY OF 10 INTEGERS ahead.

Resources