Печать адресов элементов вектора<char>показывает мусор
Рассматривать:
#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;
}
Пример вывода для кода выше:
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
Для каждого примитивного типа данных ячейки памяти являются смежными, кроме char. Это печатает некоторое значение мусора на экране.
Я попытался добавить v.reserve(4), но результат был таким же.
2 ответа
Для каждого примитивного типа данных ячейки памяти являются смежными, за исключением
char
, Это печатает некоторое значение мусора на экране.
"Области памяти" являются смежными одинаково для обоих случаев. Разница лишь в том, как вы отображаете свои результаты. Когда вы делаете:
cout << "Data: " << vChar[i] << " Address:" << &vChar[i] << "\n";
вы даете std::operator<<(std::basic_ostream)
char*
, как вы подаете заявку &
(адрес) на одном char
1 из vector
, что делает его обработанным как строка в стиле C- это означает, что он ищет завершающий ноль. В вашем случае этот нуль действительно после некоторого мусора действительно. 2 Но после того, как vector<int>
точно так же, только вы не печатаете это. 3
Если вы хотите получить ту же распечатку, что и для vector<int>
, то вы могли бы явно привести к void
указатель, так std::cout
будет обрабатывать его как адрес для печати (здесь перегрузка (7)), а не как строку:
cout << "Data: " << vChar[i] << " Address:" << static_cast<void*>(&vChar[i]) << "\n";
В этом случае вывод:
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
1 char&
чтобы быть точным, как std::vector<T>::operator[]
возвращает T&
,
2 Обратите внимание, что поиск этого завершающего нуля, который не был помещен вами, представляет собой неопределенное поведение, так как он потенциально делает вас доступным к памяти, к которой этот доступ не предназначен.
3 Йо может попробовать и убедиться в этом сам, если вы выполните обратное приведение в std::cout
относиться к vector<int>
элементы в виде строк в стиле C:
cout << "Data: " << vInt[i] << " Address:" << reinterpret_cast<char*>(&vInt[i]) << "\n";
Опять же, просто запомните, что это означает неопределенное поведение, так как код печати будет искать в памяти завершающий ноль, в то время как у вас точно не было его для его поиска.
std::vector<T>::operator[]()
возвращается T&
адрес которого в случае char
будет отформатирован перегрузкой (2) из operator<<(std::basic_ostream)
как если бы это была строка C-стиля с нулевым символом в конце (то есть строка, начинающаяся с &vChar[i]
и останавливается на первом \0
найденный).
Чтобы заставить это работать, используйте std::cout << static_cast<const void*>(&vChar[i])
подобрать перегрузку (7) из std::basic_ostream::operator<<()
,