3

I am having trouble converting a pointer array of uint16_t to std::vector<uint16_t> because of integer size issues.

        auto *arr = static_cast<const uint16_t *>(some_method.getArray());
        std::vector<uint16_t> vec(arr, sizeof arr / sizeof arr[0]);

In the first line I obtain a const uint16_t* array. In the second line I initialize the vector using the iterator constructor and pass in the pointer array arr and length of the array (size of the array divided by size of the first element = length of array).

However, c++ wants me to cast arr to unsigned long. So here it is with the cast

        std::vector<uint16_t> vec((unsigned long) arr, sizeof arr / sizeof arr[0]);

It seems to me something bad will happen casting from uint16_t (2 bytes) -> unsigned long (4 bytes) -> uint16_t (2 bytes). Is there a better way to do this array conversion?

Edit: Thank you all for the valuable feedback, the main issues I had:

  1. sizeof gets the size of the pointer, not the length of the array.

  2. I was using the wrong constructor

sean ng pack
  • 75
  • 1
  • 8
  • 2
    Does this help? https://stackoverflow.com/questions/2434196/how-to-initialize-stdvector-from-c-style-array – schteppe Jul 17 '20 at 09:18
  • 1
    Won't `sizeof arr` be the size of a pointer instead of the number of elements? I think you need a way to know how many elements `getArray()` returned. – Botje Jul 17 '20 at 09:20
  • 3
    Also, your method of calculating array size is incorrect. `arr` is a pointer, not an array. It's `sizeof` is constant. – Yksisarvinen Jul 17 '20 at 09:21
  • 2
    Whatever you do, `sizeof arr` is wrong. You can't retrieve the length of an array from a pointer to it, so if you have no way of getting that info from elsewhere you're toasted. – Quentin Jul 17 '20 at 09:21
  • 1
    @sean ng pack You are not using the constructor with iterators. – Vlad from Moscow Jul 17 '20 at 09:23
  • Thanks for the quick and valuable feedback guys! Yes you are right, sizeof will get the size of the pointer instead of the array length. I know the array length so would using this constructor work? `vec(arr, arr + length_of_array)` – sean ng pack Jul 17 '20 at 09:26
  • 1
    @seanngpack Yes that will work. – john Jul 17 '20 at 09:27
  • _"and length of the array (size of the array divided by size of the first element = length of array)"_ nooooo – Asteroids With Wings Jul 17 '20 at 09:46

3 Answers3

5

uint16_t* arr; is not an array, but is a pointer to array located in memory. The sizeof of this pointer is an integer containing an address, always equals 4. Or something else depending on architecture. But always the same constant, not the size of the array.

cout<< sizeof(arr)<< endl; // the output is 4

And sizeof(arr[0]) is a size of an 16 bit integer, so is always 2. Then sizeof arr / sizeof arr[0] will be always 2.
Probably your method some_method.getArray() returning an array of some size, you should have that size contained in some num_of_elements variable. So use that num_of_elements

std::vector<uint16_t> vec(arr, arr + num_of_elements);
armagedescu
  • 1,758
  • 2
  • 20
  • 31
  • 4
    Nit pick but on my machine a pointer is eight bytes. – john Jul 17 '20 at 09:30
  • @john Yeah, it can be different, but is always the same on the same architecture. The most important thing is that it does not show the size of the array. – armagedescu Jul 17 '20 at 09:32
  • I haven't seen a four-byte pointer in a verrry long time. – Asteroids With Wings Jul 17 '20 at 09:47
  • @AsteroidsWithWings I started programming when pointer was two-byte size – armagedescu Jul 17 '20 at 10:07
  • @armagedescu I'm sure you did, but that was a long time ago. – Asteroids With Wings Jul 17 '20 at 11:18
  • In my day, pointers were uphill both ways. – JohnFilleau Jul 17 '20 at 11:30
  • Re: "`uint16_t* arr;` ... is a pointer to array" -- no. It's a pointer to `uint16_t`. That's what `uint16_t*` says. It points to an object of type `uint16_t`. That object could be the first element of an array, but from the definition of that pointer you don't know anything except that the pointer points at a `uint16_t`. That might sound overly picky, but arrays and pointers can be very confusing if you're not careful about the way you talk about them. – Pete Becker Jul 17 '20 at 13:48
  • @PeteBecker it is pointer to array, even if it is identical to a pointer to first object. The difference is that it is allocated with new[] and should be dealocated with delete[]. There is very big difference between new and new[], as well as between delete and delete[]. – armagedescu Jul 17 '20 at 14:55
  • @armagedescu -- no. A pointer to array would be `int (*ptr)[3];` Again: `uint16_t* arr;` is a pointer to `uint16_t`. Full stop. It doesn't matter whether the pointer came from `operator new` or `operator new[]` or `malloc` or anywhere else. **If** you know that the `uint16_t` that it points at is the first element of an array you can access other elements of that array through the pointer. – Pete Becker Jul 17 '20 at 15:23
  • @PeteBecker Yes. The int(\*ptr)[3] is a pointer to a fixed size array, which size is known at compile time. But the uint16_t\* arr; is a pointer to dynamic array, which size is not known at compile time. And sizeof is a compile time operator. We are not talking about c free/malloc, which are pure allocation routines unlike new/delete. And even a bigger difference makes the new[]/delete[]. – armagedescu Jul 17 '20 at 16:16
  • 1
    @armagedescu -- please stop spreading misinformation. `uint16_t*` is a **pointer to `uint16_6`**. Just **read its declaration.** It **might** point to dynamically allocated memory, which in turn **might** be an array. Or it might just point at an auto object: `uint16_t value = 3; uint16_t* arr = &value;`. You have no way of knowing from its declaration what it in fact points at. And when you claim that it's "a pointer to dynamic array" you're making an assumption that will, sooner or later, get you in trouble. – Pete Becker Jul 17 '20 at 16:39
  • @PeteBecker it might not be an array. It is an array. You can use pointer arithmetic on it. On pointer to uint16_t you can't (ok, you can if you want such nonsense). If you don't understand correctly what it is pointing to, you are at least on risk of accumulating memory leaks. – armagedescu Jul 17 '20 at 16:57
2

To create a vector you need to know the size of the vector. So you can create a vector from an array because you know the size of the array.

But you don't have an array, you have a pointer. You cannot know the size of an array from a pointer, so your task is impossible from the information you have given.

Now maybe you have some other way to know the size of the array, if you do then you can create the vector. Please update the question if appropriate.

john
  • 85,011
  • 4
  • 57
  • 81
0

First this line is worrisome:

auto *arr = static_cast<const uint16_t *>(some_method.getArray());

You shouldn't need static_cast here, either getArray() returns uint16_t* or not.

Secondly consider rather:

auto [*arr, size] = some_method.getArray());

As you need size of array you are working on. You can't depend on sizeof pointer to return size of array you are thinking of. It works only in localscope in c, othervise it will return size of pointer not array.

Finally, depending on what you really want to do:

#include <cstdint>
#include <vector>
#include <iostream>
#include <array>
#include <tuple>

// 1. you probably don't want that:
// assigning values back from array by pointers to array to vector
std::tuple<uint16_t **, ssize_t> getArray();
auto [array, size] = getArray();
std::vector<uint16_t> v(size);
for (unsigned int i = 0; i < size; ++i) {
  v[i] = *(array[i]);
}

// 2. you probably wanted to do it like that
// this function returns pointer to first element in array
std::tuple<uint16_t *, ssize_t> getArray();
auto [array, size] = getArray();
std::vector<uint16_t> v(size);
for (unsigned int i = 0; i < size; ++i) {
  v[i] = *array;
  ++array;
}


// 3. this is the way you probably should do it
// this one returns begin and end of array and is most probable what you wanted to do
std::tuple<std::uint16_t*, std::uint16_t*> getArray()
{
    // please mind that this static arrays data is just to show that there are
    // somewhere data and these won't be lost because we created them temporarily
    // and that we don't need to release them because somebody meant to pass memory 
    static const ssize_t size = 16;
    static std::uint16_t vals[size] = {1};
    return {vals, vals + size};
}

auto [first, last] = getArray();
std::vector<std::uint16_t> v(first, last);

pholat
  • 467
  • 5
  • 20
  • You have to edit your response. The code sample provided is misleading. Because you provided three different snippets of code in one single. It will not compile because you are redeclaring variables in the same scope. Also the for loops are trivially naive to fill a vector. Because a vector already has functionality to do exactly the same thing. – armagedescu Jul 17 '20 at 12:07
  • Also about getArray returning a tuple. There are pointer and size, bound to each other, it is already a structure, and is exactly the same thing as a vector already is. I don't see the point why your getArray doesn't return just a vector instead. – armagedescu Jul 17 '20 at 12:09
  • @armagedescu Sure, I can split it to three examples. Author wrote somemehod.get() which returned some aray therefore I wanted to keep showcasing how can he work with array. I don't know why he doesn't work on vector in the very first place. Also while 'pointer array' sounds very ambigous to me - it could be array of pointers or pointer to array, and this is why I've added 3 cases for that. – pholat Jul 19 '20 at 10:27
  • That's the problem. The question is not how to implement the function. The question is how to convert array to vector. – armagedescu Jul 19 '20 at 18:15