Multidimensional arrays: don't the pointers point to their own addresses? - c

I'm a student learning C, trying to wrap my head around something.
Let's say you have some multidimensional array int multi[2][2]. The value of multi will be a pointer to the address of multi[0]. For simplicity, let's say that address is 1000. Dereferencing multi[0] extracts another address, this address the address of multi[0][0]. Dereferencing that, in turn, gets us the value (or returns the address for assignment if on the left side.)
Now, multi + 1 returns the address of the second pointer. Let's say that we have 4 byte ints (of which there are two per nested array), so the address returned by multi + 1 will be 1008. This address will contain the address of multi[1][0], which will be 1008.
So here I see a pattern: doesn't this mean that the address in multi[0], multi[1], and so forth, contains a pointer to its own address?

Arrays and pointers are different. This topic is often presented poorly in books.
In the case of int multi[2][2], this is a block of4 contiguous ints. There are no pointers involved. C's type system divides this block up into two sub-arrays, each containing 2 ints.
These expressions: multi, multi[0] denote arrays. When you use an expression that denotes an array, in a context other than sizeof or & , then a conversion is performed, and the result of that conversion is a pointer to the first element of the array.
This pointer is an rvalue, i.e. it has the same sort of status as x + y : it's a value you can work with, but it doesn't consume any storage (at least, it's not stored as part of the array); and you can't use the & operator on it.

The value of multi will be a pointer to the address of multi[0]
If multi, which is an array, is used in an expression, it is converted to a pointer to multi[0], the value of which is the address of multi[0]. An array, when used in an expression, is always converted to a pointer to its first element ... thus arrays in C aren't first class objects and cannot be passed to functions (only their addresses can) or assigned (memcpy is used to copy arrays).
Dereferencing multi[0] extracts another address, this address the address of multi[0][0]
There's no "extraction". dereferencing multi[0] yields an array, which is converted to a pointer to its first element. The value of this pointer is the address of multi[0][0]. All of these addresses have the same value, because they point to exactly the same place in memory ... the first of four ints.
Now, multi + 1 returns the address of the second pointer.
Again, there is no pointer in memory. multi + 1 refers to an array ... the second of two arrays of two ints. Using that array in an expression converts it to a pointer to its first element, multi[1][0].
Let's say that we have 4 byte ints (of which there are three per nested array), so the address returned by multi + 1 will be 1012.
Er, you declared int multi[2][2], which is two arrays each of which contains two arrays. So multi + 1 is 1008.
This address will contain the address of multi[1][0], which will be 1012.
It makes no sense to talk about addresses containing addresses. pointers contain addresses, but we have no pointers in memory here, we only have ints. multi[1][0] is an int and its address is 1008. multi[1] is an array of ints and its address is also 1008 ... of course, because its address is the same as the address of its first element.
So here I see a pattern: doesn't this mean that the address in multi[0], multi[1], and so forth, contains a pointer to its own address?
There are no addresses in multi[0] and multi[1], there are arrays (of ints). arrays have addresses, but in this case they don't contain addresses. The way to "see a pattern" is to think in terms of what's in memory. Here, you simply have a block of 4 ints -- two arrays of two ints each; arrays have no overhead or other extraneous content in C, they just have the data ... what you declare is what you get. The array is an abstraction, a grouping of items determined by its type and size, which exist only at compile-time and in the mind of the programmer. Thus, multi[0] contains an array, in the abstract model of a C program, but all there is in memory is four ints, the first two of which comprise that array.
The situation would be different with
int* multi[2];
There you have an array of two pointers to int; each pointer will point to an array of ints (once you set it to the address of an array of ints, usually obtained from malloc). Once you allocate memory for the subarrays and assign the two pointers, you can use this multi much the way you use the multi above, but the type, size, and memory layout of multi[0] and multi[1] are quite different in the two cases.

Related

Difference between array of pointers and pointer to array?

char string1[3][4]={"koo","kid","kav"}; //This is a 2D array
char * string[3]={"koo","kid","kav"}; //This is an array of 3 pointers pointing to 1D array as strings are stored as arrays in memory
char (*string1Ptr)[4]=string1; //This is a pointer to a 1D array of 4 characters
//I want to know differences between string1Ptr(pointer to array mentioned in question) and string(array of pointers mentioned in question). I only typed string1 here to give string1Ptr an address to strings
Besides the fact that string can point to strings of any size and string1Ptr can only point to strings of size 4 only(otherwise pointer arithmetic would go wrong), I don't see any differences between them.
For example,
printf("%s\n", string1[2]); // All print the same thing, ie, the word "kav"
printf("%s\n", string1Ptr[2]);
printf("%s\n", string[2]);
They all seem to perform the same pointer arithmetic.(My reason for assuming string and string1Ptr are almost similar besides for the difference I stated above)
So what are the differences between string and string1Ptr? Any reason to use one over the other?
PS: I'm a newbie so please go easy on me.
Also, I did check C pointer to array/array of pointers disambiguation, it didn't seem to answer my question.
char string1[3][4]={"koo","kid","kav"}; //This is a 2D array
char * string[3]={"koo","kid","kav"}; //This is an array of 3 pointers pointing to 1D array as strings are stored as arrays in memory
char (*string1Ptr)[4]=string1; //This is a pointer to a 1D array of 4 characters
Besides the fact that string can point to strings of any size and
string1Ptr can only point to strings of size 4 only(otherwise
pointer arithmetic would go wrong), I don't any differences between
them.
They are absolutely, fundamentally different, but C goes to some trouble to hide the distinction from you.
string is an array. It identifies a block of contiguous memory wherein its elements are stored. Those elements happen to be of type char * in this example, but that's a relatively minor detail. One can draw an analogy here to a house containing several rooms -- the rooms are physically part of and exist inside the physical boundaries of the house. I can decorate the rooms however I want, but they always remain the rooms of that house.
string1Ptr is a pointer. It identifies a chunk of memory whose contents describe how to access another, different chunk of memory wherein an array of 4 chars resides. In our real estate analogy, this is like a piece of paper on which is written "42 C Street, master bedroom". Using that information, you can find the room and redecorate it as you like, just as in the other case. But you can also replace the paper with a locator for a different room, maybe in a different house, or with random text, or you can even burn the whole envelope, without any of that affecting the room on C Street.
string1, for its part, is an array of arrays. It identifies a block of contiguous memory where its elements are stored. Each of those elements is itself an array of 4 chars, which, incidentally, happens to be just the type of object to which string1Ptr can point.
For example,
printf("%s\n", string1[2]); // All print the same thing, ie, the word "kav"
printf("%s\n", string1Ptr[2]);
printf("%s\n", string[2]);
They all seem to perform the same pointer arithmetic.(My reason for
assuming string and string1Ptr are almost similar besides for the
difference I stated above)
... and that is where C hiding the distinction comes in. One of the essential things to understand about C arrays is that in nearly all expressions,* values of array type are silently and automatically converted to pointers [to the array's first element]. This is sometimes called pointer "decay". The indexing operator is thus an operator on pointers, not on arrays, and indeed it does have similar behavior in your three examples. In fact, the pointer type to which string1 decays is the same as the type of string1Ptr, which is why the initialization you present for the latter is permitted.
But you should understand that the logical sequence of operations is not the same in those three cases. First, consider
printf("%s\n", string1Ptr[2]);
Here, string1Ptr is a pointer, to which the indexing operator is directly applicable. The result is equivalent to *(string1Ptr + 2), which has type char[4]. As a value of array type, that is converted to a pointer to the first element (resulting in a char *).
Now consider
printf("%s\n", string1[2]);
string1 is an array, so first it is converted to a pointer to its first element, resulting in a value of type char(*)[4]. This is the same type as string1Ptr1, and evaluation proceeds accordingly, as described above.
But this one is a bit more different:
printf("%s\n", string[2]);
Here, string is a pointer, so the indexing operation applies directly to it. The result is equivalent to *(string + 2), which has type char *. No automatic conversions are performed.
Any reason to use one over the other?
Many, in both directions, depending on your particular needs at the time. Generally speaking, pointers are more flexible, especially in that they are required for working with dynamically allocated memory. But they suffer from the issues that
a pointer may be in scope, but not point to anything, and
declaring a pointer does not create anything for it to point to. Also,
even if a pointer points to something at one time during an execution of the program, and its value is not subsequently written by the program, it can nevertheless stop pointing to anything. (This most often is a result of the pointer outliving the object to which it points.)
Additionally, it can be be both an advantage and a disadvantage that
a pointer can freely be assigned to point to a new object, any number of times during its lifetime.
Generally speaking, arrays are easier to use for many purposes:
declaring an array allocates space for all its elements. You may optionally specify initial values for them at the point of declaration, or in some (but not all) cases avail yourself of default initialization.
the identifier of an array is valid and refers to the array wherever it is in scope.
Optionally, if an initializer is provided then an array declaration can use it to automatically determine the array dimension(s).
* But only nearly all. There are a few exceptions, with the most important being the operand of a sizeof operator.
The difference between string1 and string is the same as the difference between:
char s1[4] = "foo";
char *s2 = "foo";
s1 is a writable array of 4 characters, s2 is a pointer to a string literal, which is not writable. See Why do I get a segmentation fault when writing to a string initialized with "char *s" but not "char s[]"?.
So in your example, it's OK to do string1[0][0] = 'f'; to change string1[0] to "foo", but string[0][0] = 'f'; causes undefined behavior.
Also, since string is an array of pointers, you can reassign those pointers, e.g. string[0] = "abc";. You can't assign to string1[0] because the elements are arrays, not pointers, just as you can't reassign s1.
The reason that string1Ptr works is because the string1 is a 2D array of char, which is guaranteed to be contiguous. string1Ptr is a pointer to an array of 4 characters, and when you index it you increment by that number of characters, which gets you to the next row of the string1 array.

Changing the array's base-address

Why can't I modify the base address of an array? Is it because the allocated memory would be lost? in that case, I can make an array using a pointer and change what the pointer points to and the allocated memory would be lost too, then what is the difference?
Arrays are objects all on their own, and not pointers. Consider a simpler object:
int a = 0;
Would you expect to be able to change its address? Of course not. An object is a region of storage with a type. The region of storage is identified by its address, so you won't expect to change it. And arrays are objects too. When you declare
int b[8] = {0};
you declare an object, the size of eight integers, that will occupy some storage. You can't change its address any more than you can change the address of any single int.
You have probably been told that arrays are pointers. But they are not! They may be converted, even implicitly, to a pointer more often than not, but they are still object types. Pointers often stand in for arrays because the address of the first element is enough to reach any other element with pointer arithmetic, but the pointer is not the array object itself. The difference becomes apparent when you inspect their object properties. For instance:
sizeof(b) != sizeof(int*)
The object b is not the size of a pointer, indeed it is the size of 8 integers, likely larger than a pointer.

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

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

I am trying to construct an m-way tree and I am having trouble visualizing an array of pointers pointing to different instances of the B_tree node class (this basically creates the array type nodes and includes all functions associated with the tree such as count, insert etc)
Are there any tips/tricks to visualizing an array of pointers for this case? Are there any good links/resources for explanation of array of pointers? (I did not find the common search results on google that helpful)...
Here is a picture of an array of pointers, they aren't pointing to anything, but this is a visualization of an array of pointers. Here is a link explaining arrays of pointers http://ee.hawaii.edu/~tep/EE160/Book/chap9/section2.1.4.html. Enjoy.
Array with pointers is just like a usual array with a maximum number of size. Each position of the array it does not hold an integer or float or char or a struct. It holds a pointer.
What a pointer is ?
Imagine the computer's memory like a huge array which hold different kind of values. The variable which holds the pointer what it actually holds is the address of a block of memory. It does not hold the value of an integer but if you have int *a; , it means that the variable a which is store in a memory address hold the address of something which is integer.
The pointer always holds 4 bytes. Therefore an array with pointers means that each positions shows the memory address of something. If you have an integer array with pointers of size 10, means that each position shows the address of a memory block( this block stores an integer). So the array holds 10 pointers and each one of them shows to an integer.

Resources