C++ determine size of array [duplicate] - c++

I am trying to write a function that prints out the elements in an array. However when I work with the arrays that are passed, I don't know how to iterate over the array.
void
print_array(int* b)
{
int sizeof_b = sizeof(b) / sizeof(b[0]);
int i;
for (i = 0; i < sizeof_b; i++)
{
printf("%d", b[i]);
}
}
What is the best way to do iterate over the passed array?

You need to also pass the size of the array to the function.
When you pass in the array to your function, you are really passing in the address of the first element in that array. So the pointer is only pointing to the first element once inside your function.
Since memory in the array is continuous though, you can still use pointer arithmetic such as (b+1) to point to the second element or equivalently b[1]
void print_array(int* b, int num_elements)
{
for (int i = 0; i < num_elements; i++)
{
printf("%d", b[i]);
}
}
This trick only works with arrays not pointers:
sizeof(b) / sizeof(b[0])
... and arrays are not the same as pointers.

Why don't you use function templates for this (C++)?
template<class T, int N> void f(T (&r)[N]){
}
int main(){
int buf[10];
f(buf);
}
EDIT 2:
The qn now appears to have C tag and the C++ tag is removed.

For C, you have to pass the length (number of elements)of the array.
For C++, you can pass the length, BUT, if you have access to C++0x, BETTER is to use std::array. See here and here. It carries the length, and provides check for out-of-bound if you access elements using the at() member function.

In C99, you can require that an array an array has at least n elements thusly:
void print_array(int b[static n]);
6.7.5.3.7: A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.
In GCC you can pass the size of an array implicitly like this:
void print_array(int n, int b[n]);

You could try this...
#include <cstdio>
void
print_array(int b[], size_t N)
{
for (int i = 0; i < N; ++i)
printf("%d ", b[i]);
printf("\n");
}
template <size_t N>
inline void
print_array(int (&b)[N])
{
// could have loop here, but inline forwarding to
// single function eliminates code bloat...
print_array(b, N);
}
int main()
{
int a[] = { 1, 2 };
int b[] = { };
int c[] = { 1, 2, 3, 4, 5 };
print_array(a);
// print_array(b);
print_array(c);
}
...interestingly b doesn't work...
array_size.cc: In function `int main()':
array_size.cc:19: error: no matching function for call to `print_array(int[0u])'
JoshD points out in comments below the issue re 0 sized arrays (a GCC extension), and the size inference above.

In c++ you can also use a some type of list class implemented as an array with a size method or as a struct with a size member(in c or c++).

Use variable to pass the size of array.
int sizeof_b = sizeof(b) / sizeof(b[0]); does nothing but getting the pre-declared array size, which is known, and you could have passed it as an argument; for instance, void print_array(int*b, int size). size could be the user-defined size too.
int sizeof_b = sizeof(b) / sizeof(b[0]); will cause redundant iteration when the number of elements is less than the pre-declared array-size.

The question has already some good answers, for example the second one. However there is a lack of explanation so I would like to extend the sample and explain it:
Using template and template parameters and in this case None-Type Template parameters makes it possible to get the size of a fixed array with any type.
Assume you have such a function template:
template<typename T, int S>
int getSizeOfArray(T (&arr)[S]) {
return S;
}
The template is clearly for any type(here T) and a fixed integer(S).
The function as you see takes a reference to an array of S objects of type T, as you know in C++ you cannot pass arrays to functions by value but by reference so the function has to take a reference.
Now if u use it like this:
int i_arr[] = { 3, 8, 90, -1 };
std::cout << "number f elements in Array: " << getSizeOfArray(i_arr) << std::endl;
The compiler will implicitly instantiate the template function and detect the arguments, so the S here is 4 which is returned and printed to output.

Related

Why can't we pass int array[] to hoo(int* &p)?

In my understanding array in int array[]={1,2,3,4,5} is just a pointer to the first element of array. It means that array can be assigned to a pointer ptr of type int*.
Parameter int* &p in hoo will pass the argument by reference. It means we can change the passed argument to point to another value from within the hoo.
void hoo(int* &p, int n)
{
for (int i = 0; i < n; i++)
cout << p[i] << endl;
}
int main()
{
int array[] = { 1,2,3,4,5 };
// I can do this
int* ptr = array;
hoo(ptr, 5);
// but not this.
//hoo(array, 5);
}
Question
Why can't we pass int array to hoo without ptr ?
In my understanding array in int array[]={1,2,3,4,5} is just a pointer to the first element of array.
This is not correct. Arrays are arrays and pointers are pointers. They are distinct types with distinct properties. They are often confused because an array has the property that it will eagerly decay to a pointer to its first element.
hoo(array, 5); tries to convert array to an int* but the result of that conversion is an rvalue and can't be bound to a non-const reference. If, for example, you changed hoo to take a const reference it will compile fine :
void hoo(int* const &p, int n) { }
int main()
{
int array[] = { 1,2,3,4,5 };
hoo(array, 5);
}
In that case, you cannot change what p points to, making the use of a reference pointless.
When a function takes an int* & parameter, that is, a (non-move) reference to a pointer-to-an-int - then there needs to be a bona fide pointer variable to which that reference is referring. It can't be a temporary pointer value. Thus you can't do:
int x;
hoo(&x, 123);
because there's no pointer variable to refer to - just the temporary. It's essentially the same thing with your int[5]. There isn't actually an int* variable anywhere - there are just 5 ints. When you pass array to hoo(), what C++ does with that identifier is an array-to-pointer decay: It actually passes &(array[0]). So just like in the previous case, that won't compile.
The other answers already explain the problem. I want to suggest a change of coding practice.
Use of void hoo(int* &p, int n) as function declaration is very very old style. Using templates, you can let the compiler deduce the size and get a reference to the array, which obviates the need for using a pointer.
template <size_t N>
void hoo( int (&p)[N]) // The argument is a reference to an array of N elements.
{
for (int i = 0; i < N; i++)
cout << p[i] << endl;
}
The call to the function becomes natural.
int array[] = { 1,2,3,4,5 };
hoo(array);
If your function needs to be able to support dynamically allocated arrays as well, you can overload the function as follows.
void hoo(int* p, size_t N)
{
for (int i = 0; i < N; i++)
cout << p[i] << endl;
}
template <size_t N>
void hoo( int (&p)[N]) // The argument is a reference to an array of N elements.
{
hoo(p, N);
}

How to pass a stack matrix by reference in C++

My question is simple, if I have a matrix created on the stack rather than on the heap, such as int matrix[10][10], how can I pass it by reference? Or, pass it in a way that it doesn't pass the whole matrix as argument, but just its pointer or reference, or whatever. I use C++11.
void proc(/*WHAT GOES HERE?*/ matrix, int n){
matrix[n-1][n-1] = 7;
}
int main(){
int matrix[10][10];
proc(matrix, 10);
return 0;
}
You simply need:
// By reference:
void proc_ref(int (&matrix)[10][10]); // first dimension must have a size of 10
// By pointer:
void proc_ptr(int (*matrix)[10], int n); // n is the size of the first dimension
In the first case, matrix will be a reference to an array of 10 array of 10 ints ("reference to int[10][10]"), in the second case matrix will be a pointer to an array of 10 int ("pointer to int[10]").
In both cases you can use it like you want in proc:
matrix[i][j] = 42;
The second version allows passing matrix of various size such as int[14][10] or int[12][10] (as long as the second dimension as a size of 10). It also allows passing dynamically allocated array of array of 10 int:
int (*p)[10] = new int[42][10];
proc_ref (p); // Error
proc_ptr (p, 42); // Ok
int m[24][10];
proc_ref (p); // Error
proc_ptr (p, 24); // Ok
If you want to only allow square matrix declared with automatic storage duration, use the reference versions.
Note: You have to specify the second dimension of your matrix at compile time. If you want to be "generic" you could use a template:
template <size_t N>
void proc (int (&matrix)[N][N]);
Also, if you are using c++11, you should use std::array which is much more convenient while still doing exactly what you want (no dynamic allocation):
template <typename T, size_t N>
using matrix_t = std::array<std::array<T, N>, N>;
template <typename T, size_t N>
void proc (matrix_t<T, N> &matrix) {
matrix[N - 1][N - 1] = 7;
}
int main () {
matrix_t<int, 10> matrix;
proc(matrix);
}
Array might decay to pointer. You can declare the parameter type as a pointer (to array) like:
void proc(int (*matrix)[10], int n){
matrix[n-1][n-1] = 7;
}
Note the dimension won't be reserved when array decaying to pointer, means you might pass int [11][10] to proc() in this case.
If you don't want this, you can declare the parameter type as reference like:
void proc(int (&matrix)[10][10], int n){
matrix[n-1][n-1] = 7;
}
Only int[10][10] could be passed here.

Passing array as function parameter in C++ [duplicate]

This question already has answers here:
When a function has a specific-size array parameter, why is it replaced with a pointer?
(3 answers)
Closed 7 years ago.
I am aware that an array can be passed to a function in quite a few ways.
#include <iostream>
#include <utility>
using namespace std;
pair<int, int> problem1(int a[]);
int main()
{
int a[] = { 10, 7, 3, 5, 8, 2, 9 };
pair<int, int> p = problem1(a);
cout << "Max =" << p.first << endl;
cout << "Min =" << p.second << endl;
getchar();
return 0;
}
pair<int,int> problem1(int a[])
{
int max = a[0], min = a[0], n = sizeof(a) / sizeof(int);
for (int i = 1; i < n; i++)
{
if (a[i]>max)
{
max = a[i];
}
if (a[i] < min)
{
min = a[i];
}
}
return make_pair(max,min);
}
My code above passes only the first element while it should be passing an array (or technically, a pointer to the array) and hence, the output is 10, 10 for both max and min (i.e. a[0] only).
What am I doing wrong, I guess this is the correct way.
The contents of the array are being passed to the function. The problem is:
n = sizeof(a) / sizeof(int)
Does not give you the size of the array. Once you pass an array to a function you can't get its size again.
Since you aren't using a dynamic array you can use a std::array which does remember its size.
You could also use:
template <int N>
void problem1(int (&a) [N])
{
int size = N;
//...
}
No, you simply cannot pass an array as a parameter in C or C++, at least not directly.
In this declaration:
pair<int, int> problem1(int a[]);
even though a appears to be defined as an array, the declaration is "adjusted" to a pointer to the element type, so the above really means:
pair<int, int> problem1(int* a);
Also, an expression of array type is, in most contexts, implicitly converted to a pointer to the array's initial element. (Exceptions include an array as the operand of sizeof or unary &). So in a call to the above function:
int arr[10];
problem1(arr);
the array expression arr is equivalent to &arr[0], and that address (pointer value) is what's passed to the function.
Of course you can write code that does the equivalent of passing an array. You can make the array a member of a structure (but then it has to be of fixed length). Or you can pass a pointer to the initial element and pass a separate parameter containing the actual length of the array object.
Or you can use one of the C++ standard library classes that implement array-like data structures; then the length can be taken directly from the parameter.
I highly recommend reading section 6 of the comp.lang.c FAQ, which covers arrays and pointers. It's applicable to C++ as well (though it doesn't mention the C++ standard library).
In C++ language a function parameter declared as int a[] is immediately interpreted as and is equivalent to int *a parameter. Which means that you are not passing an array to your function. You are passing a pointer to the first element of an array.
Trying to apply the sizeof(a) / sizeof(int) technique to a pointer is useless. It cannot possibly produce the size of the argument arraay.
One alternative that hasn't been mentioned is writing your code as a template, and passing the array by reference so the template can deduce the size of the array:
template <class T, size_t n>
pair<T, T> problem1(T(&a)[n]) {
T max = a[0], min = a[0];
for (size_t i = 1; i < n; i++) {
if (a[i]>max) {
max = a[i];
}
if (a[i] < min) {
min = a[i];
}
}
return make_pair(max, min);
}
Note, however, that this will only work if you pass a real array, not a pointer. For example, code like this:
int *b = new int[10];
for (int i = 0; i < 10; i++)
b[i] = rand();
auto result = problem1(b);
...won't compile at all (because we've defined problem1 to receive a reference to an array, and b is a pointer, not an array).

Range-for-statement cannot build range expression with array function parameter

Why cannot build range expression passing an array as a function argument and using in a range-for-statement.
Thanks for the help
void increment(int v[]){
// No problem
int w[10] = {9,8,7,6,5,4,3,2,1,9};
for(int& x:w){
std::cout<<"range-for-statement: "<<++x<<"\n";
}
// error: cannot build range expression with array function
// parameter 'v' since parameter with array type 'int []' is
// treated as pointer type 'int *'
for(int x:v){
std::cout<<"printing "<<x<<"\n";
}
// No problem
for (int i = 0; i < 10; i++){
int* p = &v[i];
}
}
int main()
{
int v[10] = {9,8,7,6,5,4,3,2,1,9};
increment(v);
}
Despite appearances, v is a pointer not an array - as the error message says. Built-in arrays are weird things, which can't be copied or passed by value, and silently turn into pointers at awkward moments.
There is no way to know the size of the array it points to, so no way to generate a loop to iterate over it. Options include:
use a proper range-style container, like std::array or std::vector
pass the size of the array as an extra argument, and interate with an old-school loop
It's because of the way you pass the array to the function. As written it decays to pointer. Try
template<int N>
void increment(int (&v)[N])
{
for (int x : v) std::cout << "printing " << x << "\n";
}
int main()
{
int v[10] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 9 };
increment(v);
}
This runs because a reference to an array of N ints is passed in the function and (unlike pointers) range for loops can iterate on those.
The function parameter int v[] is adjasted to int * Pointers do not keep information whether they point a single object or the first object of a sequence of objects.
The range-based for statement in fact uses the same expressions as standard functions std::begin and std::end They cannot be defined for pointers without knowing the size of the array. They can be defined for arrays, not pointers.

c++ dynamic size of the array

I have got a small problem with 1D array in c++. I have got a function line this:
void func(int (&array)[???])
{
// some math here;
"for" loop {
array[i] = something;
}
}
I call the functions somewhere in the code, and before I made math I'm not able to know dimension of the array. The array goes to the function as a reference!, because I need it in the main() function. How I can allocate array like this?, so array with ?? dimension goes to the function as reference then I have to put the dimension and write to it some values.
Since you're using C++, why not use a std::vector<> instead?
Other have mentioned that you should use std::vector in C++ and they are right.
But you can make your code work by making func a function template.
template <typename T, size_t N>
void func(T (&array)[N])
{
// some math here;
"for" loop {
array[i] = something;
}
}
Use a pointer, not a reference:
void func(int *a, int N);
Or, easier, use a vector:
void func(std::vector<int> &a);
Vectors can be allocated by simply saying
std::vector<int> a(10);
The number of elements can be retrieved using a.size().
If the array you pass to func is a stack array, and not a pointer, you can retain its size by using a function template:
template <class T, size_t N>
void func(T(&array)[N])
{
size_t array_length = N; // or just use N directly
}
int main()
{
int array[4];
func(array);
}
That said, as others have already pointed out, std::vector is probably the best solution here.
As well as vector which has been suggested you could possibly use valarray which is also part of STL and is intended specificially to handle mathematical collections.
What you have to realize, is that arrays are pointers. A definition like int array[5] will allocate space for 5 integers on the stack and array will be the address of the first value. Thus, to access the first value in the array, you can write
array[0] or *array (which is the same as *(array + 0))
In the same way to retrieve the address of the third element, you can write
&array[2] or array + 2
Since arrays are pointers, you don't have to worry about the runtime size of your array if you would like to pass it to a function, simply pass it as a pointer:
void func(int *array)
{
int size;
//compute size of the array
for (int i = 0; i < size; ++i)
{
//do whatever you want with array[i]
}
}