Использование указателей для хранения строк символов - PullRequest
0 голосов
/ 03 июля 2018

Я начал изучать указатели на C. Я прекрасно понимал, пока не наткнулся на тему «Использование указателей для хранения массивов символов». Пример программы, чтобы подчеркнуть мои сомнения, выглядит следующим образом

#include <stdio.h>
main()
{
  char *string;
  string = "good"; 
  printf ("%s", string);
}

Это печатает строку символов, т.е. хорошо.

Указатели должны хранить адреса памяти, или, другими словами, мы присваиваем адрес переменной (используя оператор адреса) переменной указателя. Чего я не понимаю, так это как мы можем назначить строку символов непосредственно указателю? Это тоже без адреса оператора? Кроме того, как мы можем напечатать строку без оператора косвенного обращения (*)?

Ответы [ 4 ]

0 голосов
/ 03 июля 2018

Чего я не понимаю, так это как мы можем назначить строку символов непосредственно указателю? Это тоже без адреса оператора?

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

"good" - это строковый литерал . Он имеет массив 5 символов , который включает в себя завершающий нулевой символ . Он существует в памяти, где попытки записи не должны предприниматься. Попытка записи - неопределенное поведение (UB). Это может «сработать», а может и нет. Код может умереть и т. Д.

char *string; объявить строку как указатель на символ .

string = "good"; вызывает назначение. Операция принимает "good" и преобразует этот массив в адрес и тип (char*) своего первого элемента 'g'. Затем присваивает char * string.

Кроме того, как мы можем печатать строку без оператора косвенного обращения (*)?

printf() ожидает char * - что соответствует типу string.

printf ("%s", string); передает string в printf() как char * - преобразование не производится. printf ("%s",... ожидает увидеть «... аргумент должен быть указателем на начальный элемент массива символьного типа». затем «Символы из массива записываются до (но не включая) завершающего нулевого символа». C11 §7.21.6.1 8.

0 голосов
/ 03 июля 2018

"cccccc" - это строковый литерал, который на самом деле является массивом символов, хранящимся в памяти ReadOnly. Вы назначаете указатель на адрес первого символа этого литерала.

если вы хотите скопировать строковый литерал в RAM, вам нужно:

char string[] = "fgdfdfgdfgf";

Имейте в виду, что инициализация массива (когда вы его объявляете) - это единственное место, где вы можете использовать = для копирования строкового литерала в массив char (string).

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

 strcpy(string, "asdf");

(string должно иметь достаточно места для размещения новой строки)

0 голосов
/ 03 июля 2018

Ваш первый вопрос:
What I don't understand is how are we able to assign a character string directly to the pointer? That too without address operator?

Символьный строковый литерал - это последовательность из нуля или более многобайтовых символов, заключенных в двойные кавычки, например, "Хорошо".

Из стандарта C # 6.4.5 [Строковые литералы]:

... Затем многобайтовая последовательность символов используется для инициализации массива статической длительности хранения и длины, достаточной для размещения последовательности. Для строковых литералов символов элементы массива имеют тип char и инициализируются отдельными байтами многобайтовой последовательности символов .....

В C выражение с типом массив типа преобразуется в выражение с типом , указывающее на тип , который указывает к начальному элементу массива объекта [есть несколько исключений] . Следовательно, строковый литерал, который является массивом, распадается на указатель, который может быть присвоен типу char *.

В заявлении:

string = "good";

string будет указывать на начальный символ в массиве, где хранится "good".

Ваш второй вопрос:
Also, how are we able to print the string without the indirection operator (*) ?

С printf () :

S
пишет строку символов
Аргументом должен быть указатель на начальный элемент массива символов ...

Итак, спецификатор формата %s ожидает указатель на начальный элемент, которым является переменная string - указатель на начальный символ "good". Следовательно, вам не нужен оператор косвенного обращения (*).

0 голосов
/ 03 июля 2018

Литеральная строка типа "good" действительно хранится как (только для чтения) массив символов. Кроме того, все строки в C должны быть завершены специальным нулевым символом '\0'.

Когда вы делаете поставку

string = "good";

что действительно происходит, так это то, что вы string указываете на первый символ в этом массиве.

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


Если посмотреть немного по-другому, компилятор создает свой массив

char internal_array[] = { 'g', 'o', 'o', 'd', '\0' };

затем вы делаете string указатель на первый элемент в массиве

string = &internal_array[0];

Обратите внимание, что &internal_array[0] фактически равно internal_array, поскольку массивы естественным образом распадаются на указатели на их первый элемент.

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