tags:

views:

124

answers:

5

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

A: 

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

Philippe Leybaert
I would prefer references because they are more secure, eg you can't call a function with an invalid reference.
a1337q
Ouch, not again... arrays are NOT even close to pointers, they just have a tendency to convert...
David Rodríguez - dribeas
"not even close"? Come on, get real. Conversion has nothing to do with it. Only the compiler knows the difference between a pointer and an array (sometimes).
Philippe Leybaert
-1 for that comment. An array is an array, a pointer is a pointer, nothing else. Conversion has *everything* to do with it; an array can be implicitly **converted** to a pointer to the first element. A compiler always knows the types it's working with.
GMan
Arrays and pointers are interchangeable. Don't try to be smarter than Bjarne Stroustrup. Of course they are not the same type, and the compiler can be a little smarter with array types, but they ARE essentially the same thing.
Philippe Leybaert
@Philippe: Red herrings won't get you anywhere, I never even suggesting I'm trying to be smarter than Bjarne. It's not that difficult: They are not interchangeable, they are not the same. Open your copy of the standard and read.
GMan
I read the C++ standard 20 years ago, and the C standard even longer ago. Don't try to tell me I don't know what I'm talking about. Final comment.
Philippe Leybaert
@Philippe: Apparently not. Appeal to authority/experience is another fallacy, you know; all the experience in the world doesn't imply you're right about something. You wouldn't tell a 5 year old 2 + 2 was 5 and back it up by saying "I learned addition 20 years ago", would you? So why do you think this is different? You could make a real argument by quoting from the standard, but since you obviously can't, allow me: §8.3.1 Pointers §8.3.4 Arrays, hm that's strange. Why have different sections describing different semantics for the same thing? It's like they're different. But we know they...
GMan
...aren't. Conversion has nothing to do with it, right? §4.2 Array-to-pointer conversion: An lvalue or rvalue of type “array ofN T” or “array of unknown bound of T” can be converted to an rvalueof type “pointer to T.” The result is a pointer to the first element of the array. Hm, why convert between the same things? The standard must be wrong, since arrays are pointers and no conversion is necessary. Right? Wrong. They aren't the same, period. Also, this won't be my last comment since, unlike you, I'm actually open to discussion and would love to be corrected and learn something.
GMan
The C++ standard didn't even exist 20 years ago. If you've forgotten *when* you read it, perhaps you've forgotten some details of *what* you read, too.
Rob Kennedy
There's a difference between "the same" and "essentially the same". I don't have an "academic" knowledge of C++. I've been writing commercial software using C and C++ since 1987. I know what the book says now, and what the book said in the past, but it all comes down to the single fact that pointers and arrays are "essentially" the same thing in practice. I know compilers have become smarter over the last few decades, but this doesn't mean the language has changed. Sometimes it's a good thing to point out where we came from, and what is going on at a lower level.
Philippe Leybaert
@Rob: before you say stupid things, verify your facts. The first version of "The C++ Language" was published in 1985. Unless your math is shaky, that's 25 years in my book. I was writing code in C++ in 1990, so I guess I was writing software in a non-existing language.
Philippe Leybaert
@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.
Mike Seymour
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.
Rob Kennedy
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
@pm100: Not really. Saying arrays are interchangeable with pointers is simply flat-out wrong. Saying they are "essentially the same" is wrong. Pointers point to a location in memory, arrays are a contiguous collection of elements; hardly the same.
GMan
:-) see what I mean
pm100
@pm100: No, @GMan is right and @Philippe is wrong. A pointer can be used to represent some aspects of an array, but their essences are quite different.
Mike Seymour
:-) see what I mean
pm100
@pm100: No, we don't see what you mean or we wouldn't disagree. Why don't you actually try explaining instead of waving your hands around it and say "see". Acting like you've made a point when you haven't made any is an easy way to appear like a fool.
GMan
One of you knows exactly what is meant by "a pointer is the same as an array". One of you knows exactly what is meant by "a pointer is not the same as an array". You know that both of those statements are true depending on the context and what the words 'same' and 'different' are interpreted as meaning. Yet we end up with a tirade about who has been reading the specs longer. None of it helpful to the OP or to the poor guy that posted this answer. His code is correct because ptr==array; the (not shown) calling code could be 2 different cases (static array or ptr malloc) because ptr != array
pm100
@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.
Mike Seymour
+5  A: 

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.

Mike Seymour
Allows compile-time range checks… not illustrated ;v) (+1)
Potatoswatter
Or you can not use the template and force a reference to an array of a given size.
Cedric H.
what's the difference between this and `void dosth(bool a[]) {}` ? I mean, what's the advantage?
flies
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.
Philippe Leybaert
@flies: In that case it decays to a pointer, is the same as `dosth(bool* a)` and you actually pass a pointer.
Cedric H.
@flies: `bool a[]` will give you a pointer, and no indication of the size of the array.
Mike Seymour
@Philippe: Then the function would take a reference to `std::vector` and you'd obviously use an `assert`.
GMan
+8  A: 

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.

GMan
A: 

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;
}
Cedric H.
+2  A: 

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;
David Rodríguez - dribeas
But even with the template you still have the problem of the dynamically allocated array, right ?
Cedric H.
GMan
OK it is the right solution, but in many cases people would use a dynamically allocated array...
Cedric H.
@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.
GMan