#c #pointers #char
Вопрос:
тестовый код:
#include <iostream>
using namespace std;
int main()
{
const char* b="str";
cout << b << endl;
cout << *b << endl;
cout << amp;b << endl;
cout << *(amp;b) << endl;
return 0;
}
Результат:
str
s
0x7ffdf39c27f0
str
Я запускаю свой код в веб-компиляторе runoob online
Почему я получаю эти результаты? Я посмотрел несколько вопросов о char*, но недостаточно, чтобы понять. Кто-нибудь может мне это объяснить? Фотографии лучше всего.
Я хочу узнать об этом больше с помощью рекомендованных книг или блогов.
Кстати, используя char b[]
вместо const char*
, я получаю те же результаты.
Большое спасибо за всех вас.
Я просто хочу знать, почему значение указателя символа не является адресом.
Я думаю, что адрес похож на 0x7ffdf39c27f0. адрес в памяти.
Но const char* b = "str"
. б справедлив str
.
И я обнаружил, что *b
это то же *("str")
самое, что и .
Итак, я хочу знать, что произошло в памяти? почему значение указателя символа не является адресом?
Комментарии:
1. Что в этих результатах сбивает с толку? Вы печатаете строку с окончанием 0, первый символ этой строки, ее адрес, а затем снова строку.
2. Всегда полезно высказать свои ожидания. Это позволяет тем, кто отвечает, сосредоточиться на конкретных ошибках или заблуждениях и, как правило, дает более качественный ответ.
3. Смущенный. Является
b
ли указатель или строка? Основываясь на определении, я бы подумалb
, что вернет указатель.
Ответ №1:
Чтобы понять, что выводит код, необходимо понимать, что выходные потоки C (объекты с таким типом, как std::ostream
) и, следовательно, объекты (такие как std::cout
) имеют ряд перегрузок operator<<()
. Вызываемая перегрузка зависит от типа предоставленного аргумента.
Я объясню ваш второй пример, но объяснение для первого примера почти идентично.
const char* b="str"; cout << b << endl; cout << *b << endl; cout << amp;b << endl; cout << *(amp;b) << endl;
cout << b
расширяется до cout.operator<<(b)
места, где b
есть тип const char *
. Эта перегрузка операторной функции ПРЕДПОЛАГАЕТ, что аргумент указывает на (первый символ) строку, заканчивающуюся нулем, которая представлена в памяти в виде массива char
, заканчивающегося char
значением ''
(ноль). Функция оператора выводит каждый найденный символ, пока он не достигнет определенного ''
символа. Первый ''
найденный-это тот , который ВЫ явно вставили после 't'
, поэтому вывод st
будет получен. Тот факт, что в вашей строке есть секунда ''
после 'r'
, не имеет значения, так как функция оператора останавливается на первой, которую она находит.
cout << *b
расширяется до вызова другой перегрузки operator<<()
, которая принимает один char
и выводит его char
. *b
является значением первого символа в строке, представленной b
. Таким s
образом, получается результат.
В cout << amp;b
, amp;b
имеет тип const char **
или (эквивалентно) char const **
. Нет перегрузки выходного потока operator<<()
, который принимает a const char **
, но есть перегрузка, которая принимает a const void *
. Поскольку любой указатель (кроме указателя на элемент или указателей на функции) может быть неявно преобразован void *
, это преобразование выполняется (компилятором), поэтому перегрузка соответствует и вызывается. Эта конкретная перегрузка operator<<()
печатает адрес в памяти.
Неявное преобразование в третьем случае не происходит в первых двух случаях, так как вызов, который не требует неявного преобразования, лучше соответствует вызову, который его выполняет.
В последнем утверждении *(amp;b)
это эквивалентно b
. Это происходит потому amp;
, что оператор адреса в этом коде и оператор *
разыменования (который является обратным оператору адреса). Таким образом, последнее утверждение выдает тот же результат, cout << b
что и .
Ответ №2:
cout << b << endl;
Вы печатаете строку b
cout << *b << endl;
Вы печатаете указатель, указывающий на первый символ b
., так что это то же самое, что:
cout << b[0] << endl;
cout << amp;b << endl;
amp;b
является адресом памяти b
, что означает адресную память для хранения b
в компьютере.
cout << amp;b << endl;
Итак, вы печатаете адрес памяти b
здесь. Компьютер хранит b
адрес в памяти 0x7ffdf39c27f0
, так что вот что вы получаете.
cout << *(amp;b) << endl;
Вы печатаете указатель , указывающий на память b
, поэтому вы печатаете значение по адресу памяти переменной b
, которое совпадает с
cout << b << endl;
изменить: Указатель содержит адрес, который (обычно, он может указывать на функцию, например) представляет местоположение объекта, и для печати указателя (обычно) выводится значение этого адреса памяти. Поскольку char *
он тесно связан со строками, заканчивающимися нулем, существует специальная перегрузка для указателей на символы для печати указанной строки.
Переменная указателя по-прежнему является переменной и будет иметь собственный адрес, поэтому amp;b
в результате получается указатель на указатель, char **
в данном случае a , и поскольку он больше не является a char *
, cout << amp;b;
выводится адрес b
, а не адрес, на который указывает b
или строка, на которую указывает b
.
Комментарии:
1. Часто важно, чтобы было ясно, что
b
это строка с нулевым завершением и не имеет ни одного из колоколов и свистков astd::string
.amp;b
является ли адрес памятиb
, который означает адресную память для храненияb
в компьютере. на 100% правильный, но не думайте, что это будет понятно кому-то, кто придет холодным и не осознает разницу между указателем и указываемым на нас. Может быть, еще одна фраза, чтобы забить лошадь до смерти.2. Намного лучше, но не возражаешь, если я слегка подправлю?
3. @user4581301 Конечно! Определенно, можешь.
4. Потребовалось немного больше, чтобы завершить все это, чем я ожидал. Не стесняйтесь возвращаться, если я забрел слишком далеко от ваших намерений.