When a multidimensional array is passed to a function, why does C++ require all but the first dimension to be specified in parameter li
A better way to ask this is to ask why C++ doesn't require the first dimension to be specified.
The reason is that for all arrays, you can't pass arrays by value to a function. If you try to declare a function taking an array the compiler will adjust the declaration to the corresponding pointer type.
This means that it doesn't matter what dimension you specify as the dimension doesn't form part of the function signature.
For example, these all declare exactly the same function.
void f(int *p);
void f(int p[]);
void f(int p[10]);
void f(int p[100]);
When navigating the array pointed to by p in the function, the only information that the copmiler needs is the size of the array elements, i.e. sizeof(int) in this case.
For more complex arrays exactly the same holds. These are all the same:
void g(Type p[][10][20]);
void g(Type (*p)[10][20]);
void g(Type p[10][10][20]);
void g(Type p[99][10][20]);
But these are all different from:
void g(Type p[][5][20]);
because adjusting the dimension of anything other than the outer array dimension affects the size of (at least) the outer array's elements meaning that the pointer arithmetic for navigating the array would have to change.
For example int a[n][m] is an array whose type is an int array of length m. In other words, the length of array is part of its type. And as for all function parameters, compiler need to know its type.
There is no such thing as multidimensional array in c++. It is just a syntax which looks like it. In int a[4] and int b[5] a and b are different types.
If you refer to static allocation, this is simple.
Because the blocks of memory are contiguous which means that the memory cells are one after each other and the compiler knows where the next cell is in memory.
For unidimensional array in memory looks like this:
http://cplusplus.com/doc/tutorial/arrays/arrays3.gif
For bidimensional array in memory looks like this:
http://i.msdn.microsoft.com/dynimg/IC506192.png
In short: The compiler doesn't need the dimension, because a array decays to a pointer. But any additional dimension is needed by the compiler, to calculate the correct location in memory.
At first you need to know that an array in C/C++ is a linear continuous object in memory. Which is very efficient.
Because an array in C/C++ is a linear continuous object in memory, an array will decay to a pointer. Copying the complete array will be a waste of time and memory and is not requiered. A pointer is anything needed to go through the array. To go through the array you can take the increment-operator or any calculation which evaluates to a valid address in the array. You can set a delimiter in the array itself i.e. '\0' in a String, or pass the length to the function seperatley to tell your code where the end of the array is.
With multi-dimensional arrays the thing is a little bit more complicated. A multi-dimesional array is still only a linear continuous object in the memory! But the compiler needs the information about the additional dimensions to calculate to correct position in memory, imagine the following:
char array[10][10]; // 0 - 99
correct:
// formal argument tells your compiler, that each column is 10 elements long
funca(int array[10][10]) {
// access to element 25 (2 * 10 + 4, the 10 is known through your formal argument, remember that an array is null based)
array[2][3] = 'x';
}
wrong:
// formal argument tells your compiler, that ech colum is 5 elements long
funcb(int array[10][5]) {
// access to element 15 (2 * 5 * + 4, the 5 is known through your formal argument, remember that an array is null based)
array[2][3] = 'x';
}
A note (or warning):
Arrays in Java, especiallay (irregular) multi-dimensional arrays are completely different.
Related
I know that when I want to pass an array to a function, it will decay into pointer, so its size won't be known and these two declarations are equivalent:
void funtion(int *tab, int size);
and
void funtion(int tab[], int size);
And I understand why. However, I checked that when I pass an array as a reference:
void funtion(int (&tab)[4]);
the compiler will know the size of the array and won't let me pass an array of different size as an argument of this function.
Why is that? I know that when I pass an array by address, the size isn't taken into account while computing the position of the ith element in the array, so it is discarded even if I explicitly include it in the function declaration:
void funtion(int tab[4], int size);
But what is different when I pass an array by reference? Why is its size known to the compiler?
Note: I'm interested in arrays whose size is known at compile time, so I didn't use any templates.
I found a similar question on Stack Overflow, however it doesn't answer my question - it doesn't explain why the compiler knows the size of the array, there is just some information on how to pass arrays to functions.
Because it can, and because checking adds extra safety. The compiler knows the size of the array because you tell it so, right there in the function declaration. And since that information is available, why wouldn't it use it to signal errors in your source code?
The real question is why your last example wouldn't do the same check. This is, unfortunately, another piece of C legacy - you are never passing an array, it always decays into a pointer. The size of the array then becomes irrelevant.
Could a check be added? Possibly, but it would be of limited use (since we are all using std::array now - right!?), and because it would undoubtedly break some code. This, for example:
void func (char Values [4]);
func ("x");
This is currently legal, but wouldn't be with an additional check on array size.
Because there is no odd implicit type change committed by the compiler in the case. Normally when you write:
void func(int[4]);
or
void func(void());
The compiler decides to "help" you and translates those into:
void func(int *);
or
void func(void(*)());
Funny thing though - it wouldn't aid you in such a way when you try returning one of those. Try writing:
int func()[4], func1()();
Ooops - surprise - compiler error.
Otherwise arrays are arrays and have constant size which can be acquired by using the sizeof operator.
This however is often forgotten because of the compiler behavior noted above and also because of the implicit pointer conversion applied to objects of array type when such isn't expected. And this is very often. Though here are the few exceptions when no implicit array object conversion is applied:
size_t arr[4],
(*parr)[3] = &arr, //taking the address of array
(&refarr)[3] = arr, //storing reference to array
sizearrobject = sizeof(arr); //taking the array object size
The above examples will trigger compiler error because of incompatible types on the second and third line.
I'm talking about the cases when arr object isn't automatically converted to something like this:
(size_t*)&arr
Well, there are several ways to pass an array to function. You can pass it by pointer an by reference, and there are ways to define or not to define it's size explicitely for both ways.
In your question you compare these 2 ways:
Pointer to first element: void f(int *arr)
Reference to an entire array: void f(int (&arr)[size])
You ask why you need to specify size only in one of these cases.
It looks like you assume that the only difference between them is the fact that one uses pointer and another uses reference. But this statement is incorrect, they have more differences: One is pointer to first element, but second is a reference to an entire array.
You can pass an array by pointer to an entire array:
void f(int (*arr)[size])
Compare it with your example, with passing by refence to an entire array:
void f(int (&arr)[size])
They are similar, they have similar syntax, they both explicitely define array size.
Also, consider this:
void f(int &arr)
It looks like passing a single int by reference, but you can pass an array of unknown size to it.
Pointer alternative to it is
void f(int *arr)
You ask why you need to specify array size only in one of those cases. It's because of the syntax you used, not because one is pointer and other is reference.
As I said, you can use pointer or reference. And you can specify array size or you can allow an array of any size to be used. These two are not connected.
// by pointer by reference
/* Any size */ void f(int *arr) void f(int &arr)
/* Specific size */ void f(int (*arr)[x]) void f(int (&arr)[x])
I have a class that has a large 2 dimensional array in it. It used to be a dynamic array allocated on the heap and now it is statically sized which I prefer.
private:
int fontTextureCoords_[100][7];
I had to add the type casting to the the accessor in order to return the array for access outside the class which is currently working okay, but I'm not sure it is safe or the correct way to handle this.
public:
inline int **getFontTextureCoords()
{
return (int**)fontTextureCoords_;
}
Is this safe / the correct way to do this or is there a more preferred method for returning a pointer to a multi-dimensional array?
That's not the correct way to do that and shouldn't compile. A 2d array is not convertible to a pointer to pointer. You'd have to return a pointer to an array, which is easiest to write using a typedef:
using T = int[7];
inline T* getFontTextureCoords() { return fontTextureCoords_; }
Although it'd be much better to just return a reference the full array:
using T = int[100][7];
inline T& getFontTextureCoords() { return fontTextureCoords_; }
You could also just std::array<std::array<int, 7>, 100>.
Maybe this diagram shows you the difference between the two types of multi-dimensional array declarations. (Sometime people don't understand this.)
The first one says a is a single block of 100 consecutive 7-int chunks, or 700 ints total, all together in one piece.
The second says a is an array of pointers, where each pointer points to a different chunk of ints, scattered all over memory.
The compiler needs to know this, because if you write a[i][j] it has to generate totally different code.
Casting an array such as int fontTextureCoords_[100][7]; to an int** is not right. It leads to undefined behavior.
If it is not too much, change getFontTextureCoords to:
inline int (*getFontTextureCoords()) [7]
{
return fontTextureCoords_;
}
and use it as:
int (*ptr)[7] = getFontTextureCoords();
If you have the option of using std::vector or std::array, it will be better to use them.
There are no multi-dimensional arrays in C/C++. There are only single dimenstional arrays. You can have a single-dimensional array, with every element of it being another single dimensional array. While there seem to be no difference, it is there and is very important.
This is exactly way transitive logic doesn not work. Everybody has gone through it. 'If single-dimensional arrays are passed as a pointer to the first elelement, 2-D arrays should be passed as a pointer to pointer to first element, etc'. But since it is not a two-dimensional array, but array of arrays, the logic can not be applied.
You can reason about it in the following way. Let's say, you have an array of types X.
X x[10];
How do you access element number 5? Easy -
x[5] = 42;
But what compiler does when it sees it? It does approximately this:
*(&x[0] + 5) = 42;
So it takes the address of the first element, and adds 5 to it to get to the address of your 5th element. But what adding 5 means? In bytes, how many bytes should be skipped from address of beginning of the array to arrive at requested memory location? Of course, 5 * sizeof(X). Now, if you have '2-D' array, declared like this:
X x[2][3];
And you try to work with it through the pointer to pointer:
px = (X**)x;
px[3][4] = 42;
Remember, to genereate the code for [][], compiler needs to express in the way of *(px + ). And something has to be the size of the array (as elements of your array are arrays). But you need to know array size for this, and as you can see, your px does not have any array size encoded in it. The only size it know is size of X, which is not enough.
Hope it makes sense, and explains why you can't use int** instead of x[][].
reading this question: What is the difference between int* x[n][m] and int (*x) [n][m]?
the correct reply stated this:
int arr[2][3];
int (*p1)[2][3] = &arr; // arr decays to int(*)[3], so we need to take the address
int (*p2)[2][3] = new int[42][2][3]; // allocate 42 arrays dynamically
the comment in that last line says it allocates 42 new arrays.
how does that work? can someone explain that to me?
thanks!
i would reply on that question, but i can't, so new question it is (:
new int[3] allocates 3 integers. Now new int[2][3] allocates 2 arrays, each of length 3 integers. Extending this further, new int[42][2][2] allocates 42 arrays, each of length 2 arrays, each of which in turn is, of length 2 integers. Declarations are really a recursive idea.
Allright, class time.
C++ Multidementional arrays vs. Jagged array
A multidemenional array (in C++) is a block of contiguous memory. It allocates the full number of elements, all in a line, and then access them by combining the index accessors. In essense. If I have an array defined by int x[2][3], it essentially turns x[i][j] into (&x[0][0]+i*3)[j].
sizoef(int[2][3])==24 (4bytes/int*2*3)
This type of array is often called a "static" array, because the size of the array must be allocated at compile time.
Note that the first size is irrelevent to this lookup. This makes it so that, when REFERENCING this type of array, we can exclude the smallest size from the type. This makes is so that both the functions below are valid and can work on the array x declared above:
int foo(int y[2][3]){ return y[1][1];}
int bar(int y[][3]){ return y[1][1];}
Note in this context, sizeof(y)==sizeof(void*), but that is a different problem all together.
The typeing convention for static arrays behaves differently than your used to. Part of the type information comes AFTER the variable declaration. This actually persists in typedefs as well:
typedef int a[4][20];
typedef int b[][20];
If you wanted to take the address of such a value type, then what you need to declare the pointer to this array type. That can be done with:
int (*xptr)[2][3] = &x;
The int (*var)[...] says that var is a pointer to a int[2][3].
When people say C++ arrays are pointers, they are NOT refering to this type of array: the array is a little more compilicated than a pointer here, though we could flatten it into a 1D array.
A jagged array (or dynamic array) is a single block of contiguose memory that is allocated in a linear fashion. This type of array is often called dynamic because the size does NOT need to be known at compile time.
Dynamic arrays are allocated with new or malloc (though you should only use new in C++). These types of array are strictly pointers. When I say int* a=new int[4], I allocate 4 integers: thats it.
We achieve mutlidementionality here by crating jagged arrays, which are arrays of pointers. So for example:
int** a = new int*[2];
for (int i = 0; i < 2; i++) { a[i]=new int[3];}
What your code does
int arr[2][3];//
int (*p1)[2][3] = &arr; // arr decays to int(*)[3], so we need to take the address
int (*p2)[2][3] = new int[42][2][3]; // allocate a dynamic array (42 elements long) of int[2][3] (sizeof(int[2][3])==24, so this allocates 42*24 bytes!)
It essentially allocates 43 int[2][3] in a row. So it actually comes up with all contiguous memory (though why it needs to be dynamic and not static is beyond me).
Personally, my rule is multidementional arrays "confusing as hell" and only use them in a local context now, but to each their own.
I was wondering how do arrays work in c. I end up with an hypothesis and I'd like to know if I am right or not.
We know arrays are a sequence of adjacent memory cases(boxes), where each box has the size of the type it stocks (i.e if INTs one box has a size = sizeof(int) and an array of 3 INTs takes in memory adjacent places of 3 sizeof(int) )
Now we also know that we can dynamically allocate memory for an array of a certain type (malloc in C, new in C++).
what makes me wonder is the fact that an array has for origin the the address of the first box of the array and the first value (the value in the later box) when calling it with the bracket [0] is array[0] == *(array+0) == *array (whether array was declared "type * array" or "type array[]" or "type array[size]") and "array" called that way whether define as a pointer or an array ("type * array" or "type array[]" or "type array[size]") is the address of the first box.
I end up thinking and I'd like a confirmation on this: arrays when even declared with the square brackets ([]) are actually in memory a sequence of n pointers each containing (having as a value not as an address) the address of a memory box Bi containing the actual value + those memory boxes (B0,...,Bn each containing the actual values). such that in the and when one declares "int array[5]" the program actually allocate 5 adjacent boxes of int pointers P0,P1,..,P4 and 5 int sized memory places scattered all over the computer memory B0,B1,...,B4 where the value of Pi is the address of Bi
Am I right or wrong!!?? Thank you!
arrays when even declared with the square brackets ([]) are actually in memory a sequence of n pointers each containing [...] the address of a memory box Bi containing the actual value + those memory boxes
Nope.
It sounds like you're puzzled how array[0] == *(array+0) == *array could be true both for an array declared as int array[10]; and int *array = ...;. A perfectly reasonable question; We're told that for a pointer ptr the expression *ptr gets the value the pointer is pointing at, so when we use the same syntax with an array where are the addresses that we're dereferencing?
Here's the secret: The array index operator ([]) does not work on arrays in C and C++. When you apply it to an array the language implicitly converts the array into a pointer to the array's first element. Thus adding to an array or dereferencing an array appears to behave the same as adding or dereferencing a pointer.
int array[10];
// These lines do exactly the same thing:
int *ptr1 = &array[0]; // explicitly get address of first element
int *ptr2 = array; // implicitly get address of first element
So arrays really are a contiguous set of elements in memory where each element really is the value, not a pointer to another location containing the value. It's just that the way arrays are defined means that they often convert to a pointer implicitly and so it seems like there are pointers when really there's just an implicit conversion.
Arrays are stored contiguously in the virtual memory. However, the physical memory addresses that they map to may or may not be contiguous.
And the array elements do not store a pointer to point to the next element. Only the value is stored.
Think of it as this:
array[n] is simply a syntactic sugar for *(array + n).
And no, there are no pointers, the array actually contains the values in a continuos memory range.
The array does not consist of any pointers. The elements of an array are stored on the heap whereas the reference to those elements is stored on the stack. If you declare an array called values of type int and it consists of 5 elements.
The variable values is a pointer to the first value values[0] stored on the heap, it is also referred to as the base address which is the address of the first element of the array. You might wonder that how would the code find the other elements of the array. values[1] can be dereferenced by *(values+1) or at a low level it is like this *(&values + n*sizeof(values[0])) where n is the index of the element you want to dereference.
So you get the other elements of an array by just adding the size of the element to the memory. This is because the elements of an array are stored side-by-side in memory or technically stated, the blocks of memory share the same border.
An array does not have any pointers, an array like data-structure that contains pointers is called a linked list.
You can learn about the internal working of arrays here
I am a little bit confused about pass an array in C/C++. I saw some cases in which the signature is like this
void f(int arr[])
some is like this
void f(int arr[], int size)
Could anybody elaborate what's the difference and when and how to use it?
First, an array passed to a function actually passes a pointer to the first element of the array, e.g., if you have
int a[] = { 1, 2, 3 };
f(a);
Then, f() gets &a[0] passed to it. So, when writing your function prototypes, the following are equivalent:
void f(int arr[]);
void f(int *arr);
This means that the size of the array is lost, and f(), in general, can't determine the size. (This is the reason I prefer void f(int *arr) form over void f(int arr[]).)
There are two cases where f() doesn't need the information, and in those two cases, it is OK to not have an extra parameter to it.
First, there is some special, agreed value in arr that both the caller and f() take to mean "the end". For example, one can agree that a value 0 means "Done".
Then one could write:
int a[] = { 1, 2, 3, 0 }; /* make sure there is a 0 at the end */
int result = f(a);
and define f() something like:
int f(int *a)
{
size_t i;
int result = 0;
for (i=0; a[i]; ++i) /* loop until we see a 0 */
result += a[i];
return result;
}
Obviously, the above scheme works only if both the caller and the callee agree to a convention, and follow it. An example is strlen() function in the C library. It calculates the length of a string by finding a 0. If you pass it something that doesn't have a 0 at the end, all bets are off, and you are in the undefined behavior territory.
The second case is when you don't really have an array. In this case, f() takes a pointer to an object (int in your example). So:
int change_me = 10;
f(&change_me);
printf("%d\n", change_me);
with
void f(int *a)
{
*a = 42;
}
is fine: f() is not operating on an array anyway.
WHen an array is passed in C or C++ only its address is passed. That is why the second case is quite common, where the second parameter is the number of elements in the array. The function has no idea, only by looking at the address of the array, how many elements it is supposed to contain.
you can write
void f( int *arr, int size )
as well, having latter (size) allows to not step outside the array boundaries while reading/writing to it
C and C++ are not the same thing. They have some common subset, though. What you observed here is that the "first" array dimension when passed to a function always results just in a pointer being passed. The "signature" (C doesn't use this term) of a function declared as
void toto(double A[23]);
is always just
void toto(double *A);
That is that the 23 above is somewhat redundant and not used by the compiler. Modern C (aka C99) has an extension here that lets you declare that A always has 23 elements:
void toto(double A[static 23]);
or that the pointer is const qualified
void toto(double A[const 23]);
If you add other dimension the picture changes, then the array size is used:
void toto(double A[23][7]);
in both C and C++ is
void toto(double (*A)[7]);
that is a pointer to an array of 7 elements. In C++ these array bounds must be an integer constant. In C it can be dynamic.
void toto(size_t n, size_t m, double A[n][m]);
They only thing that you have to watch here is that here n and m come before A in the parameter list. So better you always declare functions with the parameters in that order.
The first signature just passes the array with no way to tell how big the array is and can lead to problems with out-of-bounds errors and/or security flaws.\
The second signature is a more secure version because it allows the function to check against the size of the array to prevent the first versions shortcomings.
Unless this is homework, raw arrays are a bit out-dated. Use std::vector instead. It allows passing the vector around without having to manually pass the size as it does this for you.
The size of an array is not passed with the array itself. Therefore, if the other function needs the size, it will have it as a parameter.
The thing is, some functions implicitly understand the array to be of a certain size. So they won't need to have it specified explicitly. For example, if your function operates on an array of 3 floats, you don't need the user to tell you that it is an array of 3 floats. Just take an array.
And then there are those functions (let's call them "terrible" because they are) that will fill an array in with arbitrary data up to a point defined by that data. sprintf is probably the "best" example. It will keep putting characters in that array until it is finished writing them. That's very bad, because there's no explicit or implicit agreement between the user and the function as to how big this array could be. sprintf will write some number of characters, but there's no way for the user to know exactly how many get written (in the general case).
Which is why you should never use sprintf; use snprintf or _snprintf, depending on your compiler.
Anytime you need to know the size of the array, it needs to be provided. There is nothing special about the two forms of passing the array itself; the first parameter is the same either way. The second method simply provides the information needed to know the size of the array while the first does not.
Sometimes the array itself holds the information about its size, though. In your first example, for instance, perhaps arr[0] is set to the size of the array, and the actual data begins at arr[1]. Or consider the case of c-strings... you provide just a char[], and the array is assumed to end at the first element equal to \0. In your example, a negative value may act as a similar sentinel. Or perhaps the function simply doesn't care about the array's size, and will simply assume it is large enough.
Such methods are inherently unsafe, though... it is easy to forget to set arr[0] or to accidently overwrite the null terminator. Then, f suddenly has no way of knowing how much space it has available to it. Always prefer to provide the size explicitly, either via a size parameter like you show, or with a second pointer to the end of the array. The latter is the method generally taken by the standard library functions in C++. You still have the issue of providing an incorrect size, though, which is why in C++ it isn't recommended you ever use such an array in the first place... use an actual container that will keep track of that information for you.
The difference is that the second one includes a parameter that indicates the array size. The logical conclusion is that if you don't use such a parameter, the function doesn't know what the array size is. And this indeed turns out to be the case. In fact, it doesn't know you have an array. In fact, you don't have to have an array to call the function.
The array syntax here, without a specified size inside the square brackets, is a fake-out. The parameter is actually a pointer. For more information, please see http://c-faq.com/aryptr/index.html , especially section 4.