Указатель на строку и разница между присваиванием и разыменованием - PullRequest
0 голосов
/ 08 июля 2019

В следующем коде:

#include <stdio.h>

int main(void) {
    char* message = "Hello C Programmer!";
    printf("%s", message);

    return 0;
}

Я не совсем понимаю, почему не было необходимости добавлять '*' к сообщению при вызове printf.Я предполагал, что message, так как это указатель на char, первая буква в строке в двойных кавычках, будет отображать адрес из 'H'.

Ответы [ 4 ]

5 голосов
/ 08 июля 2019

Оператор формата %s требует, чтобы его соответствующий аргумент был указателем char *. Он печатает всю строку, которая начинается по этому адресу. Строка - это последовательность символов, заканчивающаяся нулевым байтом. Вот почему это печатает все сообщение.

Если вы предоставите массив в качестве соответствующего аргумента, он автоматически преобразуется в указатель на первый символ массива. В общем, всякий раз, когда массив используется в качестве r-значения, он подвергается этому преобразованию.

Вам не нужно использовать оператор *, потому что аргумент должен быть указателем. Если бы вы использовали *message, вы бы только передали символ 'H' на printf(). Вы бы сделали это, если бы вы использовали формат %c вместо %s - его соответствующий аргумент должен быть char.

3 голосов
/ 08 июля 2019

Вы правы, что message является указателем типа "указатель на char" или char *.Так что если бы вы пытались напечатать символ (отдельный символ), вам, безусловно, потребовалось бы *:

printf("first character: %c\n", *message);

В спецификаторе формата printf %c ожидаетсимвол, который дает вам *message.

Но вы не пытались напечатать один символ, вы пытались напечатать всю строку.А в спецификаторе формата printf %s ожидает указатель на символ, первый из обычно нескольких символов для печати.Так что

printf("entire string: %s\n", message);

правильно.

2 голосов
/ 08 июля 2019

Спецификатор преобразования %s используется для вывода строк (последовательность символов, оканчивающихся нулевым символом '\0'), указатели на первые символы которых передаются функции printf в качестве аргумента.

Вы можете себе представить, что функция внутренне выполняет следующий цикл

for ( ; *message != '\0'; ++message )
{
    printf( "%c", *message );
} 

Если вы предоставите выражение *message, тогда оно будет иметь тип char, и функция printf попытается интерпретировать его значение, которое является символом 'H', как значение указателя. В результате вызов функции будет иметь неопределенное поведение.

Чтобы вывести значение указателя message, вы должны использовать спецификатор преобразования %p, как

printf( "%p", message );

Или в виде целочисленного значения, например,

#include <stdio.h>
#include <inttypes.h>

int main(void) 
{
    char *message = "Hello C Programmer!";

    printf( "The value of the pointer message is %" PRIiPTR "\n", ( intptr_t )message );

    return 0;
}
1 голос
/ 08 июля 2019

Кроме того, здесь должен использоваться указатель.

Если вы передадите символ, он будет передан по значению, и printf потеряет первоначальный адрес символа.Это означает, что больше невозможно будет получить доступ к символам, которые идут после первого.

Вам нужно передать указатель по значению, чтобы убедиться, что вы сохраняете исходный адрес заголовка строки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...