Начну с того, что в:
const string l = "BA";
const char* k = l.c_str();
const char* p = "BA";
cout << k << " " << *((size_t*)k) << endl;
cout << p << " " << *((size_t*)p) << endl;
И *((size_t*)k)
, и *((size_t*)p)
вызывают неопределенное поведение .Это так, поскольку в большинстве систем он получает доступ к данным за пределами массива char.Обратите внимание, что sizeof(size_t) > 3 * sizeof(char)
для 32- и 64-битной системы, так что *((size_t*)k)
обращается как минимум к одному байту за границей.
Во всем примере строковые литералы (в вашей системе) возможно выровнены попо крайней мере sizeof(size_t)
, с нулевым заполнением (не рассчитывайте на это, но, похоже, так).Это означает, что мусор после строкового литерала "BA"
(и терминатор NUL) является символом (ами) NUL.Это согласуется для всех прогонов.
В случае k
, который исходит от std::string
, вам не так повезло.Строка короткая, поэтому большинство систем будет использовать оптимизация короткой строки .Это означает, что этот буфер char
находится в объекте std::string
.В вашем случае строка настолько короткая, что остальная ее часть все еще находится в буфере, выделенном для оптимизации короткой строки.Как кажется, оставшаяся часть буфера не инициализируется и содержит ненужные.Хлам остался до вызова функции.В результате, кроме первых 3 байтов BA\0
, остальное - случайный мусор.
Вам повезло, что этот случай неопределенного поведения заканчивается дополнительным мусором, а не чем-то более озадачивающим (как всегдавозвращение нуля или вызов не связанных функций).Никогда не полагайтесь на UB.