Comparing arrays for equality in C++ - c++

Can someone please explain to me why the output from the following code is saying that arrays are not equal?
int main()
{
int iar1[] = {1,2,3,4,5};
int iar2[] = {1,2,3,4,5};
if (iar1 == iar2)
cout << "Arrays are equal.";
else
cout << "Arrays are not equal.";
return 0;
}

if (iar1 == iar2)
Here iar1 and iar2 are decaying to pointers to the first elements of the respective arrays. Since they are two distinct arrays, the pointer values are, of course, different and your comparison tests not equal.
To do an element-wise comparison, you must either write a loop; or use std::array instead
std::array<int, 5> iar1 {1,2,3,4,5};
std::array<int, 5> iar2 {1,2,3,4,5};
if( iar1 == iar2 ) {
// arrays contents are the same
} else {
// not the same
}

Since nobody mentioned it yet, you can compare arrays with the std::equal algorithm:
int iar1[] = {1,2,3,4,5};
int iar2[] = {1,2,3,4,5};
if (std::equal(std::begin(iar1), std::end(iar1), std::begin(iar2)))
cout << "Arrays are equal.";
else
cout << "Arrays are not equal.";
You need to include <algorithm> and <iterator>. If you don't use C++11 yet, you can write:
if (std::equal(iar1, iar1 + sizeof iar1 / sizeof *iar1, iar2))

You're not comparing the contents of the arrays, you're comparing the addresses of the arrays. Since they're two separate arrays, they have different addresses.
Avoid this problem by using higher-level containers, such as std::vector, std::deque, or std::array.

Array is not a primitive type, and the arrays belong to different addresses in the C++ memory.

Nobody mentions memcmp? This is also a good choice.
/* memcmp example */
#include <stdio.h>
#include <string.h>
int main ()
{
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
n=memcmp ( buffer1, buffer2, sizeof(buffer1) );
if (n>0) printf ("'%s' is greater than '%s'.\n",buffer1,buffer2);
else if (n<0) printf ("'%s' is less than '%s'.\n",buffer1,buffer2);
else printf ("'%s' is the same as '%s'.\n",buffer1,buffer2);
return 0;
}
Ref: http://www.cplusplus.com/reference/cstring/memcmp/

If you are reluctant to change your existing code to std::array, then use a couple of methods instead which takes non-type template arguments :
//Passed arrays store different data types
template <typename T, typename U, int size1, int size2>
bool equal(T (&arr1)[size1], U (&arr2)[size2] ){
return false;
}
//Passed arrays store SAME data types
template <typename T, int size1, int size2>
bool equal(T (&arr1)[size1], T (&arr2)[size2] ){
if(size1 == size2) {
for(int i = 0 ; i < size1; ++i){
if(arr1[i] != arr2[i]) return false;
}
return true;
}
return false;
}
Here is the demo. Note that, while calling, we just need to pass the array variables e.g. equal(iar1, iar2) in your case, no need to pass the size of arrays.

You are comparing the addresses instead of the values.

Both store memory addresses to the first elements of two different arrays. These addresses can't be equal hence the output.

If you are willing to use std::array instead of built-in arrays, you may use:
std::array<int, 5> iar1 = {1,2,3,4,5};
std::array<int, 5> iar2 = {1,2,3,4,5};
if (iar1 == iar2)

Right. In most, if not all implementations of C, the array identifier can be implicitly casted to a pointer to the first element (i.e. the first element's address). What you're doing here is comparing those addresses, which is obviously wrong.
Instead, you need to iterate over both arrays, checking each element against each other. If you get to the end of both without a failure, they're equal.

When we use an array, we are really using a pointer to the first element in the array. Hence, this condition if( iar1 == iar2 ) actually compares two addresses. Those pointers do not address the same object.

Related

This code fails, but why? Returning memory address of an integer pointer [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 1 year ago.
I need to read in an array to my function, extract the data, and then return an array from the function.
The array will only ever hold 2 values.
This is what I want to do in concept:
int myfunction(int my_array[1])
{
int f_array[1];
f_array[0] = my_array[0];
f_array[1] = my_array[1];
// modify f_array some more
return f_array;
}
I've read up about pointers etc but have got very confused and would appreciate a really basic example of how best to approach this!
Thanks!
You can't return n builtin array in c++.
If you are new to c++ and get confused about pointers you really don't want to use arrays (at least not builtin arrays). Use std::vector<int> instead, or if you only ever have a certain number of elements and want to express that (and really need the better performance) use boost::array<int, N>.(or even std::array<int, N>, if you program in C++11 (if you don't know whether or not you program in C++11 chances are that you don't).
For example:
std::vector<int> myfunction(const std::vector<int>& my_array) {
std::vector<int> f_array;
for(int i = 0; i < my_array.size(); ++i)
f_array.push_back(my_array[i]);
return f_array;
}
boost::array<int, 2> myfunction(const boost::array<int, 2>& my_array) {
boost::array<int, 2> f_array;
f_array[0] = my_array[0];
f_array[1] = my_array[1];
return f_array;
}
You can then make your copying code simpler (look up the constructors and memberfunctions of whatever class you decide to use, as well as STL algorithms). Example:
std::vector<int> myfunction(const std::vector<int>& my_array) {
std::vector<int> f_array(m_array);
...
return f_array;
}
As another point your code has a bug in it: you define my_array as int my_array[1], meaning its an array with one element, but you access two elements (my_array[0] and my_array[1]), the access to my_array[1] is out of bounds (int foo[N] has place for N items, starting at index 0 and going to index N-1). I assume you really mean int my_array[2].
std::array<int,2> myfunction(int * my_array)
{
std::array<int,2> f_array;
f_array[0] = my_array[0];
f_array[1] = my_array[1];
// modify f_array some more
return f_array;
}
Note that as a parameter, int my_array[1] is exactly identical to int my_array[1000], int my_array[] or int * my_array. It's just a pointer, and the size value is meaningless. This doesn't apply to regular array declarations, just parameters.
To ensure that you're only being passed arrays of size 2, you can take the array by reference:
std::array<int,2> myfunction(int (&my_array)[2])
If you ever only need two values I would have a look at std::pair, after all, that's what it's there for. It also have the proper copy (move in c++11) semantics to make this work correctly.
You can't return an array from a function, but you can add a second argument for the "out" array:
void foo(int array_in[], int array_out[], int array_size)
{
for (int i = 0; i < array_size; i++)
array_out[i] = array_in[i];
}
If you will have strictly 2 elements in array I suggest std::pair
typedef std::pair<int,int> int_pair;
int_pair myfunction(int_pair ip)
{
ip.first *= 0.12;
ip.second -= 355;
return ip;
}
You can't return an array in C or C++.
As you're working in C++, use a container class instead of a raw array. A std::vector or a boost::array would be good options.
An array with two values should be declared as int my_array[2]. Anyway, you can't copy arrays by value. You said you'll only ever have two ints in the object. So I suggest you use pair<int,int> instead.
using namespace std;
pair<int,int> myfunction(pair<int,int> my_array)
{
pair<int,int> f_array;
f_array.first = my_array.first;
f_array.second = my_array.second;
// modify f_array some more
return f_array;
}

Returning Arrays from C++ functions [duplicate]

I have an array int arr[5] that is passed to a function fillarr(int arr[]):
int fillarr(int arr[])
{
for(...);
return arr;
}
How can I return that array?
How will I use it, say I returned a pointer how am I going to access it?
In this case, your array variable arr can actually also be treated as a pointer to the beginning of your array's block in memory, by an implicit conversion. This syntax that you're using:
int fillarr(int arr[])
Is kind of just syntactic sugar. You could really replace it with this and it would still work:
int fillarr(int* arr)
So in the same sense, what you want to return from your function is actually a pointer to the first element in the array:
int* fillarr(int arr[])
And you'll still be able to use it just like you would a normal array:
int main()
{
int y[10];
int *a = fillarr(y);
cout << a[0] << endl;
}
C++ functions can't return C-style arrays by value. The closest thing is to return a pointer. Furthermore, an array type in the argument list is simply converted to a pointer.
int *fillarr( int arr[] ) { // arr "decays" to type int *
return arr;
}
You can improve it by using an array references for the argument and return, which prevents the decay:
int ( &fillarr( int (&arr)[5] ) )[5] { // no decay; argument must be size 5
return arr;
}
With Boost or C++11, pass-by-reference is only optional and the syntax is less mind-bending:
array< int, 5 > &fillarr( array< int, 5 > &arr ) {
return arr; // "array" being boost::array or std::array
}
The array template simply generates a struct containing a C-style array, so you can apply object-oriented semantics yet retain the array's original simplicity.
In C++11, you can return std::array.
#include <array>
using namespace std;
array<int, 5> fillarr(int arr[])
{
array<int, 5> arr2;
for(int i=0; i<5; ++i) {
arr2[i]=arr[i]*2;
}
return arr2;
}
$8.3.5/8 states-
"Functions shall not have a return type of type array or function, although they may have a return type of type pointer or reference to such things. There shall be no arrays of functions, although there can be arrays of pointers to functions."
int (&fn1(int (&arr)[5]))[5]{ // declare fn1 as returning refernce to array
return arr;
}
int *fn2(int arr[]){ // declare fn2 as returning pointer to array
return arr;
}
int main(){
int buf[5];
fn1(buf);
fn2(buf);
}
the answer may depend a bit on how you plan to use that function. For the simplest answer, lets decide that instead of an array, what you really want is a vector. Vectors are nice because the look for all the world like boring, ordinary values you can store in regular pointers. We'll look at other options and why you want them afterwards:
std::vector<int> fillarr( std::vector<int> arr ) {
// do something
return arr;
}
This will do exactly what you expect it to do. The upside is that std::vector takes care of making sure everything is handled cleanly. the downside is that this copies a very large amount of data, if your array is large. In fact it copies every element of the array twice. first it copies the vector so that the function can use it as a parameter. then it copies it again to return it to the caller. If you can handle managing the vector yourself, you can do things quite a bit more easily. (it may copy it a third time if the caller needs to store it in a variable of some sort to do more calculation)
It looks like what you're really trying to do is just populate a collection. if you don't have a specific reason to return a new instance of a collection, then don't. we can do it like this
void fillarr(std::vector<int> & arr) {
// modify arr
// don't return anything
}
this way you get a reference to the array passed to the function, not a private copy of it. any changes you make to the parameter are seen by the caller. You could return a reference to it if you want, but that's not really a great idea, since it sort of implies that you're getting something different from what you passed.
If you really do need a new instance of the collection, but want to avoid having it on the stack (and all the copying that entails), you need to create some kind of contract for how that instance is handled. the easiest way to do that is to use a smart pointer, which keeps the referenced instance around as long as anyone is holding onto it. It goes away cleanly if it goes out of scope. That would look like this.
std::auto_ptr<std::vector<int> > fillarr( const std::vector<int> & arr) {
std::auto_ptr<std::vector<int> > myArr(new std::vector<int>);
// do stuff with arr and *myArr
return myArr;
}
For the most part, using *myArr works identically to using a plain vanilla vector. This example also modifies the parameter list by adding the const keyword. Now you get a reference without copying it, but you can't modify it, so the caller knows it'll be the same as before the function got to it.
All of this is swell, but idiomatic c++ rarely works with collections as a whole. More normally, you will be using iterators over those collections. that would look something more like this
template <class Iterator>
Iterator fillarr(Iterator arrStart, Iterator arrEnd) {
Iterator arrIter = arrStart;
for(;arrIter <= arrEnd; arrIter++)
;// do something
return arrStart;
}
Using it looks a bit odd if you're not used to seeing this style.
vector<int> arr;
vector<int>::iterator foo = fillarr(arr.begin(), arr.end());
foo now 'points to' the beginning of the modified arr.
What's really nice about this is that it works equally well on vector as on plain C arrays and many other types of collection, for example
int arr[100];
int *foo = fillarr(arr, arr+100);
Which now looks an awful lot like the plain pointer examples given elsewhere in this question.
This:
int fillarr(int arr[])
is actually treated the same as:
int fillarr(int *arr)
Now if you really want to return an array you can change that line to
int * fillarr(int arr[]){
// do something to arr
return arr;
}
It's not really returning an array. you're returning a pointer to the start of the
array address.
But remember when you pass in the array, you're only passing in a pointer.
So when you modify the array data, you're actually modifying the data that the
pointer is pointing at. Therefore before you passed in the array, you must realise
that you already have on the outside the modified result.
e.g.
int fillarr(int arr[]){
array[0] = 10;
array[1] = 5;
}
int main(int argc, char* argv[]){
int arr[] = { 1,2,3,4,5 };
// arr[0] == 1
// arr[1] == 2 etc
int result = fillarr(arr);
// arr[0] == 10
// arr[1] == 5
return 0;
}
I suggest you might want to consider putting a length into your fillarr function like
this.
int * fillarr(int arr[], int length)
That way you can use length to fill the array to it's length no matter what it is.
To actually use it properly. Do something like this:
int * fillarr(int arr[], int length){
for (int i = 0; i < length; ++i){
// arr[i] = ? // do what you want to do here
}
return arr;
}
// then where you want to use it.
int arr[5];
int *arr2;
arr2 = fillarr(arr, 5);
// at this point, arr & arr2 are basically the same, just slightly
// different types. You can cast arr to a (char*) and it'll be the same.
If all you're wanting to do is set the array to some default values, consider using
the built in memset function.
something like:
memset((int*)&arr, 5, sizeof(int));
While I'm on the topic though. You say you're using C++. Have a look at using stl vectors. Your code is likely to be more robust.
There are lots of tutorials. Here is one that gives you an idea of how to use them.
http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html
This is a fairly old question, but I'm going to put in my 2 cents as there are a lot of answers, but none showing all possible methods in a clear and concise manner (not sure about the concise bit, as this got a bit out of hand. TL;DR 😉).
I'm assuming that the OP wanted to return the array that was passed in without copying as some means of directly passing this to the caller to be passed to another function to make the code look prettier.
However, to use an array like this is to let it decay into a pointer and have the compiler treat it like an array. This can result in subtle bugs if you pass in an array like, with the function expecting that it will have 5 elements, but your caller actually passes in some other number.
There a few ways you can handle this better. Pass in a std::vector or std::array (not sure if std::array was around in 2010 when the question was asked). You can then pass the object as a reference without any copying/moving of the object.
std::array<int, 5>& fillarr(std::array<int, 5>& arr)
{
// (before c++11)
for(auto it = arr.begin(); it != arr.end(); ++it)
{ /* do stuff */ }
// Note the following are for c++11 and higher. They will work for all
// the other examples below except for the stuff after the Edit.
// (c++11 and up)
for(auto it = std::begin(arr); it != std::end(arr); ++it)
{ /* do stuff */ }
// range for loop (c++11 and up)
for(auto& element : arr)
{ /* do stuff */ }
return arr;
}
std::vector<int>& fillarr(std::vector<int>& arr)
{
for(auto it = arr.begin(); it != arr.end(); ++it)
{ /* do stuff */ }
return arr;
}
However, if you insist on playing with C arrays, then use a template which will keep the information of how many items in the array.
template <size_t N>
int(&fillarr(int(&arr)[N]))[N]
{
// N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0])
for(int* it = arr; it != arr + N; ++it)
{ /* do stuff */ }
return arr;
}
Except, that looks butt ugly, and super hard to read. I now use something to help with that which wasn't around in 2010, which I also use for function pointers:
template <typename T>
using type_t = T;
template <size_t N>
type_t<int(&)[N]> fillarr(type_t<int(&)[N]> arr)
{
// N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0])
for(int* it = arr; it != arr + N; ++it)
{ /* do stuff */ }
return arr;
}
This moves the type where one would expect it to be, making this far more readable. Of course, using a template is superfluous if you are not going to use anything but 5 elements, so you can of course hard code it:
type_t<int(&)[5]> fillarr(type_t<int(&)[5]> arr)
{
// Prefer using the compiler to figure out how many elements there are
// as it reduces the number of locations where you have to change if needed.
for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
{ /* do stuff */ }
return arr;
}
As I said, my type_t<> trick wouldn't have worked at the time this question was asked. The best you could have hoped for back then was to use a type in a struct:
template<typename T>
struct type
{
typedef T type;
};
typename type<int(&)[5]>::type fillarr(typename type<int(&)[5]>::type arr)
{
// Prefer using the compiler to figure out how many elements there are
// as it reduces the number of locations where you have to change if needed.
for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
{ /* do stuff */ }
return arr;
}
Which starts to look pretty ugly again, but at least is still more readable, though the typename may have been optional back then depending on the compiler, resulting in:
type<int(&)[5]>::type fillarr(type<int(&)[5]>::type arr)
{
// Prefer using the compiler to figure out how many elements there are
// as it reduces the number of locations where you have to change if needed.
for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
{ /* do stuff */ }
return arr;
}
And then of course you could have specified a specific type, rather than using my helper.
typedef int(&array5)[5];
array5 fillarr(array5 arr)
{
// Prefer using the compiler to figure out how many elements there are
// as it reduces the number of locations where you have to change if needed.
for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
{ /* do stuff */ }
return arr;
}
Back then, the free functions std::begin() and std::end() didn't exist, though could have been easily implemented. This would have allowed iterating over the array in a safer manner as they make sense on a C array, but not a pointer.
As for accessing the array, you could either pass it to another function that takes the same parameter type, or make an alias to it (which wouldn't make much sense as you already have the original in that scope). Accessing a array reference is just like accessing the original array.
void other_function(type_t<int(&)[5]> x) { /* do something else */ }
void fn()
{
int array[5];
other_function(fillarr(array));
}
or
void fn()
{
int array[5];
auto& array2 = fillarr(array); // alias. But why bother.
int forth_entry = array[4];
int forth_entry2 = array2[4]; // same value as forth_entry
}
To summarize, it is best to not allow an array decay into a pointer if you intend to iterate over it. It is just a bad idea as it keeps the compiler from protecting you from shooting yourself in the foot and makes your code harder to read. Always try and help the compiler help you by keeping the types as long as possible unless you have a very good reason not to do so.
Edit
Oh, and for completeness, you can allow it to degrade to a pointer, but this decouples the array from the number of elements it holds. This is done a lot in C/C++ and is usually mitigated by passing the number of elements in the array. However, the compiler can't help you if you make a mistake and pass in the wrong value to the number of elements.
// separate size value
int* fillarr(int* arr, size_t size)
{
for(int* it = arr; it != arr + size; ++it)
{ /* do stuff */ }
return arr;
}
Instead of passing the size, you can pass the end pointer, which will point to one past the end of your array. This is useful as it makes for something that is closer to the std algorithms, which take a begin and and end pointer, but what you return is now only something that you must remember.
// separate end pointer
int* fillarr(int* arr, int* end)
{
for(int* it = arr; it != end; ++it)
{ /* do stuff */ }
return arr;
}
Alternatively, you can document that this function will only take 5 elements and hope that the user of your function doesn't do anything stupid.
// I document that this function will ONLY take 5 elements and
// return the same array of 5 elements. If you pass in anything
// else, may nazal demons exit thine nose!
int* fillarr(int* arr)
{
for(int* it = arr; it != arr + 5; ++it)
{ /* do stuff */ }
return arr;
}
Note that the return value has lost it's original type and is degraded to a pointer. Because of this, you are now on your own to ensure that you are not going to overrun the array.
You could pass a std::pair<int*, int*>, which you can use for begin and end and pass that around, but then it really stops looking like an array.
std::pair<int*, int*> fillarr(std::pair<int*, int*> arr)
{
for(int* it = arr.first; it != arr.second; ++it)
{ /* do stuff */ }
return arr; // if you change arr, then return the original arr value.
}
void fn()
{
int array[5];
auto array2 = fillarr(std::make_pair(&array[0], &array[5]));
// Can be done, but you have the original array in scope, so why bother.
int fourth_element = array2.first[4];
}
or
void other_function(std::pair<int*, int*> array)
{
// Can be done, but you have the original array in scope, so why bother.
int fourth_element = array2.first[4];
}
void fn()
{
int array[5];
other_function(fillarr(std::make_pair(&array[0], &array[5])));
}
Funny enough, this is very similar to how std::initializer_list work (c++11), but they don't work in this context.
to return an array from a function , let us define that array in a structure;
So it looks something like this
struct Marks{
int list[5];
}
Now let us create variables of the type structure.
typedef struct Marks marks;
marks marks_list;
We can pass array to a function in the following way and assign value to it:
void setMarks(int marks_array[]){
for(int i=0;i<sizeof(marks_array)/sizeof(int);i++)
marks_list.list[i]=marks_array[i];
}
We can also return the array. To return the array , the return type of the function should be of structure type ie marks. This is because in reality we are passing the structure that contains the array. So the final code may look like this.
marks getMarks(){
return marks_list;
}
the Simplest way to do this ,is to return it by reference , even if you don't write
the '&' symbol , it is automatically returned by reference
void fillarr(int arr[5])
{
for(...);
}
int *fillarr(int arr[])
You can still use the result like
int *returned_array = fillarr(some_other_array);
if(returned_array[0] == 3)
do_important_cool_stuff();
As above mentioned paths are correct. But i think if we just return a local array variable of a function sometimes it returns garbage values as its elements.
in-order to avoid that i had to create the array dynamically and proceed. Which is something like this.
int* func()
{
int* Arr = new int[100];
return Arr;
}
int main()
{
int* ArrResult = func();
cout << ArrResult[0] << " " << ArrResult[1] << endl;
return 0;
}
Source: https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_functions.htm
C++ does not allow to return an entire array as an argument to a function. However, you can return a pointer to an array by specifying the array's name without an index.
If you want to return a single-dimension array from a function, you would have to declare a function returning a pointer as in the following example:
int * myFunction() {
.
.
.
}
C++ does not advocate to return the address of a local variable to outside of the function so you would have to define the local variable as static variable.
Applying these rules on the current question, we can write the program as follows:
# include <iostream>
using namespace std;
int * fillarr( );
int main ()
{
int *p;
p = fillarr();
for ( int i = 0; i < 5; i++ )
cout << "p[" << i << "] : "<< *(p + i) << endl;
return 0;
}
int * fillarr( )
{
static int arr[5];
for (int i = 0; i < 5; ++i)
arr[i] = i;
return arr;
}
The Output will be:
p[0]=0
p[1]=1
p[2]=2
p[3]=3
p[4]=4
template<typename T, size_t N>
using ARR_REF = T (&)[N];
template <typename T, size_t N>
ARR_REF<T,N> ArraySizeHelper(ARR_REF<T,N> arr);
#define arraysize(arr) sizeof(ArraySizeHelper(arr))
and what about:
int (*func())
{
int *f = new int[10] {1,2,3};
return f;
}
int fa[10] = { 0 };
auto func2() -> int (*) [10]
{
return &fa;
}
Actually when you pass an array inside a function, the pointer to the original array is passed in the function parameter and thus the changes made to the array inside that function is actually made on the original array.
#include <iostream>
using namespace std;
int* func(int ar[])
{
for(int i=0;i<100;i++)
ar[i]=i;
int *ptr=ar;
return ptr;
}
int main() {
int *p;
int y[100]={0};
p=func(y);
for(int i=0;i<100;i++)
cout<<i<<" : "<<y[i]<<'\n';
}
Run it and you will see the changes
And why don't "return" the array as a parameter?
fillarr(int source[], size_t dimSource, int dest[], size_t dimDest)
{
if (dimSource <= dimDest)
{
for (size_t i = 0; i < dimSource; i++)
{
//some stuff...
}
}
else
{
//some stuff..
}
}
or..in a simpler way (but you have to know the dimensions...):
fillarr(int source[], int dest[])
{
//...
}
A simple and elaborate example, so that I can refer here if I forget the concept and need help.
#include <iostream>
using namespace std;
int *ReturnArray(int arr[], int size)
{
static int MinMax[2] = {0, 0}; // must use static, else address would be deleted after the return is reached
MinMax[0] = arr[0];
MinMax[1] = arr[size - 1];
return MinMax;
}
int main()
{
int arr[] = {1, 2, 3};
int size = sizeof(arr) / sizeof(*arr);
int *ans; // pointer to hold returned array
ans = ReturnArray(arr, size); // only pointer can receive the return, not an array
cout << "Min: " << ans[0] << " Max: " << ans[1];
return 0;
}
Here's a full example of this kind of problem to solve
#include <bits/stdc++.h>
using namespace std;
int* solve(int brr[],int n)
{
sort(brr,brr+n);
return brr;
}
int main()
{
int n;
cin>>n;
int arr[n];
for(int i=0;i<n;i++)
{
cin>>arr[i];
}
int *a=solve(arr,n);
for(int i=0;i<n;i++)
{
cout<<a[i]<<endl;
}
return 0;
}
i used static array so that while returning array it should not throw error as you are returning address of local variable...
so now you can send any locally created variable from function by making it as static...as it works as global variable....
#include<iostream>
using namespace std;
char *func(int n)
{
// char a[26]; /*if we use this then an error will occur because you are
// returning address of a local variable*/
static char a[26];
char temp='A';
for(int i=0;i<n;i++)
{
a[i]=temp;temp++;
}
return a;
}
int main()
{
int n=26;
char *p=func(n);
for(int i=0;i<n;i++)
cout<<*(p+i)<<" ";
//or you can also print like this
for(int i=0;i<n;i++)
cout<<p[i]<<" ";
}
Just define a type[ ] as return value, like:
private string[] functionReturnValueArray(string one, string two)
{
string[] x = {one, two};
x[0] = "a";
x[1] = "b";
return x;
}
.
.
.
function call:
string[] y;
y = functionReturnValueArray(stringOne, stringTwo)

Using an Array as a Whille loop condition

I am trying specify a condition by saying that if an array is not equal to an array run loop. So for example:
array1 [1,2,3]
array2 [1,2,3]
Here array1 does equal array2 as the elements in 0 in both arrays are the same, the elements in 1 in both arrays are the same and so on...
The code I have so far doesn't seem to work. Is there a way of comparing two arrays and if all elements in one match all the elements in the second one the condition is true.
Here is my test code:
int C1Mean[3];
int C2Mean[3];
int prv_mean1[3];
int prv_mean2[3];
while (C1Mean[3] = prv_mean1[3] && C2Mean[3] = prv_mean2[3])
{
//code
}
Thanks chaps.
As commented you access your arrays out of bounds, and you are using assignments (single =) instead or comparisons (==).
To compare your arrays (element by element), you can use std::equal :
while(std::equal(std::begin(C1Mean), std::end(C1Mean), std::begin(prv_mean1))
&& std::equal(std::begin(C2Mean), std::end(C2Mean), std::begin(prv_mean2)))
{
...
}
Or without c++11 :
while(std::equal(C1Mean, C1Mean + sizeof C1Mean / sizeof *C1Mean, prv_mean1)
&& std::equal(C2Mean, C2Mean + sizeof C2Mean / sizeof *C2Mean, prv_mean2))
{
...
}
In c++11, you may use std::array, and use ==:
std::array<int, 3> C1Mean;
std::array<int, 3> C2Mean;
std::array<int, 3> prv_mean1;
std::array<int, 3> prv_mean2;
while (C1Mean == prv_mean1 && C2Mean == prv_mean2)
{
//code
}
You are not using comparison operator (==) but assignment (=), so you change the value of CMean[i] in the condition and the condition would be false only when one of prv_mean2 would be equal to zero. And no, you can't compare the whole arrays.
If you are able to use c++11 you can use a generic function. The generic function is:
bool equal(beginIterator, endIterator, beginIterator Other);
This generic function will compare all values in a range. Note that the second array must be at least as long as the first array.
Since an array is nog an object you cannot use arr.begin () and you should use std::begin(arr) and std::end(arr). These functions come with #include.
Furthermore, if you can use c++11 you can also use the standad container std::array or std::vector. Then you can just state arr1 == arr2.
Note: I wrote this on my mobile and didn't check whether the generic function actually works on arrays. I will check this when at home again and eventually remove my post.
You can create a function to compare the two arrays that will return 1 if they are equal and 0 otherwise. Say, for example,
while(areEqual(C1Mean,prv_mean1) && areEqual(C2Mean,prv_mean2))
{
//Perform your task
}
where
int areEqual(int array1[],int array2[])
{
//compare them and return 1 if equal else return 0;
}
It seems like you need a double equals("=="). Try:
while (C1Mean[3] == prv_mean1[3] && C2Mean[3] == prv_mean2[3])
{
//code
}

Return array in a function

I have an array int arr[5] that is passed to a function fillarr(int arr[]):
int fillarr(int arr[])
{
for(...);
return arr;
}
How can I return that array?
How will I use it, say I returned a pointer how am I going to access it?
In this case, your array variable arr can actually also be treated as a pointer to the beginning of your array's block in memory, by an implicit conversion. This syntax that you're using:
int fillarr(int arr[])
Is kind of just syntactic sugar. You could really replace it with this and it would still work:
int fillarr(int* arr)
So in the same sense, what you want to return from your function is actually a pointer to the first element in the array:
int* fillarr(int arr[])
And you'll still be able to use it just like you would a normal array:
int main()
{
int y[10];
int *a = fillarr(y);
cout << a[0] << endl;
}
C++ functions can't return C-style arrays by value. The closest thing is to return a pointer. Furthermore, an array type in the argument list is simply converted to a pointer.
int *fillarr( int arr[] ) { // arr "decays" to type int *
return arr;
}
You can improve it by using an array references for the argument and return, which prevents the decay:
int ( &fillarr( int (&arr)[5] ) )[5] { // no decay; argument must be size 5
return arr;
}
With Boost or C++11, pass-by-reference is only optional and the syntax is less mind-bending:
array< int, 5 > &fillarr( array< int, 5 > &arr ) {
return arr; // "array" being boost::array or std::array
}
The array template simply generates a struct containing a C-style array, so you can apply object-oriented semantics yet retain the array's original simplicity.
In C++11, you can return std::array.
#include <array>
using namespace std;
array<int, 5> fillarr(int arr[])
{
array<int, 5> arr2;
for(int i=0; i<5; ++i) {
arr2[i]=arr[i]*2;
}
return arr2;
}
$8.3.5/8 states-
"Functions shall not have a return type of type array or function, although they may have a return type of type pointer or reference to such things. There shall be no arrays of functions, although there can be arrays of pointers to functions."
int (&fn1(int (&arr)[5]))[5]{ // declare fn1 as returning refernce to array
return arr;
}
int *fn2(int arr[]){ // declare fn2 as returning pointer to array
return arr;
}
int main(){
int buf[5];
fn1(buf);
fn2(buf);
}
the answer may depend a bit on how you plan to use that function. For the simplest answer, lets decide that instead of an array, what you really want is a vector. Vectors are nice because the look for all the world like boring, ordinary values you can store in regular pointers. We'll look at other options and why you want them afterwards:
std::vector<int> fillarr( std::vector<int> arr ) {
// do something
return arr;
}
This will do exactly what you expect it to do. The upside is that std::vector takes care of making sure everything is handled cleanly. the downside is that this copies a very large amount of data, if your array is large. In fact it copies every element of the array twice. first it copies the vector so that the function can use it as a parameter. then it copies it again to return it to the caller. If you can handle managing the vector yourself, you can do things quite a bit more easily. (it may copy it a third time if the caller needs to store it in a variable of some sort to do more calculation)
It looks like what you're really trying to do is just populate a collection. if you don't have a specific reason to return a new instance of a collection, then don't. we can do it like this
void fillarr(std::vector<int> & arr) {
// modify arr
// don't return anything
}
this way you get a reference to the array passed to the function, not a private copy of it. any changes you make to the parameter are seen by the caller. You could return a reference to it if you want, but that's not really a great idea, since it sort of implies that you're getting something different from what you passed.
If you really do need a new instance of the collection, but want to avoid having it on the stack (and all the copying that entails), you need to create some kind of contract for how that instance is handled. the easiest way to do that is to use a smart pointer, which keeps the referenced instance around as long as anyone is holding onto it. It goes away cleanly if it goes out of scope. That would look like this.
std::auto_ptr<std::vector<int> > fillarr( const std::vector<int> & arr) {
std::auto_ptr<std::vector<int> > myArr(new std::vector<int>);
// do stuff with arr and *myArr
return myArr;
}
For the most part, using *myArr works identically to using a plain vanilla vector. This example also modifies the parameter list by adding the const keyword. Now you get a reference without copying it, but you can't modify it, so the caller knows it'll be the same as before the function got to it.
All of this is swell, but idiomatic c++ rarely works with collections as a whole. More normally, you will be using iterators over those collections. that would look something more like this
template <class Iterator>
Iterator fillarr(Iterator arrStart, Iterator arrEnd) {
Iterator arrIter = arrStart;
for(;arrIter <= arrEnd; arrIter++)
;// do something
return arrStart;
}
Using it looks a bit odd if you're not used to seeing this style.
vector<int> arr;
vector<int>::iterator foo = fillarr(arr.begin(), arr.end());
foo now 'points to' the beginning of the modified arr.
What's really nice about this is that it works equally well on vector as on plain C arrays and many other types of collection, for example
int arr[100];
int *foo = fillarr(arr, arr+100);
Which now looks an awful lot like the plain pointer examples given elsewhere in this question.
This:
int fillarr(int arr[])
is actually treated the same as:
int fillarr(int *arr)
Now if you really want to return an array you can change that line to
int * fillarr(int arr[]){
// do something to arr
return arr;
}
It's not really returning an array. you're returning a pointer to the start of the
array address.
But remember when you pass in the array, you're only passing in a pointer.
So when you modify the array data, you're actually modifying the data that the
pointer is pointing at. Therefore before you passed in the array, you must realise
that you already have on the outside the modified result.
e.g.
int fillarr(int arr[]){
array[0] = 10;
array[1] = 5;
}
int main(int argc, char* argv[]){
int arr[] = { 1,2,3,4,5 };
// arr[0] == 1
// arr[1] == 2 etc
int result = fillarr(arr);
// arr[0] == 10
// arr[1] == 5
return 0;
}
I suggest you might want to consider putting a length into your fillarr function like
this.
int * fillarr(int arr[], int length)
That way you can use length to fill the array to it's length no matter what it is.
To actually use it properly. Do something like this:
int * fillarr(int arr[], int length){
for (int i = 0; i < length; ++i){
// arr[i] = ? // do what you want to do here
}
return arr;
}
// then where you want to use it.
int arr[5];
int *arr2;
arr2 = fillarr(arr, 5);
// at this point, arr & arr2 are basically the same, just slightly
// different types. You can cast arr to a (char*) and it'll be the same.
If all you're wanting to do is set the array to some default values, consider using
the built in memset function.
something like:
memset((int*)&arr, 5, sizeof(int));
While I'm on the topic though. You say you're using C++. Have a look at using stl vectors. Your code is likely to be more robust.
There are lots of tutorials. Here is one that gives you an idea of how to use them.
http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html
This is a fairly old question, but I'm going to put in my 2 cents as there are a lot of answers, but none showing all possible methods in a clear and concise manner (not sure about the concise bit, as this got a bit out of hand. TL;DR 😉).
I'm assuming that the OP wanted to return the array that was passed in without copying as some means of directly passing this to the caller to be passed to another function to make the code look prettier.
However, to use an array like this is to let it decay into a pointer and have the compiler treat it like an array. This can result in subtle bugs if you pass in an array like, with the function expecting that it will have 5 elements, but your caller actually passes in some other number.
There a few ways you can handle this better. Pass in a std::vector or std::array (not sure if std::array was around in 2010 when the question was asked). You can then pass the object as a reference without any copying/moving of the object.
std::array<int, 5>& fillarr(std::array<int, 5>& arr)
{
// (before c++11)
for(auto it = arr.begin(); it != arr.end(); ++it)
{ /* do stuff */ }
// Note the following are for c++11 and higher. They will work for all
// the other examples below except for the stuff after the Edit.
// (c++11 and up)
for(auto it = std::begin(arr); it != std::end(arr); ++it)
{ /* do stuff */ }
// range for loop (c++11 and up)
for(auto& element : arr)
{ /* do stuff */ }
return arr;
}
std::vector<int>& fillarr(std::vector<int>& arr)
{
for(auto it = arr.begin(); it != arr.end(); ++it)
{ /* do stuff */ }
return arr;
}
However, if you insist on playing with C arrays, then use a template which will keep the information of how many items in the array.
template <size_t N>
int(&fillarr(int(&arr)[N]))[N]
{
// N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0])
for(int* it = arr; it != arr + N; ++it)
{ /* do stuff */ }
return arr;
}
Except, that looks butt ugly, and super hard to read. I now use something to help with that which wasn't around in 2010, which I also use for function pointers:
template <typename T>
using type_t = T;
template <size_t N>
type_t<int(&)[N]> fillarr(type_t<int(&)[N]> arr)
{
// N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0])
for(int* it = arr; it != arr + N; ++it)
{ /* do stuff */ }
return arr;
}
This moves the type where one would expect it to be, making this far more readable. Of course, using a template is superfluous if you are not going to use anything but 5 elements, so you can of course hard code it:
type_t<int(&)[5]> fillarr(type_t<int(&)[5]> arr)
{
// Prefer using the compiler to figure out how many elements there are
// as it reduces the number of locations where you have to change if needed.
for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
{ /* do stuff */ }
return arr;
}
As I said, my type_t<> trick wouldn't have worked at the time this question was asked. The best you could have hoped for back then was to use a type in a struct:
template<typename T>
struct type
{
typedef T type;
};
typename type<int(&)[5]>::type fillarr(typename type<int(&)[5]>::type arr)
{
// Prefer using the compiler to figure out how many elements there are
// as it reduces the number of locations where you have to change if needed.
for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
{ /* do stuff */ }
return arr;
}
Which starts to look pretty ugly again, but at least is still more readable, though the typename may have been optional back then depending on the compiler, resulting in:
type<int(&)[5]>::type fillarr(type<int(&)[5]>::type arr)
{
// Prefer using the compiler to figure out how many elements there are
// as it reduces the number of locations where you have to change if needed.
for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
{ /* do stuff */ }
return arr;
}
And then of course you could have specified a specific type, rather than using my helper.
typedef int(&array5)[5];
array5 fillarr(array5 arr)
{
// Prefer using the compiler to figure out how many elements there are
// as it reduces the number of locations where you have to change if needed.
for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
{ /* do stuff */ }
return arr;
}
Back then, the free functions std::begin() and std::end() didn't exist, though could have been easily implemented. This would have allowed iterating over the array in a safer manner as they make sense on a C array, but not a pointer.
As for accessing the array, you could either pass it to another function that takes the same parameter type, or make an alias to it (which wouldn't make much sense as you already have the original in that scope). Accessing a array reference is just like accessing the original array.
void other_function(type_t<int(&)[5]> x) { /* do something else */ }
void fn()
{
int array[5];
other_function(fillarr(array));
}
or
void fn()
{
int array[5];
auto& array2 = fillarr(array); // alias. But why bother.
int forth_entry = array[4];
int forth_entry2 = array2[4]; // same value as forth_entry
}
To summarize, it is best to not allow an array decay into a pointer if you intend to iterate over it. It is just a bad idea as it keeps the compiler from protecting you from shooting yourself in the foot and makes your code harder to read. Always try and help the compiler help you by keeping the types as long as possible unless you have a very good reason not to do so.
Edit
Oh, and for completeness, you can allow it to degrade to a pointer, but this decouples the array from the number of elements it holds. This is done a lot in C/C++ and is usually mitigated by passing the number of elements in the array. However, the compiler can't help you if you make a mistake and pass in the wrong value to the number of elements.
// separate size value
int* fillarr(int* arr, size_t size)
{
for(int* it = arr; it != arr + size; ++it)
{ /* do stuff */ }
return arr;
}
Instead of passing the size, you can pass the end pointer, which will point to one past the end of your array. This is useful as it makes for something that is closer to the std algorithms, which take a begin and and end pointer, but what you return is now only something that you must remember.
// separate end pointer
int* fillarr(int* arr, int* end)
{
for(int* it = arr; it != end; ++it)
{ /* do stuff */ }
return arr;
}
Alternatively, you can document that this function will only take 5 elements and hope that the user of your function doesn't do anything stupid.
// I document that this function will ONLY take 5 elements and
// return the same array of 5 elements. If you pass in anything
// else, may nazal demons exit thine nose!
int* fillarr(int* arr)
{
for(int* it = arr; it != arr + 5; ++it)
{ /* do stuff */ }
return arr;
}
Note that the return value has lost it's original type and is degraded to a pointer. Because of this, you are now on your own to ensure that you are not going to overrun the array.
You could pass a std::pair<int*, int*>, which you can use for begin and end and pass that around, but then it really stops looking like an array.
std::pair<int*, int*> fillarr(std::pair<int*, int*> arr)
{
for(int* it = arr.first; it != arr.second; ++it)
{ /* do stuff */ }
return arr; // if you change arr, then return the original arr value.
}
void fn()
{
int array[5];
auto array2 = fillarr(std::make_pair(&array[0], &array[5]));
// Can be done, but you have the original array in scope, so why bother.
int fourth_element = array2.first[4];
}
or
void other_function(std::pair<int*, int*> array)
{
// Can be done, but you have the original array in scope, so why bother.
int fourth_element = array2.first[4];
}
void fn()
{
int array[5];
other_function(fillarr(std::make_pair(&array[0], &array[5])));
}
Funny enough, this is very similar to how std::initializer_list work (c++11), but they don't work in this context.
to return an array from a function , let us define that array in a structure;
So it looks something like this
struct Marks{
int list[5];
}
Now let us create variables of the type structure.
typedef struct Marks marks;
marks marks_list;
We can pass array to a function in the following way and assign value to it:
void setMarks(int marks_array[]){
for(int i=0;i<sizeof(marks_array)/sizeof(int);i++)
marks_list.list[i]=marks_array[i];
}
We can also return the array. To return the array , the return type of the function should be of structure type ie marks. This is because in reality we are passing the structure that contains the array. So the final code may look like this.
marks getMarks(){
return marks_list;
}
the Simplest way to do this ,is to return it by reference , even if you don't write
the '&' symbol , it is automatically returned by reference
void fillarr(int arr[5])
{
for(...);
}
int *fillarr(int arr[])
You can still use the result like
int *returned_array = fillarr(some_other_array);
if(returned_array[0] == 3)
do_important_cool_stuff();
As above mentioned paths are correct. But i think if we just return a local array variable of a function sometimes it returns garbage values as its elements.
in-order to avoid that i had to create the array dynamically and proceed. Which is something like this.
int* func()
{
int* Arr = new int[100];
return Arr;
}
int main()
{
int* ArrResult = func();
cout << ArrResult[0] << " " << ArrResult[1] << endl;
return 0;
}
Source: https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_functions.htm
C++ does not allow to return an entire array as an argument to a function. However, you can return a pointer to an array by specifying the array's name without an index.
If you want to return a single-dimension array from a function, you would have to declare a function returning a pointer as in the following example:
int * myFunction() {
.
.
.
}
C++ does not advocate to return the address of a local variable to outside of the function so you would have to define the local variable as static variable.
Applying these rules on the current question, we can write the program as follows:
# include <iostream>
using namespace std;
int * fillarr( );
int main ()
{
int *p;
p = fillarr();
for ( int i = 0; i < 5; i++ )
cout << "p[" << i << "] : "<< *(p + i) << endl;
return 0;
}
int * fillarr( )
{
static int arr[5];
for (int i = 0; i < 5; ++i)
arr[i] = i;
return arr;
}
The Output will be:
p[0]=0
p[1]=1
p[2]=2
p[3]=3
p[4]=4
template<typename T, size_t N>
using ARR_REF = T (&)[N];
template <typename T, size_t N>
ARR_REF<T,N> ArraySizeHelper(ARR_REF<T,N> arr);
#define arraysize(arr) sizeof(ArraySizeHelper(arr))
and what about:
int (*func())
{
int *f = new int[10] {1,2,3};
return f;
}
int fa[10] = { 0 };
auto func2() -> int (*) [10]
{
return &fa;
}
Actually when you pass an array inside a function, the pointer to the original array is passed in the function parameter and thus the changes made to the array inside that function is actually made on the original array.
#include <iostream>
using namespace std;
int* func(int ar[])
{
for(int i=0;i<100;i++)
ar[i]=i;
int *ptr=ar;
return ptr;
}
int main() {
int *p;
int y[100]={0};
p=func(y);
for(int i=0;i<100;i++)
cout<<i<<" : "<<y[i]<<'\n';
}
Run it and you will see the changes
And why don't "return" the array as a parameter?
fillarr(int source[], size_t dimSource, int dest[], size_t dimDest)
{
if (dimSource <= dimDest)
{
for (size_t i = 0; i < dimSource; i++)
{
//some stuff...
}
}
else
{
//some stuff..
}
}
or..in a simpler way (but you have to know the dimensions...):
fillarr(int source[], int dest[])
{
//...
}
A simple and elaborate example, so that I can refer here if I forget the concept and need help.
#include <iostream>
using namespace std;
int *ReturnArray(int arr[], int size)
{
static int MinMax[2] = {0, 0}; // must use static, else address would be deleted after the return is reached
MinMax[0] = arr[0];
MinMax[1] = arr[size - 1];
return MinMax;
}
int main()
{
int arr[] = {1, 2, 3};
int size = sizeof(arr) / sizeof(*arr);
int *ans; // pointer to hold returned array
ans = ReturnArray(arr, size); // only pointer can receive the return, not an array
cout << "Min: " << ans[0] << " Max: " << ans[1];
return 0;
}
Here's a full example of this kind of problem to solve
#include <bits/stdc++.h>
using namespace std;
int* solve(int brr[],int n)
{
sort(brr,brr+n);
return brr;
}
int main()
{
int n;
cin>>n;
int arr[n];
for(int i=0;i<n;i++)
{
cin>>arr[i];
}
int *a=solve(arr,n);
for(int i=0;i<n;i++)
{
cout<<a[i]<<endl;
}
return 0;
}
i used static array so that while returning array it should not throw error as you are returning address of local variable...
so now you can send any locally created variable from function by making it as static...as it works as global variable....
#include<iostream>
using namespace std;
char *func(int n)
{
// char a[26]; /*if we use this then an error will occur because you are
// returning address of a local variable*/
static char a[26];
char temp='A';
for(int i=0;i<n;i++)
{
a[i]=temp;temp++;
}
return a;
}
int main()
{
int n=26;
char *p=func(n);
for(int i=0;i<n;i++)
cout<<*(p+i)<<" ";
//or you can also print like this
for(int i=0;i<n;i++)
cout<<p[i]<<" ";
}
Just define a type[ ] as return value, like:
private string[] functionReturnValueArray(string one, string two)
{
string[] x = {one, two};
x[0] = "a";
x[1] = "b";
return x;
}
.
.
.
function call:
string[] y;
y = functionReturnValueArray(stringOne, stringTwo)

How to reliably get size of C-style array?

How do I reliably get the size of a C-style array? The method often recommended seems to be to use sizeof, but it doesn't work in the foo function, where x is passed in:
#include <iostream>
void foo(int x[]) {
std::cerr << (sizeof(x) / sizeof(int)); // 2
}
int main(){
int x[] = {1,2,3,4,5};
std::cerr << (sizeof(x) / sizeof(int)); // 5
foo(x);
return 0;
}
Answers to this question recommend sizeof but they don't say that it (apparently?) doesn't work if you pass the array around. So, do I have to use a sentinel instead? (I don't think the users of my foo function can always be trusted to put a sentinel at the end. Of course, I could use std::vector, but then I don't get the nice shorthand syntax {1,2,3,4,5}.)
In C array parameters in C are really just pointers so sizeof() won't work. You either need to pass in the size as another parameter or use a sentinel - whichever is most appropriate for your design.
Some other options:
Some other info:
for C++, instead of passing a raw array pointer, you might want to have the parameter use something that wraps the array in a class template that keeps track of the array size and provides methods to copy data into the array in a safe manner. Something like STLSoft's array_proxy template or Boost's boost::array might help. I've used an array_proxy template to nice effect before. Inside the function using the parameter, you get std::vector like operations, but the caller of the function can be using a simple C array. There's no copying of the array - the array_proxy template takes care of packaging the array pointer and the array's size nearly automatically.
a macro to use in C for determining the number of elements in an array (for when sizeof() might help - ie., you're not dealing with a simple pointer): Is there a standard function in C that would return the length of an array?
A common idiom mentioned in GNU Libstdc++ documentation is the lengthof function:
template<typename T, unsigned int sz>
inline unsigned int lengthof(T (&)[sz]) { return sz; }
You can use it as
int x[] = {1,2,3,4,5};
std::cerr << lengthof(x) << std::endl;
Warning: this will work only when the array has not decayed into a pointer.
How about this?..
template <int N>
void foo(int (&x)[N]) {
std::cerr << N;
}
You can either pass the size around, use a sentinel or even better use std::vector. Even though std::vector lacks initializer lists it is still easy to construct a vector with a set of elements (although not quite as nice)
static const int arr[] = {1,2,3,4,5};
vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );
The std::vector class also makes making mistakes far harder, which is worth its weight in gold. Another bonus is that all C++ should be familiar with it and most C++ applications should be using a std::vector rather than a raw C array.
As a quick note, C++0x adds Initializer lists
std::vector<int> v = {1, 2, 3, 4};
You can also use Boost.Assign to do the same thing although the syntax is a bit more convoluted.
std::vector<int> v = boost::assign::list_of(1)(2)(3)(4);
or
std::vector<int> v;
v += 1, 2, 3, 4;
c provides no native support for this. Once an array is passed out of its declared scope, its size is lost.
You can pass the size with the array. You can even bundle them into a structure if you always to to keep the size, though you'll have some bookkeepping overhead with that.
I also agree that Corwin's method above is very good.
template <int N>
void foo(int (&x)[N])
{
std::cerr << N;
}
I don't think anybody gave a really good reason why this is not a good idea.
In java, for example, we can write things like:
int numbers [] = {1, 2, 3, 4};
for(int i = 0; i < numbers.length(); i++)
{
System.out.println(numbers[i]+"\n");
}
In C++ it would be nice instead of saying
int numbers [] = {1, 2, 3, 4};
int size = sizeof(numbers)/sizeof(int);
for(int i = 0; i < size; i++)
{
cout << numbers[i] << endl;
}
We could take it a step further and go
template <int N>
int size(int (&X)[N])
{
return N;
}
Or if that causes problems I suppose you could write explicitly:
template < int N >
int size(int (&X)[N])
{
int value = (sizeof(X)/sizeof(X[0]));
return value;
}
Then we just have to go in main:
int numbers [] = {1, 2, 3, 4};
for(int i = 0; i < size(numbers); i++)
{
cout << numbers[i] << endl;
}
makes sense to me :-)
An array expression will have its type implicitly converted from "N-element array of T" to "pointer to T" and its value will be the address of the first element in the array, unless the array expression is the operand of either the sizeof or address-of (&) operators, or if the array expression is a string literal being used to initialize another array in a declaration. In short, you can't pass an array to a function as an array; what the function receives is a pointer value, not an array value.
You have to pass the array size as a separate parameter.
Since you're using C++, use vectors (or some other suitable STL container) instead of C-style arrays. Yes, you lose the handy shorthand syntax, but the tradeoff is more than worth it. Seriously.
Now, you can use C++11's extent and rank.
By example:
#include <iostream>
#include <type_traits>
int main()
{
int a[][3] = {{1, 2, 3}, {4, 5, 6}};
std::cout << "\nRank: : " << std::rank<decltype(a)>::value;
std::cout << "\nSize: [_here_][]: " << std::extent<decltype(a), 0>::value;
std::cout << "\nSize: [][_here_]: " << std::extent<decltype(a), 1>::value;
std::cout << "\nSize: [][]_here_: " << std::extent<decltype(a), 2>::value;
}
prints:
Rank: : 2
Size: [_here_][]: 2
Size: [][_here_]: 3
Size: [][]_here_: 0
You need to pass the size along with the array, just like it is done in many library functions, for instance strncpy(), strncmp() etc. Sorry, this is just the way it works in C:-).
Alternatively you could roll out your own structure like:
struct array {
int* data;
int size;
};
and pass it around your code.
Of course you can still use std::list or std::vector if you want to be more C++ -ish.
Since c++11, there is a very convenient way:
static const int array[] = { 1, 2, 3, 6 };
int size = (int)std::distance(std::begin(array), std::end(array))+1;