I'm trying to get the last defined element in a C++ vector, but both vector::capacity and vector::size are just giving me the max size. For example:
int main() {
char* array = new char[MAX_SIZE]; //MAX_SIZE is a const int equaling 100
std::cout << "Enter in a number: ";
std::cin >> array;
std::vector<char> cVector;
cVector.reserve(MAX_SIZE);
cVector.assign(array, array + MAX_SIZE);
for (std::vector<char>::const_iterator i = cVector.begin(); i != cVector.end(); ++i)
{
std::cout << *i;
}
std::cout << std::endl;
std::cout << "Size: " << cVector.size() << std::endl;
std::cout << "Actual size: " << cVector.capacity() << std::endl;
}
Sample Output:
Enter in a number: 55
55
Size: 100
Actual size: 100 [Should say 2]
I've tried using vector::end() and similar methods, but there's no way for me to get the index of the last element.
When you call reserve(MAX_SIZE), you change the capacity, so the output 100 is what it should be. That loop where you print out the values, actually iterates all 100 times, but all the remaining chars are \0, so std::cout interprets those pointers as empty strings. Here is a slightly modified version that create a proper vector, so vector.back() will point to the last element and vector.end() to the next position in memory.
int main() {
std::string s;
std::cout << "Enter in a number: ";
std::cin >> s;
std::vector<char> cVector;
cVector.reserve(MAX_SIZE);
cVector.assign(&s[0], &s[0]+s.size());
for (std::vector<char>::const_iterator i = cVector.begin();
i != cVector.end(); ++i)
{
std::cout << *i;
}
std::cout << std::endl;
std::cout << "Size: " << cVector.size() << std::endl;
std::cout << "Actual size: " << cVector.capacity() << std::endl;
}
UPDATE: Note that I used std::string only to make it more C++-ish. You can keep using char[], just you need to replace your original assignment with:
cVector.assign(array, array + strlen(array));
size() gives the length of the vector (the number of elements actually in it, not the number of elements that it can currently fit). You're seeing the same number because you call assign(array, array + MAX_SIZE) on the vector, which will obviously fill it with MAX_SIZE elements.
Related
I am trying to split one large user given vector into x sub vectors. Everything "seems" to work as it should but the outcome is not right.
std::vector<std::vector<std::string>> split_to_sub_vectors(std::vector<std::string> initial_vector, int thread_amount) {
std::cout << "initial size: " << initial_vector.size() << std::endl;
int size_for_splitting = initial_vector.size();
std::cout << "split amount: " << thread_amount << std::endl;
int r = size_for_splitting / thread_amount;
std::cout << r << " need to be in each sub-vector" << std::endl;
std::cout << "There will be: " << size_for_splitting % thread_amount << " element remaining" << std::endl;
std::vector<std::vector<std::string>> perm_vector;
for (int x = 0; x < thread_amount; x++) {
std::vector<std::string> temp_vector;
for (int a = 0; a < r; a++) {
hm++;
std::cout << hm << std::endl;
temp_vector.push_back(initial_vector[hm]);
}
perm_vector.push_back(temp_vector);
}
std::cout << "Size of vector holding the sub vectors after splitting: " << perm_vector.size() << std::endl;
std::cout << perm_vector[0][0];
return perm_vector;
Running this code will give you this:
initial size: 7
split amount: 3
2 need to be in each sub-vector
There will be: 1 element remaining
1
2
3
4
5
6
Size of vector holding the sub vectors after splitting: 3
2
the vector i pass in is called test holds strings and is like so:
test.push_back("1");
test.push_back("2");
test.push_back("3");
test.push_back("4");
test.push_back("5");
test.push_back("6");
test.push_back("7");
Everything up until the last print statement seems to work. So perm_vector should hold 3 sub vectors containing every element in the main user given vector. When you print perm_vector[0][0] you would expect the output to be "1", but it is 2, also 7 should not be in the vector and 6 should be the last one but since it starts at 2, 7 is in it. the counter is defined outside of the function and it starts at 0. My question is why is it starting at 2?
I see two problems in your code:
hm is incremented before use. Furthermore, there is no point in making it global.
size_for_splitting is the result of an integer division, so the remainder is missing
I modified your code so the issues with hm are solved. I get the intended output <<1, 2>, <3, 4>, <5, 6>>, the 7 is missing as mentioned above.
#include <iostream>
#include<vector>
#include<string>
std::vector<std::vector<std::string> > split_to_sub_vectors(std::vector<std::string> initial_vector, int thread_amount) {
std::cout << "initial size: " << initial_vector.size() << std::endl;
int size_for_splitting = initial_vector.size();
std::cout << "split amount: " << thread_amount << std::endl;
int r = size_for_splitting / thread_amount;
std::cout << r << " need to be in each sub-vector" << std::endl;
std::cout << "There will be: " << size_for_splitting % thread_amount << " element remaining" << std::endl;
std::vector<std::vector<std::string> > perm_vector;
int hm = 0;
for (int x = 0; x < thread_amount; x++) {
std::vector<std::string> temp_vector;
for (int a = 0; a < r; a++) {
std::cout << hm << std::endl;
temp_vector.push_back(initial_vector[hm]);
hm++;
}
perm_vector.push_back(temp_vector);
}
std::cout << "Size of vector holding the sub vectors after splitting: " << perm_vector.size() << std::endl;
return perm_vector;
}
int main()
{
std::vector<std::string> test;
test.push_back("1");
test.push_back("2");
test.push_back("3");
test.push_back("4");
test.push_back("5");
test.push_back("6");
test.push_back("7");
std::vector<std::vector<std::string> > out = split_to_sub_vectors(test, 3);
}
Even if hm starts at 0, you increment it before you use it. Probably if you increment at the end of the internal for loop, you might get the output you expect. It's hard to tell the problem because I don't know what's in 'initial_vector', I assume initial_vector[0] = 1?
If you use the range-v3 library, implementing this logic becomes much easier, and less error prone:
#include <range/v3/all.hpp>
namespace rs = ranges;
namespace rv = ranges::views;
auto split_to_sub_vectors(std::vector<std::string> initial_vector, int thread_amount) {
auto res = initial_vector
| rv::chunk(thread_amount)
| rs::to<std::vector<std::vector<std::string>>>;
if (res.back().size() != thread_amount)
res.pop_back();
return res;
}
Here's a demo.
I want to increase the size of the array of string after declaring it once, how can it be done. I need to increase the size in the following code..
#include<iostream>
using namespace std;
#include<string>
int main()
{
int n;
string A[] =
{ "vaibhav", "vinayak", "alok", "aman" };
int a = sizeof(A) / sizeof(A[0]);
cout << "The size is " << a << endl;
for (int i = 0; i < a; i++)
{
cout << A[i] << endl;
}
cout << "Enter the number of elements you want to add to the string"
<< endl;
cin >> n;
cout << "ok now enter the strings" << endl;
for (int i = a; i < n + a; i++)
{
cin >> A[i];
}
a = a + n;
A.resize(a); // THIS KIND OF THING
for (int i = 0; i < a; i++)
{
cout << A[i] << endl;
}
return 0;
}
Plain and simple: you cannot.
You can get a larger array, copy all your stuff over and use that instead. But why do all that, when there is a perfectly good class already there, doing it all for you: std::vector.
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> A = {"vaibhav", "vinayak", "alok", "aman"};
std::cout << "The size is " << A.size() << std::endl;
for(string s : A)
{
std::cout << s << std::endl;
}
// want to enter more?
sd::string more;
std::cin >> more;
A.push_back(more);
std::cout << "The size is " << A.size() << std::endl;
for(string s : A)
{
std::cout << s << std::endl;
}
return 0;
}
Convert your code over to use std::vector and this problem becomes much easier to solve.
#include<iostream>
#include<string>
#include<vector>
int main(){
int n;
std::vector<std::string> A = {"vaibhav", "vinayak", "alok", "aman"};
int a = A.size();
std::cout << "The size is " << a << std::endl;
//Prefer Range-For when just iterating over all elements
for(std::string const& str : A){
std::cout << str << std::endl;
}
std::cout << "Enter the number of elements you want to add to the string" << std::endl;
std::cin >> n;
std::cout << "ok now enter the strings" << std::endl;
for(int i = 0; i < n; i++ ) {
//emplace_back automatically resizes the container when called.
A.emplace_back();
std::cin >> A.back();
//If you're using C++17, you can replace those two lines with just this:
//std::cin >> A.emplace_back();
}
for(std::string const& str : A){
std::cout << str << std::endl;
}
return 0;
}
Also, don't use using namespace std;, since it leads to expensive to fix bugs and makes your code harder to read for other C++ programmers.
I want to increase the size of the array of string after declaring it
once, how can it be done.
It cannot be done. Use std::vector if the element count isn't known at compile time or can change dynamically. It even has a resize member function named exactly like the one in your code.
You cannot increase the size of a Raw Array, you could use an std::vecto<std::string> as this type of array can grow at runtime.
However, you could also create a class that will store an array of string and create your own implementation to resize the raw array. Which would be creating a bigger array and copying all the other values over, then setting the class array to the new array (or just return it)
As stated in the title, when I pass a vector to another function, its capacity becomes equal to its size at the time of the function call.
void sizeCheck(std::vector<int> test)
{
std::cout << "Size: " << test.size() << std::endl;
std::cout << "Capacity: " << test.capacity() << std::endl;
std::cout << std::endl;
}
int main()
{
std::vector<int> test;
for(int i = 0; i < 10; ++i)
{
test.push_back(i);
std::cout << "Size : " << test.size() << std::endl;
std::cout << "Capacity: " << test.capacity() << std::endl;
std::cout << std::endl;
}
test.resize(0);
for(int i = 0; i < 10; ++i)
{
test.push_back(i);
sizeCheck(test);
}
}
The above code's first series of outputs show that the vector's capacity increases how one could normally expect; however, the second series of outputs is indicating that the size is always equal to the capacity. I'm assuming this means the capacity is being pushed back by one each time.
I understand that normally it would be best to just pass by reference (const or not), but isn't there any circumstance where I would need to pass a copy of a vector and manipulate it in some way without affecting my original data? In this case, passing by value would be inefficient if every time I use push_back, it has to relocate the vector.
Something like
v2.assign(v1.first(), v1.end());
func(v2);
would work, assuming func() takes a vector by reference, but it seems strange to me that I'm allowed to pass a vector to a function by value if there are zero cases where it's the best option.
In C++ you have the choice of passing by value, by reference, or by pointer, depending on the situation.
You are passing your vector by value into the function. A copy of the vector is being made. The vector copy constructor makes the capacity of the new vector the same as the size of the vector being copied from.
If you pass your vector by reference or by pointer instead, no copy is made, you output the size/capacity of the original vector instead:
void sizeCheck(std::vector<int> &test)
{
std::cout << "Size: " << test.size() << std::endl;
std::cout << "Capacity: " << test.capacity() << std::endl;
std::cout << std::endl;
}
void sizeCheck(std::vector<int> *test)
{
std::cout << "Size: " << test->size() << std::endl;
std::cout << "Capacity: " << test->capacity() << std::endl;
std::cout << std::endl;
}
I'm trying to assign an array's values to a vector. It seems to be working fine for one vector, but when I do it for a second, I'm getting back garbage values. I cout the number and I know it's correct, but it's not assigning correctly. I don't understand because it's working fine for the first vector.
int sorted[] = {0,1,2,3,4,5,6,7,8,9,10};
// make two smaller arrays, do this untill they are a base case size;
void split(int *dataIN, int dataSize){
// new data will be broken up into two vectors with each half of the
// original array. These will be size firstHalfSize and secondHalfSize.
int firstHalfSize;
int secondHalfSize;
vector<int> firstHalf;
vector<int> secondHalf;
// test to see if array in is odd or even
bool isOdd;
if (dataSize%2 == 1){
isOdd = true;
}else if (dataSize%2 == 0){
isOdd = false;
}
// determine length of new vectors
// second half is firstHalf + 1 if odd.
firstHalfSize = dataSize/2;
if (isOdd){
secondHalfSize = firstHalfSize + 1;
}else if (!isOdd){
secondHalfSize = firstHalfSize;
}
// assign first half of dataIn[] to firstHalf vector
cout << "firs: " << firstHalfSize << endl;
for (int i = 0; i < firstHalfSize; i++){
cout << "a: " << dataIN[i] << endl;// make sure i have the right number
firstHalf.push_back(dataIN[i]);// assign
cout << "v: " << firstHalf[i] << endl;// make sure assigned correctly
}
// do the same for second half
cout << "second: " << secondHalfSize << endl;
for (int i = firstHalfSize; i < (firstHalfSize+secondHalfSize); i++){
cout << "a: " << dataIN[i] << endl;
secondHalf.push_back(dataIN[i]);
cout << "v: " << secondHalf[i] << endl;
}
}
int main(void){
split(sorted, sizeof(sorted)/sizeof(int));
return 0;
}
This is my result. As you can see the first vector push_back went fine and the array values (after "a: ") are also correct.
firs: 5
a: 0
v: 0
a: 1
v: 1
a: 2
v: 2
a: 3
v: 3
a: 4
v: 4
second: 6
a: 5
v: -805306368
a: 6
v: 2
a: 7
v: -805306368
a: 8
v: 0
a: 9
v: 0
a: 10
v: 0
In the second case, you are indexing from firstHalfSize.
You need to cout the values starting from index 0. For example:
cout << "v: " << secondHalf[i-firstHalfSize] << endl;
You are iterating firstHalf from 0 to firstHalfSize with the variable i, so i will be within the range of firstHalf, when you use operator[] - in the second vector's case, i does not mean the same thing.
The filling of the vector is working. It is just your debug output that is incorrect. When outputting values from secondHalf you need to use indexes from 0, not from firstHalfSize.
You can write your code more simply if you take advantage of the std::vector range constructor that takes a pair of iterators. Array pointers can be treated as iterators:
void print(const std::vector<int>& data){
for(int value : data)
std::cout << value << " ";
std::cout << "\n";
}
void split(int *dataIN, int dataSize){
auto firstHalfSize = (dataSize + 1) / 2;
std::vector<int> firstHalf(dataIN, dataIN + firstHalfSize);
std::vector<int> secondHalf(dataIN + firstHalfSize, dataIN + dataSize);
std::cout << "firstHalf: ";
print(firstHalf);
std::cout << "seconHalf: ";
print(secondHalf);
}
Live demo
Vectors double their size each time they run out of space when adding an element, but what about when you remove elements? say you added 800 elements to an array, and on the addition of that 800th element, the vector doubles its size to be able to hold 1600 elements. Now what if you start taking away elements to the point that its only holding say 5 or 10 elements?
will it recognize that the vector is much smaller than half the size of the space reserved for future elements and reserve less space?
Vectors do not decrease in capacity when removing elements! This is to allow future elements to be added efficiently into the existing buffer.
If it has already allocated a block of memory, it will continue to use it because it would be inefficient for it to free up some memory and later find it has to allocate more memory.
I always recommend writing a test snippet of code to test these sorts of things.
For example, I threw this together in 2 minutes to verify that I was telling you correct information:
#include <iostream>
#include <vector>
void printInfo(std::vector<char> &_vector)
{
std::cout << "Size: " << _vector.size() << std::endl;
std::cout << "Capacity: " << _vector.capacity() << std::endl;
std::cout << std::endl;
}
int main()
{
int numbElems = 10;
std::vector<char> myvector;
std::cout << "Nothing entered" << std::endl;
printInfo(myvector);
for (int i = 0; i < 10; i++) {
for (int c = 0; c < numbElems; c++) {
myvector.push_back(i);
}
std::cout << "Pushed " << numbElems << std::endl;
printInfo(myvector);
}
for (int i = 0; i < 5; i++) {
for (int c = 0; c < numbElems; c++) {
myvector.pop_back();
}
std::cout << "Popped " << numbElems << std::endl;
printInfo(myvector);
}
myvector.erase(myvector.begin(), myvector.end());
printInfo(myvector);
std::cout << "max_size: " << myvector.max_size() << std::endl;
return 0;
}
If you compile and run you will see Capacity never goes down in size. Even after erase, or some of the elements are removed.
On linux you can use less to scroll through the output.