equating two 2d pointers-2d Arrays - c

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.

Related

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);.

Why the compiler is not showing error on expressions that use arrays like pointers?

I'm new in C programming and currently learning about array and strings. I'm quite confuse in this topic. Coming to my question-
Since an array (for ex- a[]={20,44,4,8}), the name in an expression decays into pointer constant,so whenever if i try to do pointer arithmetic for example- a=a+1 or anything like this the compiler shows error but when the same thing I write in printf() function it is showing the address of the first element rather than showing error. Why?
In an expression for example *(a+1)=2 first (a+1) will be evaluated and then * will dereference it. My question is that if a is a pointer constant then how it can point to any other memory location in an array and how this expression is perfectly legal?
I tried to search about this but couldn't get the accurate result.
Although an array name evaluates to a pointer in some expressions, your a = a+1 assignment tries to assign to an array, which is not allowed.
On the other hand, a+1 expression is allowed, and it evaluates to another pointer. When you pass this value to printf, the function happily prints it. Do not forget to cast the result to void* when you print:
printf("%p\n", (void*)(a+1));
if a is a pointer constant then how it can point to any other memory location in an array and how is *(a+1) expression perfectly legal?
For the same reason that 2+3, a combination of two constants, produces a value that is neither a 2 nor a 3. In your example, a+1 expression does not modify a. Instead, the expression uses it as a "starting point", computes a different value (which happens to be of type pointer), and leaves a unchanged.
The name of the array a is not quite the same as a pointer constant. It merely
acts like a pointer constant in some circumstances. In other circumstances it will
act quite differently; for example, sizeof(a) may have a much larger value
than sizeof(b) where b is truly a pointer.
This code is legal:
int a[] = {20,44,4,8};
int *b;
b = a;
b = b + 1;
because a is enough like a pointer that you can set b to point to the same
address but, unlike a, b really is a pointer and it can be modified.
The last line of code could just as well be:
b = a + 1;
because the right-hand side here is not trying to modify a; it is merely using
the address of the first element of a to compute a new address.
The expression *(a + 1) is effectively another way of writing a[1].
You know what will happen when you write a[1] = 2, right?
It will change what is stored in the second element of a.
(The first element is always a[0] whether you do anything with it or not.)
Storing a new value in a[1] doesn't change the location of the array a.
When array decays in to pointer, the resulting value is a rvalue. It's an value that cannot be assigned to.
So int[4] will become int*const, constant pointer to integer.
Q1:
Types in expression a = a + 1 are:
int[4] = int[4] + int
If we focus on addition first, array decays to pointer:
int[4] = int*const + int
int[4] = int*const // After addition
But now there is a problem:
int*const = int*const
In memory a is an array with 4 ints, and nothing more. There is no place where you could possibly store address with type int*. Compiler will show an error.
Q2:
Types in expression *(a+1)=2 are:
*(int[4] + int) = int
Again, array decays to pointer and addition happens:
*(int*const + int) = int
*(int*const) = int // int* is now equal to &a[1]
Dereferencing int*const is legal. While pointer is constant, value it points to is not:
int = int // Ok, equal types
Types are now perfectly compatible.

Pass an array to function using pointer in C?

First I declare an array a with 10 elements. Then I call the function bubbleSort
bubbleSort( a, 10);
where bubbleSort is a function declared as
void bubbleSort(int* const array, const int size)
My question is if "array" is a pointer- which means it stored the address of array a (array= &a [0]) then how can we understand these terms array[1], array[2], array[3]... in the function bubbleSort?
It is the bubble sort program and this part is very confusing for me.
array[1] means, by definition in the C standard, *(array+1). So, if array is a pointer, this expression adds one element to the pointer, then uses the result to access the pointed-to object.
When a is an array, you may be used to thinking of a[0], a[1], a[2], and so on as elements of the array. But they actually go through the same process as with the pointer above, with one extra step. When the compiler sees a[1] and a is an array, the compiler first converts the array into a pointer to its first element. This is a rule in the C standard. So a[1] is actually (&a[0])[1]. Then the definition above applies: (&a[0])[1] is *(&a[0] + 1), so it means “Take the address of a[0], add one element, and access the object the result points to.”
Thus, a[1] in the calling code and array[1] in the called code have the same result, even though one starts with an array and the other uses a pointer. Both use the address of the first element of the array, add one element, and access the object at the resulting address.
C defines operations of addition and subtraction of integers and pointers, collectively called pointer arithmetics. The language specification says that adding N to a pointer is equivalent to advancing the pointer by N units of memory equal to the size of an object pointed to by the pointer. For example, adding ten to an int pointer is the same as advancing it by ten sizes of int; adding ten to a double pointer is equivalent to advancing the pointer by ten sizes of double, and so on.
Next, the language defines array subscript operations in terms of pointer arithmetics: when you write array[index], the language treats it as an equivalent of *((&array[0])+index).
At this point, the language has everything necessary to pass arrays as pointers: take &array[0], pass it to the function, and let the function use array subscript operator on the pointer. The effect is the same as if the array itself has been passed, except the size of the array is no longer available. The structure of your API indirectly acknowledges that by passing the size of the array as a separate parameter.
You have an array of int, identified by the address of its first element.
array[1] Is equivalent to *(array + 1) which mean "The value of what is pointed by array + the size of one element, which is known as int because you prototyped it as int *"
When you declare a to be an array of size 10, the c program stores the address of a[0] in a and since the memory is allocated continuously therefore you can access the subsequent integers by using a[2], a[4] etc. Now when you copy a to array it is actually the address that gets copied and therefore you can access the integers using array[0], array[1] etc.

array of pointers

Consider the following code:
#include <stdio.h>
int main()
{
static int a[]={0,1,2,3,4};
int *p[]={a,a+1,a+2,a+3}; /* clear up to this extent */
printf(("%u\n%u\n%u",p,*p,*(*p))); /* how does this statement work? */
return 0;
}
Also is it necessary to get the value of addresses through %u,or we can use %d also?
Okay, you've created an array of integers and populated it with the integers from 0 to 4. Then you created a 4 element array of pointers to integers, and initialized it so its four elements point to the first four elements of a. So far, so good.
Then the printf is very strange. printf is passed a single argument, namely ("%u\n%u\n%u",p,p,(*p)). This is a comma-expression which means that the comma-separated expressions will be calculated in turn, and only the last one returned. Since the very first thing is a literal, and not an expression, I'd expect it to generate an error. However, without the extraneous parentheses, you have:
printf("%u\n%u\n%u\n",p, *p, *(*p));
This is legal. Three values are passed to printf, interpreted as unsigned integers (which actually only works on some systems, since what you are actually passing in are pointers in the first two cases, and they aren't guarateed to be the same size as unsigned ints) and printed.
Those values are p, *p and **p. p is an array, and so the value of p is the address of the array. *p is what p points to, which are the values of the array. *p is the first value, *(p+1) is the second value, etc. Now *p is the value stored in p[0] which is the address of a[0], so another address is printed. The third argument is **p which is the value stored at (*p), or a[0], which is 0
Do you have an extra pair of parens in your printf statement?
Anyway, you can think of this statement:
printf("%u\n%u\n%u",p,*p,*(*p));
like following a trail of pointers.
p is the pointer itself, printing it should print out the pointer's value which is the address of what it points to. In your case its an array of (int *)'s.
*p is a dereferencing operation. It allows access to the object that p points to. In the other answers you see notes made about *p being equivalent to p[0]. That's because p is pointing to the beginning of your structure, which is the start of the array.
**p is a dereferencing operation on the pointer object that p points to. Extending the example in the previous point, you can say that **p is equivalent to *(p[0]) which is equivalent to *(a) which is equivalent to a[0].
One tip that might help you when trying to decipher these sorts of statements is that keep in mind the precedence rules of C and insert parens between expressions in the statement to break up the statement. For the **p, inserting parens would do this: *(*p) which makes it clear that what you're doing is to follow two pointers to the final destination.
With those extra parentheses, the commas become comma operators so only the final **p is passed to printf. Since printf expects its first argument to be a pointer to a character string, and on most systems pointers
and integers have the same size, so the integer 0 is interpreted as a NULL pointer, and printf prints nothing at all. Or it crashes. That's the trouble with undefined behavior.
Your printf() arguments work like so:
p is an address (it's an array of pointers)
*p is also an address (it's equivalent to p[0], which is just a)
*(*p) is an integer (it's a[0])
My memory on C pointers is a tiny bit rusty, but let me see if I can recall.
p should be a memory location, it points to nothing else, other than p.
*p dereferences (goes to the memory location and returns the value there) p. since p itself is a pointer to pointers (*p[] can be also written as **p) when we dereference p we get the first value in the array definition, or the address of a.
**p dereferences *p. *p is the address of a. If we dereference that, we'll get the value we put in the first location of a, which is 0

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