Что такое указатель?Указатель - это переменная, которая хранит адрес (ячейку памяти).Это может быть адрес другой переменной
int n = 9;
int *ptr = &n; // stores the address of n
или это может быть начало блока памяти, например, динамически выделяемого блока памяти:
int *fields = malloc(len * sizeof *fields);
Независимо от того, какой адрес указатель являетсяуказывая на, мы используем указатели для прямого доступа к памяти, которая хранится в указателе (мы также говорим , где указатель указывает на ).
Что такое строки?Вы должны понимать, что в C нет строкового типа, как в других языках программирования.В C строка - это просто последовательность 8-битных значений (представляющих символы), которые заканчиваются байтом, определяющим '\0'
.Естественный тип для одного символа - char
, поэтому мы используем char*
или char[]
для получения строки.
Когда вы делаете
const char *str = "Hello";
str
указывает где-то в памяти, и это выглядит так:
b = base address of the first character in the
sequence
b b+1 b+2 b+3 b+4 b+5
+-----+-----+-----+-----+-----+------+
| 'H' | 'e' | 'l' | 'l' | 'o' | '\0' |
+-----+-----+-----+-----+-----+------+
Целочисленные значения символьных констант, таких как 'H'
, определяются таблицей ASCII .Итак, на самом деле память выглядит так:
b = base address of the first character in the
sequence
b b+1 b+2 b+3 b+4 b+5
+----+-----+-----+-----+-----+-----+
| 72 | 101 | 108 | 108 | 111 | 0 |
+----+-----+-----+-----+-----+-----+
Итак, str
указывает на это местоположение b
, str[0]
- первый символ, str[1]
- второй и т. Д. Как вы видите, чтобы получить строку, все, что вам нужно, это доступ к первому символу в последовательности.Вот почему мы используем указатель char*
для адресации строк, потому что с указателем char*
мы имеем доступ к первому и последующим символам в строке.
Функция, подобная puts(str)
, выполняетследующее:
- является ли текущий символ байтом, определяющим
'\0'
? - , если да, затем выйти
- , если нет, затем распечатать символ и перейти к следующему
Так что puts(str)
делаетне печатать адрес, на который указывает указатель, он печатает содержимое памяти, на которую указывает указатель.
Функция, подобная strchr
, работает следующим образом:
man strchr
char *strchr(const char *s, int c);
ОПИСАНИЕ
Функция strchr()
возвращает указатель на первое вхождение символа c
в строкеs
.
Теперь, когда вы знаете расположение строк в памяти, это должно быть легко понять.Давайте посмотрим на это:
const char *str = "Hello";
char *f = strchr(str, 'l');
Помните, что расположение памяти, на которое указывает str
:
b = base address of the first character in the
sequence
b b+1 b+2 b+3 b+4 b+5
+-----+-----+-----+-----+-----+------+
| 'H' | 'e' | 'l' | 'l' | 'o' | '\0' |
+-----+-----+-----+-----+-----+------+
^
¦
first occurrence
of 'l'
, так что strchr
возвращает указательна b+2
(или str+2
, потому что в моем примере b это значение, которое хранит указатель str
).
Вот почему, когда вы puts(str)
получаете Hello
, а когдавы делаете puts(f)
вы получаете llo
.
Простая реализация для strchr
:
char *strchr(const char *s, int c);
{
// stop when the \0-terminating byte is reached
for(size_t i = 0; s[i] != '\0'; ++i)
{
if(s[i] == c)
return &s[i]; // or return s+i; using pointer arithmetic
}
return NULL; // c is not found in the string
}
Так что же это делает?
while(( p = strchr( p, ':' )) != NULL )
{
puts( ++p )
}
Когда strchr
в первый раз возвращает значение, отличное от NULL
, оно вернет указатель на первое вхождение двоеточия :
.puts(++p)
эквивалентно
p = p + 1; // let p point to the next next character after the colon
puts(p); // prints the string
, затем strchr
выполняется снова, поскольку в строке есть еще одно двоеточие :
, оно не будет возвращать NULL
, но местоположение где :
хранится.В следующий раз, когда цикл будет выполнен, больше нет двоеточий, и strchr
вернет NULL
, тем самым завершив цикл.Таким образом, вывод будет:
MEAS:VOLT:DC? // puts( p );
VOLT:DC? // 1. puts( ++p ); of the loop
DC? // 2. puts( ++p ); of the loop