HoneyBunchers
HoneyBunchers

Reputation: 45

Is there a way to fill a vector using an array?

I'm trying to fill a vector with integers from an array I have but when I check the contents of the vector all the values are zero.

I'm using vector.push_back() to try and fill the vector so it will be in the same order as the array as I needed it ordered in a specific way.

unsigned char* buffer = new unsigned char[size];
std::vector<unsigned char> *data = new std::vector<unsigned char>(size);
fread(buffer, sizeof(unsigned char), size, f);
for(int transfer = 0; transfer < size; transfer += 1){
    std::cout << buffer[transfer];
    data->push_back(buffer[transfer]);
    std::cout << int(data->at(transfer));
}
fclose(f);

When I print the output I can see that the values aren't zero when they're coming from the buffer array but they are when I read from the data vector. Here is some example output φ0$0.

Upvotes: 1

Views: 5111

Answers (3)

walnut
walnut

Reputation: 22152

The overload of the constructor of std::vector that you are using takes the number of elements to initialize the vector with and initializes these (to 0 in this case).

After the line

std::vector<unsigned char> *data = new std::vector<unsigned char>(size);

*data therefore contains already size elements set to zero.

Then with data->push_back(...) you are adding additional elements after these size elements. You are not overwriting the previous ones.

Either use

std::vector<unsigned char> *data = new std::vector<unsigned char>();

to default-initialize an empty vector, or use

(*data)[transfer] = ...

to set the elements at the given location.

Furthermore your program has undefined behavior if the fread reads less than size bytes into the array. You need to check the number of bytes read from its return value and you are not allowed to access any elements beyond that in data, because you never initialized it.

You can initialize it to zero with:

unsigned char* buffer = new unsigned char[size]{};

If you want to write C++, don't use C library functions like fread, use the facilities provided by <fstream>, i.e. std::ifstream and std::ofstream instead.

Similarly there is no need for dynamic memory allocation here. Declare variables with automatic storage:

unsigned char buffer[size]{};
std::vector<unsigned char> data(size);

and the rest of the syntax also simplifies:

data[transfer] = ...

Finally, as mentioned in the other answer, there is a constructor for std::vector that will perform the whole copy loop for you. Note however that my argument about undefined behavior still applies when using that.

Defining data as automatic array as in

unsigned char buffer[size]{};

works only if size is a compile-time constant. If it is not, then this part of my advice does not apply. However there is no real need to use arrays at all in any case. You can initialize a std::vector of proper size (compile-time constant or not) and provide that as buffer via its .data() method, which returns a pointer to the underlying (continuous) storage:

std::vector<unsigned char> buffer(size);
fread(buffer.data(), sizeof(unsigned char), buffer.size(), f);

Upvotes: 3

Oblivion
Oblivion

Reputation: 7374

std::vector has a constructor for this purpose:

std::vector<unsigned char> data(buffer, buffer + size);

newing a vector almost always should be avoided.

Live

Upvotes: 5

Blastfurnace
Blastfurnace

Reputation: 18652

You don't need a separate buffer or any dynamic allocation in your code. You can create the std::vector with the desired size and then read from the file directly into the vector. The std::vector::data member function returns a pointer to the vector's underlying array that you can pass to the fread() function

std::vector<unsigned char> vec(size);
fread(vec.data(), sizeof(unsigned char), size, f);

Ideally you'll also check the return value from fread() to know how many elements were read.

Upvotes: 2

Related Questions