c++ pass array to function question - c++

How is it possible to pass an array parameter to a function, and calculate the size of the array parameter? Because every time i try to calculate it, the return value is always 4.
Thanks the fast replies. I'm going to pass the size of the array as well then. Or i give a shot to vectors. Thanks

You can do it using templates as described here:
template<size_t Size>
void AcceptsArray( ParameterType( &Array )[Size] )
{
//use Size to find the number of elements
}
it is be called like this:
ParameterType array[100];
AcceptsArray( array ); //Size will be auto-deduced by compiler and become 100
The only drawback is that you now have a templated function and that increases code bloat. This can be addressed by redirecting the call to a non-templated function that accepts the address of the first element and the number of elements.

This is (one of) the difference between arrays and pointers. Taking the size of an array results in its size in bytes, whereas taking the size of a pointer yields the size of pointers on that system. However, whenever you pass an array to a function, it decays to a pointer, the size of which is always the same no matter what type of pointer it is (4 on a 32 bit machine).
So technically, it's impossible to pass an array into a function since whenever you try, it becomes a pointer.
You'll need to pass the size of the array in to the function as well, or better yet if you can, use std::vector or std::array, or std::string if you're using the array as a C-style string.

In C++ it is considered a bad pratice to use raw arrays. You should consider using std::vector or boost::array instead.
It is difficult to calculate the size of an array if you do not keep track of the size or supply some sort of an guardian value at the end. In C-strings (not std::strings), for example, the '\0' character marks the end of the string (a char array).

This works with g++:
template <typename T>
std::size_t size_of_array (T const & array)
{
return sizeof (array) / sizeof (*array);
}
int main ()
{
int x [4];
std::cout << "size: " << size_of_array (x) << '\n';
}
I guess it is because the function is inlined, but still it seems the array does not decay in this case. Can somebody explain why?

If you are using c arrays it's not possible because they're automatically casted to pointer when passing it to a function. So 4 is the size of the pointer.
Solution: use std::vector
#include <vector>
int carray[] = {1,2,3,4};
std::vector<int> v(carray, carray + sizeof(carray)/sizeof(int));
my_function(v);

Related

How to get size of an array decayed into a pointer in C++ [duplicate]

My function receives an array as a parameter but the array decays to a pointer so sizeof() doesn't work. I'm not allowed to import any extra libraries and the array was passed as int arr[]. when I searched it up, most people just say to define it outside of the function and pass it in as an argument but I can't do that. so is there a way for me to get the array size?
There are three ways (well two really, as two of the ways are basically the same just with different classes):
Use std::vector instead of array and use the size function to get the number of elements
Use std::array instead (which is really the same as the first)
Use templates and pass the array by reference:
template<size_t N>
void my_function(int (&my_array)[N])
{
std::cout << "The number of elements in the array is " << N << '\n';
}
If you let the array decay to a pointer, all that you have is that pointer to a single element of your array. There's no information about the array itself, like its size. When using pointers you need to pass the size as a separate argument.
If you're not allowed to change the function signature, and the function only takes a pointer as an argument, there's really no way to get the size of the array. For an interview question this is probably the answer you should give.
If it's an assignment given at school or similar you have to talk to the teacher and tell them it's impossible, or come up with an algorithm where you don't need the size explicitly (like adding some kind of terminator to the array, similar to the way that C-style strings are terminated).

Is there a way to get the size of an array passed to a function?

My function receives an array as a parameter but the array decays to a pointer so sizeof() doesn't work. I'm not allowed to import any extra libraries and the array was passed as int arr[]. when I searched it up, most people just say to define it outside of the function and pass it in as an argument but I can't do that. so is there a way for me to get the array size?
There are three ways (well two really, as two of the ways are basically the same just with different classes):
Use std::vector instead of array and use the size function to get the number of elements
Use std::array instead (which is really the same as the first)
Use templates and pass the array by reference:
template<size_t N>
void my_function(int (&my_array)[N])
{
std::cout << "The number of elements in the array is " << N << '\n';
}
If you let the array decay to a pointer, all that you have is that pointer to a single element of your array. There's no information about the array itself, like its size. When using pointers you need to pass the size as a separate argument.
If you're not allowed to change the function signature, and the function only takes a pointer as an argument, there's really no way to get the size of the array. For an interview question this is probably the answer you should give.
If it's an assignment given at school or similar you have to talk to the teacher and tell them it's impossible, or come up with an algorithm where you don't need the size explicitly (like adding some kind of terminator to the array, similar to the way that C-style strings are terminated).

C++ multidimensional array member accessor

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[][].

C++ sizeof different result for the same value

I want to calculate the 'sizeof' array:
char* arr[] = { "abc", "def" };
When I call sizeof manually, immediately after the initialization of the array, it works fine. However if I pass the array to some function, It doesn't give the same result.
int test(char* b[]) {
return (int)sizeof(b);
}
int _tmain(int argc, _TCHAR* argv[])
{
char* arr[] = { "abc", "def" };
int p = test(arr); // gives 4
int k = sizeof(arr); // gives 8
...
}
So what's the problem? Sorry for the newbie question, but I really miss it.
When you use sizeof on arr in _tmain, you're taking the size of the array itself, which is 2 * sizeof(char*) = 2 * 4 = 8 on your architecture, because your char*s occupy 32 bits = 4 bytes.
When you use sizeof on b in test, you're taking the size of a pointer to the first element of the array, which is sizeof(char**) = 4 on your architecture. The reason you're taking the size of the pointer and not the array is that you can't pass arrays as such to functions - instead, you pass them via a pointer to their first element. The information about the actual size of the array is thus lost in the call. Put another way, the signature of your function test is equivalent to int test(char **b).
This is because when you call a function in C or C++, arrays decay to pointers.
In the first case, the compiler sees arr as an array; in the second case, all it sees is a pointer to a pointer.
At point where test is defined, compiler cannot see what b points to. So, sizeof gives the size of a pointer (actually, size of a pointer to pointers).
Inside main, it can see perfectly well that real size is two pointers.
There really is no such thing as passing array into function - only pointer to array is passed. The [] form is just syntactic sugar.
You lose the size information when calling test because you array decays to a pointer.
You have to pass the size of the array as additional parameter, or fix it in the parameter type.
Welcome to C++.
You cannot pass an array to a function at all. In C++, arrays decay to pointers most of the time. You are trying to pass an array but in fact passing a pointer, and your second sizeof evaluates to the size of that pointer.
You should not care about any of this. Arrays are specialized low-level data structures that should be only used to implement higher-level abstractions. Use std::vector instead.

Passing arrays as a reference

In C++ how can I pass an array as a reference when I don't know the size at compile time? So far, I found out that the only way to make it work is to use something like
const double( &numbers ) [size]
but it means that I need to know the size of the array at compile time, thus I cannot use it in an external function.
My questions are:
If I don't pass an array as a ( const double( &numbers ) [length] ), because for example I don't know its size, how do I make sure that it doesn't get copied, but it is referenced?
If I pass an array like in the above example, ( double array[] ) is it referenced or is it copied?
The other answers are great, but no one mention using templates to handle this. You should still make your function take a pointer and a size, but templates can fill that automatically for you:
void f( double const numbers[], std::size_t length )
{ ... }
template< std::size_t Length >
void f( double const (&numbers)[ Length ] )
{
return f( numbers, Length );
}
In C++, you should use std::vector.
In C/C++, you can't pass arrays as a copy. Arrays are always passed by reference.
EDIT
In C++, arrays passed by reference has different meaning. In both C and C++, arrays decay into a pointer to the first element of the array. Please check the comments below.
If I don't pass an array as a ( const double( &numbers ) [length] ),
because for example I don't know its size, how do I make sure that it
doesn't get copied, but it is referenced?
Yes, it means you're passing an array as reference,
void Foo(const double( &numbers ) [length]);
Note that the length is a constant integer.
If I pass an array like in the above example, ( double array[] ) is it
referenced or is it copied?
No, it is not copied. It means you're passing a pointer to your array which is equivalent to,
void Foo(const double *length);
A couple things:
C++ doesn't allow variable-sized arrays anyway. So all your arrays will need to have known sizes at compile time. So I'm not entirely sure if your initial question is even applicable since you won't be able to make an array with an unknown size in the first place.
When you pass an array, it is done by reference. It is not copied.
In any case, you'll probably want to consider using vector instead.
EDIT : See comments.
double average(const double *arr, size_t len){
// Compute average
return accumulate(arr, arr + len, 0) / (double)len;
}
int main(){
double array[10] = // Initialize it
cout << average(array, 10) << endl;
// Alternatively: This could probably be made a macro.
// But be careful though since the function can still take a pointer instead
// of an array.
cout << average(array, sizeof(array) / sizeof(double)) << endl;
return 0;
}
In C++, an array's name is just a constant pointer to its first element. A constant pointer means a pointer that's capable of changing whatever it points to, but it can't be changed to point to something else.
This means that whenever you pass an array, you're actually passing a constant pointer to that array. In other words, you're already passing it by reference, no need for extra efforts. To be more accurate, what is actually copied is that constant pointer, so the final (hopefully not-that-confusing) phrasing is that you're passing a constant pointer to the array by value.
If you don't know your array's size at compile time, just use a (normal) pointer to your data type instead of an explicit array. So whatever is T my_array[] (where T is a type, like int, double or even one of your classes) becomes T* my_array, and the syntax is exactly the same hereafter... my_array[i] will work fine (another syntax also exists, but not as elegant). For initialization, use the new operator:
T* my_array;
my_array = new T[3];
or
T* my_array;
my_array = new T[x];
where x is an integer (not necessarily constant as is the case with normal arrays). This way you can take this x from the user at runtime and create your "array" then. Just take care not to forget delete[] my_array after you finish using it to avoid memory leaks.
[Final Note] Using such a dynamically allocated array is a good choice only when you know exactly how many elements you want... either at compile time or even at runtime. So, for example, if after the user supplies his x you'll exactly be using those, that's fine. Otherwise you're facing the danger of overflowing your array (if you need more than x) - which usually crashes the application - or just wasting some space. But even if this is the case, you'll implement most of the functions you need for array manipulation yourself. That's why it's preferable to use containers provided by the C++ Standard Library, like std::vector (as Donotalo mentioned). I just wanted to elaborate on that point more.
Other languages like Java and Python do store the length of arrays at runtime. In C++ arrays, the length of the array is not stored. That means you need to store it manually somewhere.
Whenever you have a fixed size array on your code, the compiler knows the size of the array since it is reading it from the source code itself. But once the code get compiled, that length information is lost. For example:
void f1(double array[10]) {...}
The compiler won't enforce the size of the array. The following code will silently compile since the array parameter of f1 us just a pointer to the first element of an array:
void h1() {
double a[10];
double b[5];
f1(a); // OK.
f2(b); // Also OK.
}
Since the compiler ignores the static size of the array when passing it to a function, the only way you have to know the size of an arbitrarily sized array passed as a reference is to explicitly state the size:
void f2(double array[], size_t array_size) {...}
Then you can call that function with any array:
void h2() {
double a[10];
double b[19];
f2(a, sizeof(a) / sizeof(a[0]));
f2(b, sizeof(a) / sizeof(a[0]));
}
The parameter array_size contains the actual size of the array.
As a note, sizeof(array) only works on statically defined arrays. When you pass that array to another functions, the size information is lost.
An array is not the same as a pointer. However, an array of undefined size like the parameter of f2 is just a pointer to the first double element in the sequence:
void f3(double array*, size_t array_size) {...}
For any practicar purpose, f2 and f3 are equivalent.
This is exactly how std::vector works. Internally, a vector is a class with two fields: a pointer to the first element, and the number of elements in the vector. This makes things a little simpler when you want to accept an array of any size as a parameter:
void g(std::vector& v) {...}