1

I made an array with 5 integer elements, and passed it to the test method which takes its parameter with the void pointer.

After casting it to the integer array, I tried to looping the array with for statement.

But it does not work. Why is this happening?

#include <iostream>

using namespace std;

void test(void* arr){
    int* arr2 = static_cast<int*>(arr);
    for(int num:arr2){
        cout << num << endl;
    }
}

int main(){
    int arr[5] = {1,2,3,4,5};
    test(arr);
}
jwkoo
  • 2,393
  • 5
  • 22
  • 35
  • 2
    How should a compiler jump to the next element if it doesn't know element size? You have `(int num:arr)` in your code, not `(int num:arr2)`. – Evg Dec 13 '19 at 07:36
  • @Evg sorry I edited it! so is it same with the dynamic array? – jwkoo Dec 13 '19 at 07:38
  • 2
    And how should a compiler know where to stop? – Evg Dec 13 '19 at 07:38
  • A pointer doesn't contain the size of the array it points to. It's not possible. You could pass the size to the function or use a STL container – Thomas Sablik Dec 13 '19 at 07:40
  • For range based for loop to work, the type should have `begin` and `end` and a raw pointer won't work in itself. – Wander3r Dec 13 '19 at 07:40
  • 4
    Please use std::vector instead of type* for common operations in C++ – Kiruahxh Dec 13 '19 at 07:41
  • 2
    @Kiruahxh or `std:array` if the size is known at compile time – Wander3r Dec 13 '19 at 07:42
  • The operand in range-based for must be valid for `begin(x)` and `end(x)`. But there is no definition for `begin(pointer)` or `end(pointer)` . – M.M Dec 13 '19 at 07:43
  • This small article might help you understand what happens in that code: https://www.geeksforgeeks.org/what-is-array-decay-in-c-how-can-it-be-prevented/ – AlexGeorg Dec 13 '19 at 07:54

3 Answers3

4

Array decays to a pointer and loses all size information in the function. Here's a solution with templates:

#include <iostream>

template <typename T>
void test(T const& arr) {
  for (auto const& num : arr) {
    std::cout << num << '\n';
  }
}

int main() {
  int arr[5] = {1, 2, 3, 4, 5};
  test(arr);
}
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
1

You can't use range-based for to iterate over an array of unknown bound or "over" a pointer. A compiler doesn't know where to stop.

Assuming that for some reason arr parameter is fixed to be void*, you can pass the size explicitly:

void test(void* arr, std::size_t size) {
    int* arr2 = static_cast<int*>(arr);
    while (size-- > 0)
        std::cout << *arr2++ << std::endl;
}

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    test(arr, 5);
}

But this is an example of a bad code. Don't do it unless you have a good reason.

If you want to use a range-based for loop, in C++20 you'll be able to use use std::span:

void test(void* arr, std::size_t size) {
    int* arr2 = static_cast<int*>(arr);
    std::span span(arr2, size);
    for (int num : span)
        std::cout << num << std::endl;
}

Before that you can use a self-made workaround:

template<typename T>
class my_span {
public:
    my_span(T* first, std::size_t size) :
        first_(first), size_(size) {}

    T* begin() const {
        return first_;
    }

    T* end() const {
        return first_ + size_;
    }

private:
    T* const first_;
    const std::size_t size_;
};

void test(void* arr, std::size_t size) {
    int* arr2 = static_cast<int*>(arr);
    my_span span(arr2, size);
    for (int num : span)
        std::cout << num << std::endl;
}
Evg
  • 25,259
  • 5
  • 41
  • 83
0

arr and arr2 are pointers, not arrays. The length of the array they point to is unknown to test, thus the range-based for does not iterate over the array.

jkb
  • 2,376
  • 1
  • 9
  • 12
  • for(int num:arr){ cout << num << endl; } work though arr is pointer. what is the difference? – jwkoo Dec 13 '19 at 07:39
  • 1
    I'm not convinced that either way works. The code does not compile whether using `arr` or `arr2` in `test` since both are pointers. – jkb Dec 13 '19 at 07:49
  • @jkb I assumed they meant `arr` in main, for this comment – M.M Dec 13 '19 at 08:22
  • @M.M I am sorry but isn't that arr is just an address? so I meant by pointer since we can use them with dereferencing. – jwkoo Dec 14 '19 at 14:24
  • @jwkoo the confusion is that you have two different variables called `arr` (the array in main, and the pointer in `test`). You can use `int num : x` syntax if `x` is an array but not if `x` is a pointer . – M.M Dec 15 '19 at 02:39