I'm a bit confused about pointer arrays and I just wanna make sure I'm right.
When I write int *arrit is just a pointer to an int variable, not an array yet. It is only that I initialize it (say with malloc) that it becomes an array. Am I right so far?
Also I have another question: were given (in school) a little function that is supposed to return an array of grades, with the first cell being the average. The function was deliberately wrong: what they did was to set
int *grades = getAllGrades();
And than they have decreased the pointer by one for the average 'cell'
*(grades - 1) = getAverage();
return *(grades - 1)
I know this is wrong because the returned value is not an array, I just don't know how to explain it. When I set a pointer, how does the machine/compiler know if I want just a pointer or an array?
(If I'm not clear its because I'm trying to ask about something that is still vague for me, my apologizes)
how does the machine/compiler know if I want just a pointer or an
array?
It doesn't, and it never will. Suppose you
int *a = malloc(3 * sizeof(int));
You just allsocated 12 bytes (assuming int is 4). But malloc only sees 12. Is that 1 big object or lots of little ones? It doesn't know. The only one who actually knows is you ;)
Now about your particular example,
int *grades = getAllGrades();
At this point, as you said, there's nothing to say whether grades points to an array. But you know it points to an array, and that's what's important. Or, maybe you know it doesn't point to an array. The key is you have to know what getAllGrades does, to know if it's returning an array or a pointer to 1 thing.
*(grades - 1) = getAverage();
return *(grades - 1)
This is not necessarily wrong, but it does look kind of sketch. If it is an array, you would expect grades[0] == *(grade + 0) to be the first element, so grades[-1] == *(grades - 1) looks like it would be before the first element. Again, it's not necessarily wrong; maybe in getAllGrades they did:
int* getAllGrades() {
int *grades = malloc(sizeof(int) * 10);
return grades + 1;
}
ie they scooched the start up by 1. It's been known to happen (look in Numerical Recipes in C) but it's kind of odd.
Arrays are not pointers. Pointers are not arrays.
Perhaps it would be clearer to say that array objects are not pointer objects, and vice versa.
When you declare int *arr, arr is a pointer object. That's all it is; it cannot be, and never will be, an array.
When you execute arr = malloc(10 * sizeof *arr);, (if malloc() doesn't fail, which you should always check), arr now points to an int object. That object happens to be the first element of a 10-element array of int (the one created by the malloc call). Note that there is such a thing as a pointer to an array, but this isn't it.
Arrays, in a very real sense, are not first-class types in C. You can create and manipulate array objects as you can with any other type of objects, but you'll rarely deal with array values directly. Instead, you'll deal with the elements of an array object indirectly, via pointers to those elements. And in the case of the arr declaration above, you can perform arithmetic on the pointer to the first element to obtain pointers to the other elements (and you have to have some other mechanism to remember how many elements there are).
Any expression of array type, in most contexts, is implicitly converted to a pointer to the array's first element (the exceptions are: the operand of a unary & operator, the operand of the sizeof operator, and a string literal in an initializer used to initialize an array (sub)object). That's the rule that makes it seem as if arrays and pointers are interchangeable.
The array indexing operator [] is actually defined to work on pointers, not arrays. a[b] is simply another way of writing *((a)+(b)). If a happens to be the name of an array object, it's first converted to a pointer, as I describe above.
I highly recommend reading section 6 of the comp.lang.c FAQ. (The link is to the front page, not directly to section 6, because I like to encourage people to browse the whole thing.)
I mentioned that there are array pointers. Given int foo[10];, &foo[0] is a pointer to an int, but &foo is a pointer to the entire array. Both point to the same location in memory, but they're of different types, and they behave quite differently under pointer arithmetic.
When I write int *arr it is just a pointer to an int variable, not
an array yet. It is only that I initialize it (say with malloc) that
it becomes an array. Am I right so far?
Well, yes and no :). arr is a pointer to (or the address of) some block of memory. Until arr is initialized it probably points to an invalid, or non-sense memory address. So it may be confusing to think of arr as a pointer to an int variable. For example, before the malloc, you can't store an integer in the location that it is pointing to.
Also, it may be easier to understand if you say that after the malloc, arr points to an array, it does not "become" an array. Before the malloc, arr points to some random non-sense location.
When I set a pointer, how does the machine/compiler know if I want
just a pointer or an array?
If you set a pointer (e.g. arr = <something>) you are just changing where the pointer points. That may be what you want. If don't want to change where arr points but you want to change the values stored in the memory where it is pointing you have to do it one element at a time (e.g. with a for loop that iterates over each element in the array).
You are right, the only difference between arrays and pointers is convention. Here's a picture of what memory must look like when the getAllGrades() function returns:
| secret malloc() stuff |
+-----------------------+
| average value |
+-----------------------+ ----\
grades* points here ---> | grade at index 0 | | by convention
+-----------------------+ | this stuff is
| grade at index 1 | | called grades[]
+-----------------------+ |
| grade at index 2 | |
+-----------------------+ .
| ... | .
Now, there is no difference between an array and a pointer. So, when the compiler sees *(grades - 1) it first subtracts 1 from the grades pointer. This is special pointer arithmetic so it knows to go one whole int block upwards, and points at the average value. Then it can operate on this value, for example to set the average with *(grades - 1) = getAverage().
An aside on array indexing: Array indexing gets compiled exactly like pointer arithmetic. For example, grades[2] gets compiled down to *(grades + 2) which does pointer arithmetic to move down 2 blocks to the memory address marked "grade at index 2" in my picture. This means you could change *(grades - 1) = getAverage() to grades[-1] = getAverage() and it would work exactly the same.
If you wanted to experiment you could do (-1)[grades] which compiles down to *(-1 + grades) and works as well, but that's stupid so don't do that :)
Related
If I have:
int A[10][20];
printf("%p",A[3]);
it will print the address of A[3][0].
However, I'd like to know if this one dimensional array A[3] containing pointers really exists, or it is calculated in some way.
The way you have defined A means that the compiler will allocate for it a contiguous block of memory large enough to hold 10 x 20 (200) integers; see here (scroll down to "Multidimesional arrays"). As I'm sure you realize, if you were to do printf("%p", A); you would see the address of the beginning of that allocated block.
Now, when the compiler sees the expression A[3], it will add what it calculates as the necessary amount of "integer sizes" to the base address (that of A, or A[0][0]); in this case, it will add "3" (the index specified) multiplied by the combined size of all the other dimensions (in this case, there's only one, which is 20).
So, in your case, there is no actual array of pointers; just a memory block that the compiler can interpret according to how you described any part(s) of it.
However, in a more versatile approach, one can actually define a 2D array in terms of an actual array of pointers, like so:
int **A;
A = malloc(10 * sizeof(int*));
for (int n = 0; n < 10; ++n) A[n] = malloc(20 * sizeof(int));
In this case, using printf("%p",A[3]); would still be valid, but it would give a very different offset value from printf("%p",A); or printf("%p",A[0]);.
It's also, perhaps, worth noting that, even though these two different declarations for A can both resolve an individual element through an expression like A[i][j] (but the compiler would evaluate the addresses differently), there is here scope for major confusion! When, for example, passing such an array to a function: if the function expects data allocated in the second form, and you give it an array defined in the first form (and vice versa), you're gonna get major undefined behaviour .
yes there is a way to calculate the position:
for A[i][j]
the position of the memory block will be
pos = A + i*(number_of_columns_in_each_row) + j
here A is the pointer to the first element of the array
However, I'd like to know if this one dimensional array A containing pointers really exists, or it is calculated in some way.
The way you defined the array A :
int A[10][20];
does not contain any pointers as elements of the array. it contains only integer elements.
if you want to make an array of pointers, which should be assigned to int-variables is defined like that:
int *A[10][20];
You also can set a pointer to the start of the array, which means element [0] [0]
by using:
int *pointer;
int *A[10][20];
pointer = &A;
You also be able to set the pointer slightly forwards according to each element by increase the pointer.
pointer++;
This question already has answers here:
how do arrays work internally in c/c++
(4 answers)
Closed 4 years ago.
I have a question about how C arrays are stored in memory. But I'm having trouble formulating the question, so here's my best try to put it into words. I have trouble with English. Let's say we have a three dimensional array:
int foo[2][3][4];
Elements can be accessed using either array or pointer notation:
foo[i][j][k]
*(*(*(foo + i) + j) + k)
We could think of the array as a pointer to a pointer to a pointer to an int, or, for example, a pointer to a 2 dimensional array like (*a)[2][3].
The problem in my thinking is this: I would have thought that in order to 'extract' values in the array, we'd only have to dereference the top level of the array (i.e. [i]) once, the second level (i.e. [j]) twice, and the third level (i.e. [k]) three times. But actually we always have to dereference three times to get to any value. Why is this? Or is this really the case?
I try to imagine the array structure in memory.
Apologies for my poor way to express this.
Your array of arrays of arrays foo is arranged like this in memory:
+--------------+--------------+--------------+--------------+--------------+--------------+--------------+--------------+----------+
| foo[0][0][0] | foo[0][0][1] | foo[0][0][2] | foo[0][0][3] | foo[0][1][0] | foo[0][1][1] | foo[0][1][2] | foo[0][1][3] | ... etc. |
+--------------+--------------+--------------+--------------+--------------+--------------+--------------+--------------+----------+
foo[0][0][0] will be at the lowest memory location, foo[1][2][3] will be at the highest.
And an important note: An array is not a pointer. It can decay to a pointer to its first element, but please don't "think of" an array as a pointer.
Another important note: The pointers &foo, &foo[0], &foo[0][0] and &foo[0][0][0] are all pointing to the same location, but they are all different types which makes them semantically different:
&foo is of the type int (*)[2][3][4]
&foo[0] is of the type int (*)[3][4]
&foo[0][0] is of the type int (*)[4]
And &foo[0][0][0] is of the type int *
Lastly a note about the array-to-pointer decay, it only happens in one step. That means foo decays to &foo[0], foo[0] decays to &foo[0][0], and foo[0][0] decays to &foo[0][0][0].
An array is not as plain as a storage location (memory address), but an object with a type and layout.
So in your example, foo is an array of 3 arrays of 4 arrays of int, whose length is 2. *f is an array of 4 arrays of int, and **f is an array of int.
Even though each level of dereferencing gives the same memory address, they're different because they have different types, and thus the data at the same location should be interpreted differently.
I have been following some examples that declare an int pointer
int *myInt;
and then turn that pointer into an array
myInt = (int*)malloc(1024);
this checks out
myInt[0] = 5;
cout << myInt[0]; // prints 5
myInt[1] = 7;
cout << myInt[1]; // prints 7
I thought an int pointer was a pointer to an int and never anything else. I know that pointers to strings just point to the first character of the string but it looks like the same sort of thing is happening here with an array of ints. But then if what we want is an array of ints why not just create an array of ints instead of a pointer to an int?
By the way I am interested in how this works in C not C++. This is in a C++ file but the relevant code is in C.
Is an int pointer an array of ints?
No.
I thought an int pointer was a pointer to an int and never anything else
That's right. Pointers are pointers, arrays are arrays.
What confuses you is that pointers can point to the first element of arrays, and arrays can decay into pointers to their first element. And what's even more confusing: pointers have the same syntax for dereferencing and pointer arithmetic that arrays utilize for indexing. Namely,
ptr[i]
is equivalent with
*(ptr + i)
if ptr is a pointer. Of course, similarly, arr[i] is the ith element of the arr array too. The similarity arises out of the common nature of pointers and arrays: they are both used to access (potentially blocks of) memory indirectly.
The consequence of this strong relation is that in some situations (and with some constraints), arrays and pointers can be used as if they were interchangeable. This still doesn't mean that they are the same, but they exhibit enough common properties so that their usage often appears to be "identical".
There is an alternative syntax for accessing items pointed by a pointer - the square brackets. This syntax lets you access data through pointers as if the pointer were an array (of course, pointers are not arrays). An expression a[i] is simply an alternative form of writing *(a+i)* .
When you allocate dynamic storage and assign it to myInt, you can use the pointer like a dynamic array that can change size at runtime:
myInt = malloc(1024*sizeof(int)); // You do not need a cast in C, only in C++
for (int i = 0 ; i != 1024 ; i++) {
myInt[i] = i; // Use square bracket syntax
}
for (int i = 0 ; i != 1024 ; i++) {
printf("%d ", *(myInt+i)); // Use the equivalent pointer syntax
}
* Incidentally, commutativity of + lets you write 4[array] instead of array[4]; don't do that!
Sort of, and technically no. An int pointer does point to the int. But an array of ints is contiguous in memory, so the next int can be referenced using *(myInt+1). The array notation myInt[1] is equivalent, in that it uses myInt pointer, adds 1 unit to it (the size of an int), and reference that new address.
So in general, this is true:
myInt[i] == *(myint + i)
So you can use an int pointer to access the array. Just be careful to look out for the '\0' character and stop.
An int pointer is not an array of ints. But your bigger question seems to be why both arrays and pointers are needed.
An array represents the actual storage in memory of data. Once that storage is allocated, it makes no significant difference whether you refer to the data stored using array notation or pointer notation.
However, this storage can also be allocated without using array notation, meaning that arrays are not necessarily needed. The main benefit of arrays is convenient allocation of small blocks of memory, i.e., int x[20] and the slightly more convenient notation array[i] rather than *(array+i). Thankfully, this more convenient notation can be used regardless of whether array came from an array declaration or is just a pointer. (Essentially, once an array has been allocated, its variable name from that point onwards is no different than a pointer that has been assigned to point to the location in memory of the first value in the array.)
Note that the compiler will complain if you try to directly allocate too big of a block of memory in an array.
Arrays:
represent the actual memory that is allocated
the variable name of the array is the same as a pointer that references the point in memory where the array begins (and the variable name + 1 is the same as a pointer that references the point in memory where the second element of the array begins (if it exists), etc.)
values in the array can be accessed using array notation like array[i]
Pointers:
are a place to store the location of something in memory
can refer to the memory that is allocated in an array
or can refer to memory that has been allocated by functions like malloc
the value stored in the memory pointed to by the pointer can be accessed by dereferencing the pointer, i.e., *pointer.
since the name of the array is also a pointer, the value of the first element in the array can be accessed by *array, the second element by *(array+1), etc.
an integer can be added or subtracted to a pointer to create a new pointer that points to other values within the same block of memory your program has allocated. For example, array+5 points to the place in memory where the value array[5] is stored.
a pointer can be incremented or decremented to point to other values with the same block of memory.
In many situations one notation will be more convenient than the other, so it is extremely beneficial that both notations are available and so easily interchanged with each other.
They are not the same. Here is the visible difference.
int array[10];
int *pointer;
printf ("Size of array = %d\nSize of pointer = %d\n",
sizeof (array), sizeof (pointer));
The result is,
Size of array = 40
Size of pointer = 4
If You do "array + 1", the resulting address will be address of array[0] + 40. If You do "pointer + 1", resulting address will be address of pointer[0] + 4.
Array declaration results in compile time memory allocation. Pointer declaration does not result in compile time memory allocation and dynamic allocation is needed using calloc() or malloc()
When you do following assignment, it is actually implicit type cast of integer array to integer pointer.
pointer = array;
Sanity-check questions:
I did a bit of googling and discovered the correct way to return a one-dimensional integer array in C is
int * function(args);
If I did this, the function would return a pointer, right? And if the return value is r, I could find the nth element of the array by typing r[n]?
If I had the function return the number "3", would that be interpreted as a pointer to the address "3?"
Say my function was something like
int * function(int * a);
Would this be a legal function body?
int * b;
b = a;
return b;
Are we allowed to just assign arrays to other arrays like that?
If pointers and arrays are actually the same thing, can I just declare a pointer without specifying the size of the array? I feel like
int a[10];
conveys more information than
int * a;
but aren't they both ways of declaring an array? If I use the latter declaration, can I assign values to a[10000000]?
Main question:
How can I return a two-dimensional array in C? I don't think I could just return a pointer to the start of the array, because I don't know what dimensions the array has.
Thanks for all your help!
Yes
Yes but it would require a cast: return (int *)3;
Yes but you are not assigning an array to another array, you are assigning a pointer to a pointer.
Pointers and arrays are not the same thing. int a[10] reserves space for ten ints. int *a is an uninitialized variable pointing to who knows what. Accessing a[10000000] will most likely crash your program as you are trying to access memory you don't have access to or doesn't exist.
To return a 2d array return a pointer-to-pointer: int ** f() {}
Yes; array indexing is done in terms of pointer arithmetic: a[i] is defined as *(a + i); we find the address of the i'th element after a and dereference the result. So a could be declared as either a pointer or an array.
It would be interpreted as an address, yes (most likely an invalid address). You would need to cast the literal 3 as a pointer, because values of type int and int * are not compatible.
Yes, it would be legal. Pointless, but legal.
Pointers and arrays are not the same thing; in most circumstances, an expression of array type will be converted ("decay") to an expression of pointer type and its value will be the address of the first element of the array. Declaring a pointer by itself is not sufficient, because unless you initialize it to point to a block of memory (either the result of a malloc call or another array) its value will be indeterminate, and may not point to valid memory.
You really don't want to return arrays; remember that an array expression is converted to a pointer expression, so you're returning the address of the first element. However, when the function exits, that array no longer exists and the pointer value is no longer valid. It's better to pass the array you want to modify as an argument to the function, such as
void foo (int *a, size_t asize)
{
size_t i;
for (i = 0; i < asize; i++)
a[i] = some_value();
}
Pointers contain no metadata about the number of elements they point to, so you must pass that as a separate parameter.
For a 2D array, you'd do something like
void foo(size_t rows, size_t columns, int (*a)[columns])
{
size_t i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < columns; j++)
a[i][j] = some_value;
}
This assumes you're using a C99 compiler or a C2011 compiler that supports variable length arrays; otherwise the number of columns must be a constant expression (i.e., known at compile time).
These answers certainly call for a bit more depth. The better you understand pointers, the less bad code you will write.
An array and a pointer are not the same, EXCEPT when they are. Off the top of my head:
int a[2][2] = { 1, 2, 3, 4 };
int (* p)[2] = a;
ASSERT (p[1][1] == a[1][1]);
Array "a" functions exactly the same way as pointer "p." And the compiler knows just as much from each, specifically an address, and how to calculate indexed addresses. But note that array a can't take on new values at run time, whereas p can. So the "pointer" aspect of a is gone by the time the program runs, and only the array is left. Conversely, p itself is only a pointer, it can point to anything or nothing at run time.
Note that the syntax for the pointer declaration is complicated. (That is why I came to stackoverflow in the first place today.) But the need is simple. You need to tell the compiler how to calculate addresses for elements past the first column. (I'm using "column" for the rightmost index.) In this case, we might assume it needs to increment the address ((2*1) + 1) to index [1][1].
However, there are a couple of more things the compiler knows (hopefully), that you might not.
The compiler knows two things: 1) whether the elements are stored sequentially in memory, and 2) whether there really are additional arrays of pointers, or just one pointer/address to the start of the array.
In general, a compile time array is stored sequentially, regardless of dimension(s), with no extra pointers. But to be sure, check the compiler documentation. Thus if the compiler allows you to index a[0][2] it is actually a[1][0], etc. A run time array is however you make it. You can make one dimensional arrays of whatever length you choose, and put their addresses into other arrays, also of whatever length you choose.
And, of course, one reason to muck with any of these is because you are choosing from using run time multiplies, or shifts, or pointer dereferences to index the array. If pointer dereferences are the cheapest, you might need to make arrays of pointers so there is no need to do arithmetic to calculate row addresses. One downside is it requires memory to store the addtional pointers. And note that if the column length is a power of two, the address can be calculated with a shift instead of a multiply. So this might be a good reason to pad the length up--and the compiler could, at least theoretically, do this without telling you! And it might depend on whether you select optimization for speed or space.
Any architecture that is described as "modern" and "powerful" probably does multiplies as fast as dereferences, and these issues go away completely--except for whether your code is correct.
I see this question a lot on SO. Maybe not in so many words... but time and again there is confusion on how arrays are different from pointers. So I thought I would take a moment to Q&A a few points about this.
For purposes of this Q&A we're going to assume a 32-bit system and the following have been declared:
char * ptr = "hello";
char arr[10] = "hello";
int iarr[10] = {0};
Here's a list of questions that surmise the confusion I see on SO. As I see new ones I'll add to my list of Q&A (others feel free to as well, and correct me if you see any mistakes!)
Isn't a pointer and an array basically the same thing?
Follow up: both *(ptr) and *(arr), or ptr[0] and arr[0] give the same thing, why?
How come arr and &arr is the same value?
Follow up: why do I get a different value printing arr+1 vs &arr+1?
1) Pointers are not arrays. Arrays are not pointers. Don't think of them that way because they are different.
How can I prove this? Think about what they look like in memory:
Our array arr is 10 characters long. It contains "Hello", but wait, that's not all! Because we have a statically declared array longer than our message, we get a bunch of NULL characters ('\0') thrown in for free! Also, note how the name arr is conceptually attached to the contiguous characters, (it's not pointing to anything).
Next consider how our pointer would look in memory:
Note here we're pointing to a character array some place in read only memory.
So while both arr and ptr were initialized the same way, the contents/location of each is actually different.
This is the key point:ptr is a variable, we can point it to anything, arr is a constant, it will always refer to this block of 10 characters.
2) The [] is an "add and deference" operator that can be used on an address. Meaning that arr[0] is the same as saying *(arr+0). So yes doing this:
printf("%c %c", *(arr+1), *(ptr+1));
Would give you an output of "e e". It's not because arrays are pointers, it's because the name of an array arr and a pointer ptr both happen to give you an address.
Key point to #2: The deference operator * and the add and deference operator [] are not specific to pointers and arrays respectively. These operators simply work on addresses.
3) I don't have an extremely simple answer... so let's forget our character arrays for a second and take a look at it this example for an explanation:
int b; //this is integer type
&b; //this is the address of the int b, right?
int c[]; //this is the array of ints
&c; //this would be the address of the array, right?
So that's pretty understandable how about this:
*c; //that's the first element in the array
What does that line of code tell you? If I deference c, then I get an int. That means just plain c is an address. Since it's the start of the array it's the address of the array and also the address of the first element in the array, thus from a value standpoint:
c == &c;
4) Let me go off topic for a second here... this last question is part of the confusion of address arithmetic. I saw a question on SO at one point implying that addresses are just integer values... You need to understand that in C addresses have knowledge of type. That is to say:
iarr+1; //We added 1 to the address, so we moved 4 bytes
arr+1; //we added 1 to the address, so we moved 1 byte
Basically the sizeof(int) is 4 and the sizeof(char) is 1. So "adding 1 to an array" is not as simple as it looks.
So now, back to the question, why is arr+1 different from &arr+1? The first one is adding 1 * sizeof(char)=1 to the address, the second one is adding 1 * sizeof(arr)=10 to the address.
This is why even though they are both "only adding 1" they give different results.