Вы можете подписать указатель так же, как вы можете подписать массив, при условии, что все адреса были установлены правильно.
При условии следующего объявления:
char **ptr;
Вот типы различных выражений:
Expression Type Equivalent expressions (yield same value)
---------- ---- -----------------------------------------
ptr char ** &ptr[0]
*ptr char * ptr[0]
*(ptr+i) char * ptr[i]; &ptr[i][0]
**ptr char ptr[0][0]
*(*(ptr+i)) char ptr[i][0]; *ptr[i]
*(*(ptr+i)+j) char ptr[i][j]
следующим образом:
ptr
можно трактовать , как если бы это был массив строк (2-й массив символов)
ptr[i]
указывает на начало i-й строки в списке
ptr[i][j]
- значение j-го символа i-й строки в списке
- Выражения
ptr++
и ++ptr
будут продвигаться ptr
, чтобы указывать на следующую строку
- Выражения
(*ptr)++
и ++(*ptr)
будут продвигаться *ptr
, чтобы указывать на следующий символ
Что касается настройки ваших указателей, эта схема предполагает, что все уже было выделено как статические массивы или динамически через malloc
. Вы не можете просто написать
char **ptr = {"foo", "bar", "bletch"}; // using aggregate initializer on
// non-aggregate type; bad juju,
// a.k.a undefined behavior
или
char **ptr; // ptr has not been initialized to point anywhere
ptr[0] = "foo"; // dereferencing ptr via subscript invokes undefined
ptr[1] = "bar"; // behavior
ptr[2] = "bletch";
Как правило, когда вы используете указатель, как если бы он был массивом, вы будете использовать malloc
или что-то подобное для распределения ваших буферов:
char **ptr = malloc(sizeof *ptr * N);
if (ptr)
{
ptr[0] = "foo"; // ptr[i] gets address of
ptr[1] = "bar"; // string literal
ptr[2] = "bletch";
...
}
или
char **ptr = malloc(sizeof *ptr * N);
if (ptr)
{
size_t i;
for (i = 0; i < N; i++)
{
ptr[i] = malloc(sizeof *ptr[i] * M); // strictly speaking, the sizeof
if (ptr[i]) // is not necessary here
{
//initialize ptr[i]
}
}
}