Я часто пишу разную ерунду для эксперимента (чтоб получше понять что к чему). Вот одна из них:
#include <iostream>
#include <string>
using std::string;
struct Test {
char* s;
Test(const string str)
: s(new char[strlen(str.c_str()) + 1])
{ strcpy(s, str.c_str()); }
};
int main()
{
const string ms = "string";
Test t(ms);
char* p = t.s;
//преобразование указателья на содержащий указатель на строку "string"?
char *pt = reinterpret_cast<char*>(&t);
for (size_t i = 0; i < ms.size(); ++i) {
*pt = 'x' + i; // UB?
std::cout << t.s << endl;
}
return 0;
}
/*результат:
string
tring
ring
ing
ng
g*/
Хотелось бы получше понять что тут происходит. Хотелось бы услышать ответ подробнее(насколько это возможно). Извеняюсь: добавлю к вопросу почему указатели p и pt указывают на разную сущность?
У вас есть структура Test
, хранящая в себе указатель s
типа char *
. В строке
Test t(ms);
конструируется объект t
типа Test
. Судя по конструктору, указатель t.s
инициализируется валидным значением. Теперь t.s
указывает на первый элемент массива char
'ов, который оканчивается нулевым символом, т.е. t.s
указывает на первый символ некоторой строки.
Затем, вы получаете адрес объекта t
и преобразуете его к указателю на char
:
char *pt = reinterpret_cast<char*>(&t);
Таким образом, pt
хранит адрес первого байта объекта t
, но не строки, на которую указывает указатель t.s
!.
Следующим шагом, вы начинаете изменять объект t
через указатель на его первый байт:
*pt = 'x' + i;
Повторюсь ещё раз: вы изменяете не строку, адрес первого символа которой хранится в указателе t.s
, который в свою очередь является подобъектом t
, вы изменяете непосредственно первый байт объекта t
.
Не то что бы так делать нельзя, но в данном конкретном случае, результат может быть непредсказуемым. Немного модифицируем тело функции main
, чтобы посмотреть как изменяется t.s
после модификации первого байта объекта t
:
const string ms = "st";
Test t(ms);
char* p = t.s;
char *pt = reinterpret_cast<char*>(&t);
//Выводим адреса символов строки, на которую указывает t.s
for (size_t i = 0; i < ms.size(); ++i)
cout << "original = " << uintptr_t(t.s + i) << endl;
for (size_t i = 0; i < ms.size(); ++i) {
*pt = 'x' + i; // UB?
//Выводим модифицированный t.s
cout << "modified = " << uintptr_t(t.s) << endl;
//std::cout << t.s << endl;
}
Один из возможных выводов программы выглядит так:
original = 94862834732064
original = 94862834732065
modified = 94862834732152
modified = 94862834732153
Видно, что t.s
после модификации указывает за пределы строки, на которую он указывал изначально. t.s
— невалидный указатель, попытка его разыменования приводит к неопределённому поведению.
Если очень сильно повезёт, то первый байт объекта t
будет равен значению символа 'x'
и программа отработает именно так как в вашем вопросе, но это просто совпадение.
*pt = 'x' + i;
будет изменять первый октет указателя t.s
делая его невалидным. Последующие попытки разыменовать его приводят к неопределенному поведению.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Я переустанавливал WIndows, qt у меня находиться тут:
Нашёл, как мне показалось, очень полезную статью: ссылка
Пытаюсь подключить стороннюю библиотекуСобираю библиотеку, генерируются следующие файлы: Подключаю библиотеку в QtCreator'е:
Имеется папка с наличием в ней текстовых документов например: atxt, b