Как должна работать эта функция, которая создает связанный список для любой строки среды?

#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 . Кроме того, для этого вам действительно не нужен связанный список, вы можете просто выделить массив строк, это будет менее подвержено ошибкам. Я не уверен, каковы ваши требования.