Hi I am just starting to learn cpp and I have two examples of getting the size of a vector in the for statements both seem to work but which is right and why? sizeof(vector) or vector.size()?
Thanks
Brian
void print_vector(vector<string> vector_to_print){
cout << "\nCars vector = ";
for(int i = 0; i < sizeof(vector_to_print); i++){
cout << vector_to_print[i];
(i < vector_to_print.size()-1) ? (cout << ", ") : (cout << endl); // ? the tenrary operator is an if statement (?) do one outcome (:) or the other
}
}
void print_vector(vector <string> vector_to_print){
cout << "\nVector contents = ";
for( int i = 0; i < (vector_to_print.size()); i++ ){
cout << vector_to_print[i];
(i < (vector_to_print.size()-1)) ? (cout << ", ") : (cout << endl);
}
}
Both seem to work I try to rewrite the same code from memory each day for a week to help me learn it and I couldn't quite get the sizeof() to work so I googled it and the example I found used .size() but when I got home and checked what I did yesterday I had used sizeof().
std::vector<std::string> is a container class, which stores an array of std::strings plus other values to assist with manipulation of the array and providing information about the state of the stored array. When you call sizeof(vector_to_print) you are simply getting the size of the container class not the amount of elements in the array that it is storing.
run the following code to prove it to yourself:
std::vector<std::string> vec{"hello","world"};
std::cout << sizeof(vec) << '\n';
vec.push_back("!");
std::cout << sizeof(vec);
the size of the underlying array is changing it goes from 2 elements to 3, but not only does the sizeof(vec) not change, it is always = to 24!
sizeof(vec) must be the same each time (24 bytes on my machine) because sizeof is a compile time constant, because the size of a type must be a compile time constant.
The latter (.size()) is the only valid method
As you already know there are classes in C++. One class can have many methods doing different things and many fields holding different things. When we create an object of class Vector this object has method .size() which as mentioned here returns the number of elements in our object. The complexity is Constant and there is no problem using .size().
When you are using sizeof() as mentioned here on our object you know the size of the object with all its fields (for example vector can have size_t field where it counts all the elements and some field which holds them) you don't need the actual size of the vector in order to iterate the elements this could be wrong in many cases.
P.S. You must use .size()!
Related
I'm new to C++ and wanted to make a small function today which would flip all the elements of an array that was given to it (I had a pretty good idea for it). I started using arrays, but ran into issues since only a pointer to the first element is passed to the function; it was giving some very strange output. It was recommended I use a vector instead, but that started to give me some really odd output, too. I added a cout iterating over the vector values to see what it contains for some sanity-checking, but the outputs are completely bizarre; looks like I'm struggling to work out how to read input into it correctly.
As I mentioned, I first tried an array, which I could read into fine with a range-for loop. I tried that same thing with vectors (solution 1) and found it to be ignoring the first input, and assigning each element the last value that I gave it.
I first tried other Stack overflow threads but I found the solutions far too verbose or not suitable for something as simple as I need.
I thought maybe the vector couldn't be used in the range-for so I did for(auto x : array_size) instead - this gave an error stating there was no suitable "begin" for the function, so I changed this back.
Instead I looked around at the documentation and found .push_back(value) (solution 2) which appeared to put a given value at the end of the vector. Thought I might at least get some input into it correctly, which would be a step in the right direction. Instead, the output seems to show it doubled the number of positions in the vector and just assigned my first input to the furthest position. I imagine this is due to me specifying a size for the vector, and then having push_back grow the vector by that number of inputs (resulting in a double-size vector).
As for the input values themselves, I'm stumped.
Below is the offending bit of code as it stands with solution 2.
int main()
{
int array_size;
auto index_num = 0;
int arr_input = 0;
std::cout << "This program flips an array." << "\n";
std::cout << "Enter how many elements will be in your array: ";
std::cin >> array_size;
std::vector<int> user_array (array_size);
std::cout << "Fill your array with integer values. Press 'Enter' after each: " << std::endl;
for(auto x : user_array)
{
std::cin >> arr_input;
user_array.push_back(arr_input);
}
index_num = sizeof(user_array) / sizeof(user_array[0]); //or just use array_size-1 instead?
std::cout << "Your array, unflipped, contains the values: " << "\n";
for(auto y : user_array)
{
std::cout << "[" << user_array[y] << "] ";
}
Solution 2 provides this output:
Fill your array with integer values. Press 'Enter' after each:
1
2
3
4
5
Your array, unflipped, contains the values:
[0] [0] [0] [0] [0] [0] [0] [0] [0] [1]
Solution 1, where I attempt to input directly into the n-th location of the vector (as I would with an array) provides this output (with the same five 1 - 5 inputs):
Your array, unflipped, contains the values:
[0] [5] [5] [5] [5]
No error messages, everything is perfectly legal, I clearly just don't understand how something simple like a vector is implemented here.
I haven't even got to the taxing bit yet - flipping the array! Any advice appreciated.
std::vector<int> user_array (array_size) creates a vector containing array_size zeros. You then use push_back which adds additional elements to the end. You need to create an empty vector using std::vector<int> user_array, and optionally with a capacity of array_size by calling user_array.reserve(array_size). Since your vector starts out empty now, you'll need to change for(auto x : user_array) to a non-range-based loop such as for (int i = 0; i < array_size; i++).
sizeof(user_array) / sizeof(user_array[0]) only works with plain C arrays, not vectors. Use array_size or user_array.size().
In the last range-based for loop, y is the values in the array, not the indices. So print y, not user_array[y].
You seem to be confusing std::vector with C-style arrays.
std::vector<int> user_array (array_size);
initializes user_array with array_size zeroes.
for(auto x : user_array)
{
std::cin >> arr_input;
user_array.push_back(arr_input);
}
As noticed by Alexander Zhang, this piece modifies the vector while iterating over it, which results in Undefined Behaviour. It could result in anything happeining in your program, including infinite loop, crashing completely, supposingly working correct or demons flying out of your nose
index_num = sizeof(user_array) / sizeof(user_array[0]); //or just use array_size-1 instead?
This line makes no sense. You can get the length of vector using its size() method: user_array.size();, but you don't use that variable anyway.
for(auto y : user_array)
{
std::cout << "[" << user_array[y] << "] ";
}
This loop makes no sense either. y is not an index in the vector, it is a value from that vector. If you have a vector {10, 20, 30}, then in first iteration y is equal to 10, in second iteration y is 20 and in third y is 30.
After fixing the errors, your code should look like this:
std::vector<int> user_array ();
std::cout << "Fill your array with integer values. Press 'Enter' after each: " << std::endl;
for(int i = 0; i < array_size; ++i)
{
std::cin >> arr_input;
user_array.push_back(arr_input);
}
std::cout << "Your array, unflipped, contains the values: " << "\n";
for(auto y : user_array)
{
std::cout << "[" << y << "] ";
}
Or for an (invisible) increase in performance, you can reserve the size of the vector before you read it:
std::vector<int> user_array ();
user_array.reserve(array_size);
std::cout << "Fill your array with integer values. Press 'Enter' after each: " << std::endl;
for(int i = 0; i < array_size; ++i)
{
int x;
std::cin >> x;
user_array.push_back(x);
}
This question already has answers here:
How to initialize std::vector from C-style array?
(6 answers)
Closed 4 years ago.
I am working with a function which requires me to pass in an C-style array so it can be filled with data. However, the resulting array must be converted to a vector so it can be passed to another function that needs it. The vector constraint is hard, there's no getting around it. I could conceivably rework the other function so that it takes a vector, but I'd prefer not to if it can be done efficiently otherwise. Specifically, I would like there to be no copying of the data from the array to the vector if possible. As a minimal example, take the following program:
#include <iostream>
#include <algorithm>
#include <vector>
#include <chrono>
using namespace std::chrono;
static uint LENGTH = 10000000;
uint now() {
return duration_cast<microseconds>
(system_clock::now().time_since_epoch()).count();
}
void put_data_in_array(char *data) {
std::cout << now() << " filling array\n";
for (uint i = 0; i < LENGTH; i++) {
data[i] = i;
}
std::cout << now() << " filled array\n";
}
int main () {
std::cout << now() << " making array\n";
char *array = new char[LENGTH];
std::cout << now() << " made array\n";
put_data_in_array(array);
std::cout << now() << " function returned\n";
std::vector<char> v;
std::move(array, array + LENGTH, std::back_inserter(v));
std::cout << now() << " switched to vector\n";
return 0;
}
which produces the following output:
1970760826 making array
1970760926 made array
1970760927 filling array
1970774417 filled array
1970774421 function returned
1970879936 switched to vector
meaning:
100 µs to allocate memory for the array
13490 µs to fill the array
105515 µs to move the array to a vector
Ideally, I would like the time to move the array to a vector to be very small. If possible I'd like to tell the vector to take ownership of the existing array. However, if the time to transfer it to a vector can be close (less than twice) the time it takes to fill the array, I will be happy.
Thanks for any help you can give.
Edit:
Thanks for all the quick feedback! As it turns out, passing v.data() is probably the best way to accomplish what I'm looking for. I really don't care about array at all, I just knew I had to pass an array to the function.
There's no way to avoid copying the array to the vector.
The most efficient way should be to use the vector constructor to do the copy. Use two pointers which will act like begin/end iterators.
std::vector<int64_t> v(array, array + LENGTH);
I am a beginner in C++ and I am currently working with strings.
My question is why when compiling the code I'm providing below, I can get the string's characters when I use index notation, but cannot get the string itself using cout?
This is the code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string original; // original message
string altered; // message with letter-shift
original = "abc";
cout << "Original : " << original << endl; // display the original message
for(int i = 0; i<original.size(); i++)
altered[i] = original[i] + 5;
// display altered message
cout << altered[0] << " " << altered[1] << " " << altered[2] << endl;
cout << "altered : " << altered << endl;
return 0;
}
When I run this, the characters in the string altered are displayed correctly with this line:
cout << altered[0] << " " << altered[1] << " " << altered[2] << endl;
But the string itself is not displayed with this line:
cout << "altered : " << altered << endl;
I would like to know why this happens.
You have not resized your altered string to fit the length of the original string before the loop, thus your code exhibits undefined behavior:
altered[i] = original[i] + 5; // UB - altered is empty
To fix this, resize altered before the loop:
altered.resize(original.size());
Or use std::string::operator+= or similar to append to altered:
altered += original[i] + 5;
This way, it can be empty before the loop, it will automatically resize itself to contain appended characters.
Explanation
The way UB is happening here, is that you're succeeding in writing the data in the static array, which std::string uses for short string optimization (std::string::operator[] does no checks if you're accessing this array past the std::string::size()), but std::string::size() remains 0, as well as std::string::begin() == std::string::end().
That's why you can access the data individually (again, with UB):
cout << altered[0] << " " << altered[1] << " " << altered[2] << endl;
but cout << aligned does not print anything, considering simplified operator<< definition for std::string looks functionally like this:
std::ostream &operator<<(std::ostream &os, std::string const& str)
{
for(auto it = str.begin(); it != str.end(); ++it) // this loop does not run
os << *it;
return os;
}
In one sentence, std::string is not aware of what you did to its underlying array and that you meant the string to grow in length.
To conclude, <algoritm> way of doing this transformation:
std::transform(original.begin(), original.end(),
std::back_inserter(altered), // or altered.begin() if altered was resized to original's length
[](char c)
{
return c + 5;
}
(required headers: <algorithm>, <iterator>)
In your program string altered is empty. It has no elements.
Thus you may not use the subscript operator to access non-existent elements of the string as you are doing
altered[i] = original[i] + 5;
So you can append the string with new characters. There are several ways to do this. For example
altered.push_back( original[i] + 5 );
or
altered.append( 1, original[i] + 5 );
or
altered += original[i] + 5;
As you may not apply the subscript operator for an empty string to assign a value then it is better to use the range-based for loop because the index itself in fact is not used. For example
for ( char c : original ) altered += c + 5;
The size of altered is always zero - by using indexes you are trying to copy values from original to altered at indexes altered does not have. As LogicStuff has said, this is undefined behaviour - it doesn't generate an error because when we use indexes with std::string we are in fact calling an operator on a std::string to access the data field of a string. Using [] operator is defined in the C++ Standard as having no range check - that's why no error was thrown. The safe way to access indexes is to use the at(i) method: altered.at(i) will instead throw a range error if altered.size() <= i
However, I'm going to give this as my solution because it's a "Modern C++" approach (plus shorter and complete).
This is the alternative I would do to what has been given above:
string original = "abc";
string altered = original;
for (auto& c : altered) c += 5; // ranged for-loop - for each element in original, increase its value by 5
cout << altered << endl;
Note the significant reduction in code :-)
Even if I were doing it LogicStuff's way, I would still do it like this:
string original = "abc"
string altered = ""; // this is actually what an empty string should be initialised to.
for (auto c : original) altered += (c+5);
However, I actually don't recommend this approach, because of the way push_back() and string appending / string concatenation work. It's fine in this small example, but what if original was a string holding the first 10 pages of a book to be parsed? Or what if it's a raw input of a million characters? Then every time the data field for altered reaches its limit it needs to be re-allocated via a system call and the contents of altered are copied and the prior allocation for the data field is freed. This is a significant performance impediment which grows relative to the size of original -- it's just bad practice. It would always be more efficient to do a complete copy and then iterate, making the necessary adjustments on the copied string. The same applies to std::vector.
I have finished writing a program that included reversing, expanding and shifting arrays using the pointer requirement asked by the professor. Everything compiles but the answer from the expand function does not return what I wish: adding 0s after the old user input array which asks for the size of the array and the numbers you wish to put into the array. I think my problem may lie from the fact that I include a pointer on something that might not have a reference in the program. Below is my code:
// *numPtr refers to my old user input array and int tamaño is the size of the array
void expandArray(int *numPtr, int tamaño) {
int *nuevoArray = new int[tamaño *2];
for (int i = 0; i<tamaño; i++) {
nuevoArray[i] = numPtr[i];
}
for (int i = tamaño; i < (tamaño*2); i++) {
nuevoArray[i] = 0;
}
std::cout << nuevoArray << " ";
}
As I said, my theory of the code not compiling the way I wish is because I use the *nuevoArray and it has no reference in my main code, but then again, I am just a beginner with C++. I was thinking of just doing a vector, but I think I would not follow the pointer requirements placed by the professor.
If you want to print the contents of nuevoarray, just use a for loop like this:
for (int i = 0; i < (tamaño*2); i++) {
std::cout << nuevoArray[i] << " ";
}
std::cout << "\n";
Also, since you are using new[] to create the array, you should not forget to delete[] it!
you can print your array by using
for (int i = 0 ; i < tamano * 2 ; ++i) {
std::cout << nuevoArray[i] << " ";
}
std::cout << std::endl;
or in c++11
for (auto i : nuevoArray) {
std::cout << i << " ";
}
std::cout << std::endl;
PS: The std::endl will return to the start of the new line and flush the cout buffer.
Your code does appear to be allocating a larger array and correctly copying data from numPtr into the new array and also correctly filling the remainder of the new array with zeros.
You don't explicitly say what you expect this function to output, but I'm guessing you expect it to print out the contents of the new array, and that you believe there's a problem because instead of that, you're seeing it print something like "0x7fb46be05d10".
You're not correctly printing the array out. Instead you're printing the memory address of the first element out. If you want to see the contents, then you need to loop over the elements of the array and print each one out individually.
Here's a function showing one way of doing that:
#include <algorithm>
#include <iterator>
void printArray(int *arr, int n) {
std::copy(arr, arr + n, std::ostream_iterator<int>(std::cout, " "));
}
Now you can replace the line std::cout << nuevoArray << " "; in your existing code with printArray(nuevoArray, tamaño*2);
(Also it sounds like whoever is teaching you C++ should take a look at this presentation from the recent C++ conference, CppCon 2015: Stop Teaching C)
I am probably missing something fundamental, but i cannot find a solution to the following issue.
I have a two-dimensional array of some float elements and i am trying to find a way to be able to reference them by using only a single value.
Example:
float test[5][50];
test[3][25] = 34.67;
cout << test[3][25] << endl;
int id = 25;
cout << *test[id*5+3] << endl;
I am hoping to get same result from both cout. Instead my output looks like this:
34.67
Segmentation fault
What am I doing wrong?
Thanks!
Without testing, I think something like this might work. Note that C++ arrays are major->minor from left dimension to right dimension.
float test[5][50];
test[3][25] = 34.67;
cout << test[3][25] << endl;
int id = 25;
float* test2 = &test[0][0]
cout << test2[(3 * 50) + id] << endl;
test is a float[][] with 5 elements (each of which is a float[] with 50 elements), and you are referring to test[128]. Hence the seg fault.You need to convert from single index to subscript using integer division and mod:
cout << test[id/50][id%50] << endl;
You should assert(id/50<5); to make sure your index is within bounds.
The crash is because you are trying to read the contents of the element as a memory address
*test[id*5+3] means int address = test[id*5+3]; then read memory at address.
If that address is 0 or memory you don't own then it will crash.
Accessing a two-dimensional bitmap (image) with a single reference is often useful.
Use:
int image2D[dim2][dim1];
int *image1D = &image2D[0][0];
Now
image2D[i][j] == image1d[i*dim1+j]
I agree with the first comment, that you really shouldn't do it, but I'll answer anyway.
I think that if you try:
cout << test[id*5+3] << endl;
it should work. There is no need to dereference with *.