Consider:
#include <vector> #include <string> #include <iostream> using namespace std; int main() { vector<char> vChar; vChar.push_back('a'); vChar.push_back('b'); vChar.push_back('c'); vChar.push_back('d'); vector<int> vInt; vInt.push_back(1); vInt.push_back(2); vInt.push_back(3); vInt.push_back(4); cout << "For char vector Size:" << vChar.size() << " Capacity:" << vChar.capacity() << "\n"; for(int i=0; i < vChar.size(); i++) { cout << "Data: " << vChar[i] << " Address:" << &vChar[i] << "\n"; } cout << "\nFor int vector Size:" << vInt.size() << " Capacity:" << vInt.capacity() << "\n"; for (int i = 0; i < vInt.size(); i++) { cout << "Data: " << vInt[i] << " Address:" << &vInt[i] << "\n"; } return 0; }
Sample output for the code above is:
For char vector Size:4 Capacity:4 Data: a Address:abcd²²²²αPⁿ▀┬ Data: b Address:bcd²²²²αPⁿ▀┬ Data: c Address:cd²²²²αPⁿ▀┬ Data: d Address:d²²²²αPⁿ▀┬ For int vector Size:4 Capacity:4 Data: 1 Address:000001F020F80420 Data: 2 Address:000001F020F80424 Data: 3 Address:000001F020F80428 Data: 4 Address:000001F020F8042C
For every primitive data type memory locations are contiguous, except for char. It prints some garbage value on the screen.
I tried adding v.reserve(4), but the output was the same.
For every primitive data types memory locations are contiguous, except for
char
. It prints some garbage value on screen.
The "memory locations" are contiguous in the exact same way for both cases. The only difference is in how you're displaying your results. When you do:
cout << "Data: " << vChar[i] << " Address:" << &vChar[i] << "\n";
you're giving std::operator<<(std::basic_ostream)
a char*
, as you're applying &
(address-of) on a single char
1 from the vector
, which makes it treat it as a C-style string -- meaning, it looks for a terminating null. In your case, this null is right after some garbage indeed.2 But you're bound to have some garbage after the vector<int>
just as well, only you're not printing it.3
If you want to get the same printout as you're getting for the vector<int>
, then you could explicitly cast to a void
pointer, so std::cout
will treat it as an address to be printed (overload (7) here), not a string:
cout << "Data: " << vChar[i] << " Address:" << static_cast<void*>(&vChar[i]) << "\n";
In which case the output is:
For char vector Size:4 Capacity:4 Data: a Address:0x1c39810 Data: b Address:0x1c39811 Data: c Address:0x1c39812 Data: d Address:0x1c39813 For int vector Size:4 Capacity:4 Data: 1 Address:0x1c39960 Data: 2 Address:0x1c39964 Data: 3 Address:0x1c39968 Data: 4 Address:0x1c3996c
1char&
to be precise, as std::vector<T>::operator[]
returns a T&
.
2 Note that looking for this terminating null that wasn't placed there by you constitutes undefined behavior, as it potentially makes you access memory that isn't intended to be accessed for this purpose.
3 You can try and see so for yourself if you perform the reverse casting to make std::cout
treat the vector<int>
elements as C-style strings:
cout << "Data: " << vInt[i] << " Address:" << reinterpret_cast<char*>(&vInt[i]) << "\n";
Again, just remember this means undefined behavior as the printing code will look in memory for the terminating null while you definitely didn't have it there for it to find.
std::vector<T>::operator[]()
returns T&
, address of which in case of char
will be formatted by overload (2) of operator<<(std::basic_ostream)
as if it was a null terminated C-style string (that is a string that begins at &vChar[i]
and stops at the first \0
found).
To make it work use std::cout << static_cast<const void*>(&vChar[i])
to pick up overload (7) of std::basic_ostream::operator<<()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With