c - 简单链表实现 C 中的奇怪内存问题

标签 c memory data-structures singly-linked-list

我正在编写一个简单链接列表,它具有由 {name,price} 组成的元素结构,并且在我正在实现的一些函数中呈现出奇怪的行为。这些功能是:

  1. PopFront(删除列表的最后一个元素)
  2. PopByIndex(给定条目索引,它将删除该位置上的元素)

到底发生了什么?好吧,这些函数确实删除了它们应该删除的元素,但它们以某种方式改变了列表中另一个元素的价格值😕。

示例:

使用前删除功能

Name:        A  Price: 1.00
Name:        B  Price: 2.00
Name:        C  Price: 3.00
Name:        D  Price: 4.00
    --------
     |Menu|
    --------
(1) Add Element in Front
(2) Add Element in Back
(3) Add Element in Position
(4) Remove Element from Front
(5) Remove Element from Back
(6) Remove Element by Position
(7) Print List
(8) Calculate Itens Sum
(0) Exit Program

删除 D 元素后,A 的价格为 0

Name:        A  Price: 0.00
Name:        B  Price: 2.00
Name:        C  Price: 3.00
    --------
     |Menu|
    --------
(1) Add Element in Front
(2) Add Element in Back
(3) Add Element in Position
(4) Remove Element from Front
(5) Remove Element from Back
(6) Remove Element by Position
(7) Print List
(8) Calculate Itens Sum
(0) Exit Program

我用gdb查看了元素被修改的具体时刻,发现是当我调用free()来释放被删除元素地址的内存时

最小可重现示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Node Node;
typedef struct List List;

struct Node {
    char name[100];
    float price;
    int code;
    struct Node *prox; 
};

struct List{
    struct Node *head;
    int size;
};

Node* InstantiateNode() {
    Node *new_node = malloc(sizeof new_node);
    new_node->prox = NULL;
    return new_node;
}

void InitNode(Node *node, char *name, float price) {
    strcpy(node->name, name);
    node->price = price;
}

void PrintNode(Node node){
    printf("Name: %8s  Price: %.2f\n", node.name, node.price);
}

int EmptyList(List list) {
    return list.size == 0 ? 1 : 0;
}

List *InstantiateList(void) {
    List *new_list = malloc(sizeof new_list);
    new_list->head = NULL;
    new_list->size = 0;
    return new_list;
}

void InitList(List *list, Node *new_node) {
    new_node->prox = list->head;
    list->head = new_node;
    list->size++;
}

void PushFront(List *list, Node *new_node) {
    if (EmptyList(*list)) {
        InitList(list, new_node);
        return;
    }
    Node *tracker = list->head;
    while (tracker->prox != NULL)
        tracker = tracker->prox;
    tracker->prox = new_node;
    list->size++;
}

void PushBack(List *list, Node *new_node) {
        InitList(list, new_node);
}

Node *TrackListbyIndex(List lista, int index) {
    if (index > lista.size) {
        printf("Unreachable List index \n"); // Warning
        return NULL;
    }
    int cont = 0;
    Node *aux = lista.head;
    while (cont != index) {
        aux = aux->prox;
        cont++;
    }
    return aux;
}

void PushByIndex(List *list, Node *new_node, int index) {
    if (index == 0) {
        PushBack(list, new_node);
        return;
    }
    Node *aux = TrackListbyIndex(*list, index - 1);
    Node *aux2 = aux->prox;
    if (aux) {
        new_node->prox = aux->prox;
        aux->prox = new_node;
        list->size++;
    }
}

void PopFront(List *list) {
    if (EmptyList(*list))
        return;
    Node* aux = list->head;
    Node* tracker, *tracker_next;
    tracker = list->head;
    if (tracker->prox != NULL) {
        tracker_next = tracker->prox;
        while (tracker_next->prox != NULL) {
            tracker = tracker_next;
            tracker_next = tracker_next->prox;
        }    
        tracker->prox = NULL;
        aux = tracker_next;
    }
    if (aux == list->head) {
        list->head = NULL;
    }
    free(aux);
    list->size--;
}

void PopBack(List* list){
    if(EmptyList(*list))
        return;
    Node* aux = list->head;
    list->head = list->head->prox;
    free(aux);
    list->size--;   
}
void PopByIndex (List *list, int index) {
    if (index == 0) {
        PopBack(list);
        return;
    }
    //if (index + 1 == list->size) {
    //    PopFront(list);
    //    return;
    //}
    Node *aux, *aux_next;
    aux = TrackListbyIndex(*list, index - 1);
    if (aux) {
        aux_next = aux->prox;
        aux->prox = aux_next->prox;
        free(aux_next);
        list->size--;
    }
}

void PrintList(List list) {
    Node *tracker = list.head;
    while (tracker != NULL) {
        PrintNode(*tracker);
        tracker = tracker->prox;
    }
}

void Menu(void);
void HandleMenu(int);

int main(void) {
    int option;
    for (;;) {
        Menu();
        printf("Type your choosen:");
        scanf("%d", &option);
        system("clear");
        HandleMenu(option);
    }
    return 0;
}

void Menu(void) {
    printf("\t--------\n");
    printf("\t |Menu|\n");
    printf("\t--------\n");
    printf("(1) Add Element in Front\n");
    printf("(2) Add Element in Back\n");
    printf("(3) Add Element in Position\n");
    printf("(4) Remove Element from Front\n");
    printf("(5) Remove Element from Back\n");
    printf("(6) Remove Element by Position\n");
    printf("(7) Print List\n");
    printf("(8) Calculate Itens Sum\n");
    printf("(0) Exit Program\n");
}

void HandleMenu(int option) {
    static List *market_list = NULL;
    Node* new_node = NULL;
    char node_name[100];
    float node_price;
    int index;
    if (market_list == NULL)
       market_list = InstantiateList();
    switch (option) {
      case 0:
        exit(1);
        break;
      case 1:
        new_node = InstantiateNode();
        printf("Type the product's name: ");
        scanf(" %[^\n]", node_name);
        printf("Type the product's price: ");
        scanf("%f", &node_price);
        InitNode(new_node, node_name, node_price);
        PushFront(market_list, new_node);
        printf("Item Added\n");
        break;
      case 2:
        new_node = InstantiateNode();
        printf("Type the product's name: ");
        scanf(" %[^\n]", node_name);
        printf("Type the product's price: ");
        scanf("%f", &node_price);
        InitNode(new_node, node_name, node_price);
        PushBack(market_list, new_node);
        printf("Item Added\n");
        break;
      case 3:
        new_node = InstantiateNode();
        printf("Type the product's name: ");
        scanf(" %[^\n]", node_name);
        printf("Type the product's price: ");
        scanf("%f", &node_price);
        InitNode(new_node, node_name, node_price);
        printf("Type Index: ");
        scanf("%d", &index);
        PushByIndex(market_list, new_node, index-1);
        printf("Item Added\n");
        break;
      case 4:
        PopFront(market_list);
        break;
      case 5:
        PopBack(market_list);
        break;
      case 6:
        printf("Type Index: ");
        scanf("%d", &index);
        PopByIndex(market_list, index-1);
        break;
      case 7:
        PrintList(*market_list);
        break;
    }
}

最佳答案

  1. InstantiateNode()Node * 分配空间,但您想要为 Node 分配空间:
Node *new_node = malloc(sizeof *new_node);
  • InstantiateList()List * 分配空间,但您想要为 List 分配空间:
  • List *new_list = malloc(sizeof *new_list);
    

    经过这两项更改后,这是删除后的输出:

    Name:        A  Price: 1.00
    Name:        B  Price: 2.00
    Name:        C  Price: 3.00
    

    关于c - 简单链表实现 C 中的奇怪内存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75710158/

    相关文章:

    c - 将字符数组中的字符放入字符串中,直到找到特定字符

    C 程序使用 for 循环递增变量

    c - 实现系统调用而不显式调用它们

    c++ - 制表符分隔的文件数据要存储到数据结构中

    c - 在c中使用指针创建数组

    ios - 苹果 map 消耗太多内存

    java - 如何在 android studio 的 If 语句中写入 "if button clicked"?

    c++ - 为较大的数组分配对齐的内存

    algorithm - 数据结构排序

    c - 结构中数据类型的顺序