1

What I want to do is something like this:

void dosth(bool& a) {
  a[2] = false;
}

int main() {
  bool a[10];

  dosth(a);

  return 0;
}

I want to call by reference, with an array as argument. How to realize this?

Thx

5 Answers 5

8

Like this:

typedef bool array_type[10];

void dosth(array_type& a)
{
    a[2] = false;
}

int main()
{
    array_type a;
    dosth(a);
}

Or without the typedef:

void dosth(bool (&a)[10])
{
    a[2] = false;
}

int main()
{
    bool a[10];
    dosth(a);
}

Or more generally:

template <size_t Size>
void dosth(bool (&a)[Size])
{
    /*static_*/assert(Size > 2);

    a[2] = false;
}

int main()
{
    bool a[10];
    dosth(a);
}

If you're not in C++0x, you can implement a (simple) static_assert like this:

template <bool>
struct static_assert_type;

template <> // only true is defined
struct static_assert_type<true> {}

#define static_assert(x) { static_assert_type<(x)>(); }

Which allows you uncomment the static_assert and get a compile-time error if the array size is too small.

Sign up to request clarification or add additional context in comments.

Comments

5

You can allow the array to decay to a pointer, as in Philippe's answer. A more type-safe solution, that only accepts arrays and allows compile-time range checks, is

template <size_t SIZE>
void dosth(bool (&a)[SIZE])
{
    a[2] = false;
}

You could add static_assert(SIZE > 2); (or BOOST_STATIC_ASSERT(SIZE > 2); if your compiler doesn't support static_assert) to give a compile error if the index would be out of range.

7 Comments

Allows compile-time range checks… not illustrated ;v) (+1)
Or you can not use the template and force a reference to an array of a given size.
Compile-time range checking is indeed a valid argument, but in most real-world scenarios, array sizes are usually dynamic and the compiler can't do any checking at all.
@flies: In that case it decays to a pointer, is the same as dosth(bool* a) and you actually pass a pointer.
@Philippe: Then the function would take a reference to std::vector and you'd obviously use an assert.
|
2

This is kind of tricky, the simple way (and the only available in C) is defining the signature of the function as taking a pointer:

void dosth( bool* a );

The array will automatically decay into a pointer to the first element and it will work as long as you are careful enough. Note that void dosth( bool a[10] ) is exactly the above signature: the compiler will translate that for you.

This is not safe for a couple of reasons, first is that it allows callers to pass an array of any size, or even no array at all (dosth(0);).

That can be made typesafe in C++ by using a reference:

void dosth( bool (&a)[ 10 ] );

Now, the compiler will ensure that an array of exactly 10 bools is passed into the function. There are a couple of implications there, the first of all is that not only the user cannot pass a null pointer, but she is restricted to passing an array of exactly 10 elements, so you need not worry about overflow when accessing the third element later on (a[2]=false;).

On the other hand, it limits usability, as users cannot pass an array of more than 10 elements, nor a dynamically allocated array (new bool[10]). That can be improved by using a template:

template <std::size_t N>
void dosth( bool (&a)[N] ) {
   static_assert( N >= 10 );
   //...
}

EDIT: I was going to respond to Cedric with a comment, but it would probably be too long. You are right in that it leaves the dynamically allocated problem unresolved. As @GMan says, in the general case you want to use other data types that will take care of the dynamically allocated memory. Anyway, there is a complex way of getting this to work with memory allocated with new[], it is just not so direct.

The problem is that the type must be bool [10], but new T[n] returns a T* and not a T[n]. Providing a typedef does not help either:

typedef bool b10[10];
b10* p = new b10;    // error cannot convert from int* to int (*)[10]

You can overcome that limitation by not requesting a single array but an array of arrays:

bool (*array)[10] = new bool[1][10];
dosth(*array);

But of course you will need to use delete [] and not plain delete:

delete [] array;

4 Comments

But even with the template you still have the problem of the dynamically allocated array, right ?
@Cedric: Then the problem domain is different and it doesn't matter. In that case, the function would take a std::vector<int>&, and you could just assert the size with .size().
OK it is the right solution, but in many cases people would use a dynamically allocated array...
@Cedric: That's what a std::vector is. If someone uses new[], they've done it wrong and I no longer care what problems they have.
0

If you want a reference to an array you can do the following. Note that then dosth will only accept reference to arrays of that size, and that you will not be able to give a heap allocated array (ie bool* c = new bool[10]).

void dosth(bool (&a)[10]) {
         a[2] = false;
}

int main() {
        bool a[10];
        bool (&aa)[10] = a;
        dosth(a);

        return 0;
}

Comments

-2

You have to declare the argument as a pointer:

void dosth(bool* a) {
  a[2] = false;
}

An array is essentially the same as a pointer

20 Comments

Ouch, not again... arrays are NOT even close to pointers, they just have a tendency to convert...
@Philippe: there's a difference between "essentially the same" and "different", and if you last read the standard 20 years ago, I suggest you read a more up-to-date standard (although arrays and pointers have been different types for ever, so nothing has changed there). -1 for dragging a mildly incorrect statement into a tedious argument.
This appears to be another case of you finding two things that have similarities and calling them the same (or essentially the same). I have no doubt you were using C++ in 1990, but the first standard wasn't around till 1998. A book describing the language is not interchangeable with the standard, and arrays are not interchangeable with pointers.
sigh - both sides know exactly what the other side is saying and they are both correct, and they both know it, but they choose to argue anyway
@pm100: "a pointer is the same as an array" is not true in any context, however much you wave your hands and say "essentially" or "that depends what you mean by 'is'". They are different types, defined by the language standard in different ways, and exhibiting different semantics. Philippe has stopped arguing the point; perhaps you should too. The tirade is at least helpful in telling the OP that this answer isn't very helpful, while the others are.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.