#c #linked-list #environment-variables #token
#c #связанный список #переменные среды #знак
Вопрос:
Код выглядит следующим образом:
typedef struct Node { char *str; struct Node *next; } Node; Node *_getdir(char *path, char **pathCopy) { char *token = NULL; Node *head; Node *pathNode; if (path == NULL) return (NULL); *pathCopy = strdup(path); head = NULL; pathNode = malloc(sizeof(Node)); if (pathNode == NULL) return (NULL); token = strtok(*pathCopy, ":"); pathNode-gt;str = token; pathNode-gt;next = head; head = pathNode; while (token != NULL) { token = strtok(NULL, ":"); if (token == NULL) break; pathNode = malloc(sizeof(Node)); if (pathNode == NULL) return (NULL); pathNode-gt;str = token; pathNode-gt;next = head; head = pathNode; } return (head); } path = "/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin" char *pathCopy = NULL; pathDirs = _getdir(path, pathCopy);
Мое замешательство начинается pathNode = malloc(sizeof(Node))
и заканчивается на return (head);
Во-первых, я не понимаю, почему эта функция-выделение размер переменной типа под названием «узел», хранить эту информацию в переменной под названием патчнодов, и только после этого будет if statement
выполнить в случае патчнодов имеет нулевое значение, я имею в виду, как это может быть возможно, если «узел» тип переменной фиксируется (по крайней мере первоначально)?
Во-вторых, я понимаю, что strtok
функция используется для разделения строки с помощью разделителя, что в данном случае так и есть :
. Я также знаю, что оператор стрелки -gt;
используется для доступа к элементам в структурах.
Но затем следующие строки кода являются pathNode-gt;str = token;
и pathNode-gt;next = head;
являются чем-то вроде перевернутого объявления переменных, что делает синтаксис для меня просто странным, и эти переменные str
и next
не были объявлены как в случае с указателями, разве это не необходимо?
И, наконец, есть цикл while, который, я думаю, будет выполняться до тех пор, пока он не найдет
элемент в конце pathCopy
строки. Тем не менее, снова есть использование pathNode = malloc(sizeof(Node));
pathNode-gt;str = token;
и pathNode-gt;next = head;
, возвращающее меня к предыдущей путанице…
Комментарии:
1. Для первого вопроса malloc может возвращать значение NULL, так что это допустимая проверка.
Ответ №1:
Ваш вопрос, похоже, касается односвязного списка. Эта функция вставляет узлы в односвязный список.
Он выделяет pathNode
, назначает его как head
.
strtok
разбивает строки на токены, первый токен предназначен для head
.
Если следующий токен успешен, он выделяет другой узел, этот узел становится новым head
. pathNode-gt;next = head
указывает, что следующим элементом является head. Затем он назначает head = pathNode
и продолжает цикл.
«pathNode-это нулевое значение, я имею в виду, как это может быть возможно, если переменная типа «Узел» фиксирована (по крайней мере, изначально)»
pathNode
может быть NULL
, если памяти не хватает и malloc
выходит из строя.
«Однако снова используется pathNode = malloc(sizeof(узел));»
malloc
В начале head
и malloc
внутри цикла есть a для следующих узлов.
Кроме того, есть пара проблем. Функция используется pathCopy
для дублирования исходной строки. Это правильный подход, потому strtok
что изменит его источник. Но pathCopy
в конце концов его следует освободить. Бесполезно возвращать его вызывающему абоненту.
В целом эта функция сложнее, чем должна быть. Вот более простой пример:
Node* create_node(const char* str) { Node* node = malloc(sizeof(Node)); if (!node) return NULL; node-gt;str = strdup(str); node-gt;next = NULL; return node; } Node* mygetdir(const char* source) { if (!source) return NULL; char *path = strdup(source); if (!path) return NULL; Node* head = NULL; char* token = strtok(path, ":"); while (token) { Node* save = head; head = create_node(token); if (!head) return NULL; head-gt;next = save; token = strtok(NULL, ":"); } free(path); return head; }
Вы можете распечатать его следующим образом. Вы должны освободить связанный список в конце.
int main(void) { Node* head = mygetdir("/sbin1:/usr/sbin2:/bin3:/usr/bin4:/usr/local/bin5"); Node* node = head; while (node) { printf("ID = %sn", node-gt;str); node = node-gt;next; } node = head; while (node) { Node* next = node-gt;next; // ******* EDIT // don't call `free(node-gt;str)` if using your own version // because in your own version node-gt;str is just a pointer to `pathCopy` free(node-gt;str); free(node); node = next; } return 0; }
Комментарии:
1. Ух ты, спасибо тебе, сэр! Ваше объяснение было очень полезным, думаю, теперь я его понял!. Кстати, когда вы говорите, что
pathCopy
это должно быть освобождено в конце, не могу ли я просто ввестиfree(pathCopy)
сразу послеreturn(head)
этого исходный код, который я опубликовал, ничего больше не меняя? @Бармак Шемирани2. Я отредактировал ответ. Да, вы можете позвонить
free(pathCopy)
в самом конце , но не звонитеfree(node-gt;str);
, как я сделал в своей версии. Кстати, не используйте подчеркивание_
в качестве префикса, это зарезервировано для библиотечной функции.my_get_dir
все в порядке, но нет_getdir
. Кроме того, для этого вам действительно не нужен связанный список, вы можете просто выделить массив строк, это будет менее подвержено ошибкам. Я не уверен, каковы ваши требования.