Пожалуйста, посмотрите полный код ниже.
У меня есть исходный массив с именем arr.
Я использую связанный список для хранения некоторых индексов с помощью функции append. После получения индексов я сохраняю их в связанном списке и использую clearList для изменения соответствующих значений на 0 (в этом примере arr [2] и arr [4]).
Наконец, я освобождаю память, вызывая freeList, так как со связанным списком я закончил.
Однако, чтобы иметь возможность делать одно и то же снова и снова, мне нужно устанавливать для head значение NULL всякий раз, когда я вызываю freeList. Но я не могу. Есть идеи, как это решить?
Спасибо.
#include <stdio.h>
#include "gurobi_c.h"
#include <stdlib.h>
//Gurobi variables
GRBenv *env = NULL;
GRBmodel *model = NULL;
//Gurobi variables
struct Node
{
int data;
struct Node *next;
struct Node *end;
};
void append(struct Node** head_ref, int new_data)
{
struct Node *last = *head_ref;
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = NULL;
new_node->end = new_node;
if (*head_ref == NULL)
{
*head_ref = new_node;
//printf(" ..Init Append %d\n",new_data);
return;
}
last = (*head_ref)->end;
last->next = new_node;
(*head_ref)->end=new_node;
//printf(" ..Append %d\n",new_data);
return;
}
void clearList(struct Node *node, double *arr)
{
int i;
if (node!=NULL)
{
struct Node tmp;
tmp=*(node->end);
while (node != NULL)
{
i=node->data;
arr[i]=0;
//printf(" ..clear %d \n", node->data,(node->end)->data);
node = node->next;
}
}
}
void freeList(struct Node *node)
{
struct Node *tmp,*hd;
hd=node;
while (node != NULL)
{
tmp=node;
node = node->next;
//printf(" ..Free %d \n", tmp->data);
free(tmp);
}
hd=NULL;
}
int main (){
Node *head;
double *arr = (double *) malloc(sizeof(double) * 10);
for(int i=0;i<10;i++)
arr[i]=i;
head=NULL;
printf("Head: %s\n", head);
append(&head,2);
append(&head,4);
clearList(head,arr);
for(int i=0;i<10;i++)
printf("No %d : %.2f\n",i,arr[i]);
freeList(head);
free(arr);
printf("%s", head);
getchar();
return 0;
}
Я не меняю значение головы, оно всегда остается неизменным. Я только добавляю в список новые узлы.
Если вы никогда не измените значение head, это будет NULL, и ваш список будет пуст ... поэтому ваша функция append должна как-то его менять
Правильный. Я делаю это с помощью head_ref в append. Однако в freeList я освобождаю голову, что усложняет ситуацию.
Если вы передадите адрес head в freeList, вы можете установить для него значение NULL в freeList. В противном случае вам придется выполнить head = NULL; после вызова clearList. Вы также можете создать макрос препроцессора, например clearListNull делает и то, и другое.
@Bodo Не могли бы вы объяснить, как именно это сделать? Моя проблема в том, что я знаю, что это можно сделать, манипулируя адресами, но не могу заставить это работать. Я как бы нахожу альтернативное решение, но хотел бы научиться делать это правильно.





Я понял, что можно изменить функцию freeList, чтобы она возвращала значение NULL. См. Обновленный код ниже:
#include <stdio.h>
#include "gurobi_c.h"
#include <stdlib.h>
//Gurobi variables
GRBenv *env = NULL;
GRBmodel *model = NULL;
//Gurobi variables
struct Node
{
int data;
struct Node *next;
struct Node *end;
};
void append(struct Node** head_ref, int new_data)
{
struct Node *last = *head_ref;
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = NULL;
new_node->end = new_node;
if (*head_ref == NULL)
{
*head_ref = new_node;
//printf(" ..Init Append %d\n",new_data);
return;
}
last = (*head_ref)->end;
last->next = new_node;
(*head_ref)->end=new_node;
//printf(" ..Append %d\n",new_data);
return;
}
void clearList(struct Node *node, double *arr)
{
int i;
if (node!=NULL)
{
struct Node tmp;
tmp=*(node->end);
while (node != NULL)
{
i=node->data;
arr[i]=0;
//printf(" ..clear %d \n", node->data,(node->end)->data);
node = node->next;
}
}
}
Node* freeList(struct Node *node)
{
struct Node *tmp;
while (node != NULL)
{
tmp=node;
node = node->next;
printf(" ..Free %d \n", tmp->data);
free(tmp);
}
return NULL;
}
int main (){
Node *head;
double *arr = (double *) malloc(sizeof(double) * 10);
for(int i=0;i<10;i++)
arr[i]=i;
head=NULL;
printf("Head: %s -> null as expected\n", head);
append(&head,2);
append(&head,4);
clearList(head,arr);
for(int i=0;i<10;i++)
printf("No %d : %.2f\n",i,arr[i]);
printf("Head: %s -> Not null as linkedlist is not freed\n", head);
head=freeList(head);
printf("Head: %s -> Again null as expected\n", head);
free(arr);
printf("%s", head);
getchar();
return 0;
}
В сторону: Почему в new_node = (struct Node*) malloc(sizeof(struct Node)) такой ненужный актерский состав? Рассмотрим new_node = malloc(sizeof *new_node). arr = malloc(sizeof *arr * 10); и т. д. Взамен. Легче правильно кодировать, проверять и поддерживать.
Я думаю, что решение idk лучше, потому что ничто не мешает вам вызывать freeList(head); или даже (void)freeList(head); в вашем коде.
Вы уже меняете значение head в своей функции append, поэтому в основном вам нужно сделать то же самое в freeList:
void freeList(struct Node **head_ref)
{
struct Node *tmp,*node;
node=*head_ref;
while (node != NULL)
{
tmp=node;
node = node->next;
//printf(" ..Free %d \n", tmp->data);
free(tmp);
}
*head_ref=NULL;
}
int main (){
/* do stuff */
freeList(&head);
/* do stuff */
}
Для полноты: Другой возможный вариант - использовать макрос оболочки для freeList().
void freeList(struct Node *node)
{
/* ... */
}
#define freeListNull(node) do { \
freeList(node); \
node = NULL; \
} while(0)
int main () {
/* ... */
freeListNull(head);
/* ... */
}
Это решение имеет тот же недостаток, что и версия, возвращающая измененный указатель. Вы можете просто забыть использовать правильный вызов freeListNull(head); и вместо этого вызвать в freeList(head);. Лучшее решение - функция freeList(), которая принимает адрес указателя head, как в ответе idk.
Как изменить значение
headпри добавлении? Может быть, этот способ можно использовать и для удаления ...