В вашей транскрипции кода из книги есть небольшая проблема, а затем есть понимание, необходимое для char **field;
, чтобы иметь смысл.
В моем экземпляре книги первая строка, которую вам трудно понять, написана не так, как вы цитируете. Ваша цитата первая; то, что говорится в книге, занимает второе место:
field = (char **) malloc(maxfield*sizeof(field));
field = (char **) malloc(maxfield*sizeof(field[0]));
Я с облегчением, потому что официальная версия верна, хотя первая будет работать несколько случайно. Разница заключается в том, что пространство выделяется для maxfield
копий char **
, в то время как для этого большого количества char *
требуется пространство. Теперь, как это происходит, sizeof(char **) == sizeof(char *)
, но лучше всего уяснить, о чем просят. Для указателя ptr
типа Xyz *
идиома для выделения массива значений N
:
Xyz *ptr = (Xyz *)malloc(N * sizeof(*ptr));
где *ptr
, конечно, относится к типу Xyz
и также эквивалентно ptr[0]
, обозначению, используемому в книге.
Теперь о char **field
… то, что выделено, можно понять с помощью диаграммы, подобной этой:
+-------+ +----------+
| field |---->| field[0] |
+-------+ +----------+
| field[1] |
+----------+
| field[2] |
+----------+
| field[3] |
+----------+
...
При первоначальном выделении каждый из field[0]
, field[1]
,… не имеет инициализированного значения и нигде не указывает. В коде при разборе полей пространство выделяется для каждого поля следующим образом:
char ** char * char
+-------+ +----------+ +----------------+
| field |---->| field[0] |---->| String value 1 |
+-------+ +----------+ +----------------+ +----------+
| field[1] |-------------------------->| String 2 |
+----------+ +--------------+ +----------+
| field[2] |---->| Third String |
+----------+ +--------------+
| field[3] |
+----------+
...
Элементы массива являются смежными; строки не являются смежными. Каждый элемент массива - это, конечно, char *
.
Теперь внутри csvfield(int n)
функция возвращает NULL или field[n]
. Как видно из диаграммы, значения field[n]
равны char *
. Таким образом, код верен, и он возвращает char *
, как указано в сигнатуре функции. (Код тоже компилируется, даже при строгих уровнях предупреждения.)