Зачем использовать char **lineptr
вместо char *lineptr
в качестве параметра функции getline
?
Представьте, что прототип для getline
выглядит следующим образом:
ssize_t
getline(char *line, size_t n, FILE *stream);
И вы назвали это так:
char *buffer = NULL;
size_t len = 0;
ssize_t read = getline(buffer, len, stdin);
Перед вызовом getline
, buffer
равно нулю:
+------+
|buffer+-------> NULL
+------+
Когда вызывается getline
, line
получает копию buffer
, поскольку аргументы функции передаются по значению в C. Внутри getline
у нас больше нет доступа к buffer
:
+------+
|buffer+-------> NULL
+------+ ^
|
+------+ |
| line +----------+
+------+
getline
выделяет некоторую память с помощью malloc
и указывает line
на начало блока:
+------+
|buffer+-------> NULL
+------+
+------+ +---+---+---+---+---+
| line +------->+ | | | | |
+------+ +---+---+---+---+---+
После возврата getline
у нас больше нет доступа к line
:
+------+
|buffer+-------> NULL
+------+
И мывернулись туда, где мы начали.Мы не можем перенаправить buffer
на вновь выделенную память внутри getline
, потому что у нас есть только копия buffer
.
Прототип для getline
на самом деле:
ssize_t
getline(char **lineptr, size_t *n, FILE *stream);
И вы называете это так:
char *buffer = NULL;
size_t len = 0;
ssize_t read = getline(&buffer, &len, stdin);
&foo
возвращает указатель на foo
, поэтому мы имеем:
+-------+ +------+
|&buffer+------->+buffer+-------> NULL
+-------+ +---+--+
Когда getline
вызывается, lineptr
получает копию &buffer
, потому что C - это вызов по значению.lineptr
указывает на то же место, что и &buffer
:
+-------+ +------+
|&buffer+------->+buffer+-------> NULL
+-------+ +---+--+
^
+-------+ |
|lineptr+------------+
+-------+
getline
выделяет некоторую память с помощью malloc
и указывает на точку lineptr
(то есть на вещь, на которую указывает lineptr
)в начале блока:
+-------+ +------+ +---+---+---+---+---+
|&buffer+------->+buffer+------->+ | | | | |
+-------+ +---+--+ +---+---+---+---+---+
^
+-------+ |
|lineptr+------------+
+-------+
После возврата getline
у нас больше нет доступа к lineptr
, но мы все еще можем получить доступ к вновь выделенной памяти через buffer
:
+-------+ +------+ +---+---+---+---+---+
|&buffer+------->+buffer+------->+ | | | | |
+-------+ +---+--+ +---+---+---+---+---+