Печать адресов элементов вектора<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<<(),

Другие вопросы по тегам