2

I'm trying to access an element of an std::array given its pointer in C++. Here's some code that illustrates my problem:

#include <iostream>
#include <array>

void func(std::array<int, 4> *);

int main()
{
    std::array<int, 4> arr = {1, 0, 5, 0};
    func(&arr);
}

void func(std::array<int, 4> *elements)
{
    for (int i = 0; i < 4; i = i + 1)
    {
        std::cout << *elements[i] << std::endl;
    }
}

I would expect this to print every element of the std::array on a new line. However, it doesn't even get past compiling:

main.cpp: In function ‘void func(std::array<int, 4ul>*)’:
main.cpp:16:22: error: no match for ‘operator*’ (operand type is ‘std::array<int, 4ul>’)
         std::cout << *elements[i] << std::endl;

What's going on here?
Thanks!

1
  • The syntax is awkward, a good reason to pass the array with a & reference instead of a * pointer. You don't like a nullptr anyway. Commented May 30, 2015 at 16:46

3 Answers 3

11

Use

std::cout << (*elements)[i] << std::endl;

instead. Otherwise operator[] is applied first, as it has higher precedence, see http://en.cppreference.com/w/cpp/language/operator_precedence.

So you first need to dereference the pointer to get access to the first pointee, which is an array, then subsequently access the array with operator[]. Otherwise your code is parsed by the compiler as *(elements[i]), so first you get the i-th array (which of course is non-existent unless i==0), then you try to dereference it, hence the compile error.

Tip: If you're worried about copies, pass the array by const reference instead

void func(const std::array<int, 4>& elements)

Then your syntax inside the function will be "natural", i.e. elements[i] will simply denote the i-th element of the array reference elements. You'll also pass the array simply as func(arr);.

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

Comments

6

@vsoftco's answer is quite correct.

I would just like to add that it is more idiomatic in C++ to pass large objects by reference, rather than pointer:

#include <iostream>
#include <array>

// declare parameter as a reference
void func(std::array<int, 4>&);

int main()
{
    std::array<int, 4> arr = {1, 0, 5, 0};
    func(arr); // no need to take address
}

void func(std::array<int, 4>& elements)
{
    for (int i = 0; i < 4; i = i + 1)
    {
        // just use as normal
        std::cout << elements[i] << std::endl;
    }
}

If the function will not modify the array then const reference would be more appropriate:

void func(const std::array<int, 4>& elements)
{
    for (int i = 0; i < 4; i = i + 1)
    {
        // just use as normal
        std::cout << elements[i] << std::endl;
    }
}

Comments

3

Alternate answer

While the other answers are correct too, I'd like to suggest another variant because there are cases where rewriting the code to use references is not always possible:

std::cout << elements->at(i) << std::endl;

This is a variant that avoids the pointer-de-referencing (*element) but uses the std::array::operator->. It may also be simpler to read.

2 Comments

Small comment: std::array::at() does bound checking, which is OK (and recommended) when debugging the code, but sometime one may not want it (e.g. in high performance code where bound checking will burn CPU cycles).
@vsoftco, you're correct. The at() function does bounds checking. However, bounds-checking is perhaps the fastest on std::array among all the containers. So, I would not limit its use only to debug code.

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.