c - 从列表中删除节点时出现段错误 (C)

标签 c list segmentation-fault

任务是让程序从文件写入读取对象,然后从中创建一个列表,然后删除Node-s 带有奇数 int-s。删除是通过一些嵌套函数完成的。问题是,某处存在段错误。当然,我通过调试器运行了这个,但我们既没有被教导机器代码/汇编语言,也没有被教导如何完全使用调试器。

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

typedef struct smallNode {
    int val;
    char str[10];
}smallNode;

typedef struct Node {
    smallNode smallNode;
    struct Node *next;
}Node;

Node *head = NULL;

Node *getLast(Node *head);
void queue(Node **head, Node *object);
void print(Node *head);
int countNodes(Node *head);
void check(Node *head);
Node *getNth(Node *head, int n);
void delNth(Node **head, int n);
void popHead(Node **head);
void delOdds(Node *head);


int main(void) {

    FILE *fp;
    if ((fp = fopen("suka.blyad", "wb")) == NULL) {
        return 69;
    }
    smallNode array[5];
    int j;
    for (j = 0; j < 5; j++) {
        array[j].val = j;
    }
    strcpy(array[0].str, "zero");
    strcpy(array[1].str, "one");
    strcpy(array[2].str, "two");
    strcpy(array[3].str, "three");
    strcpy(array[4].str, "four");
    int i;
    smallNode *object0 = (smallNode *)malloc(sizeof(smallNode));
    for (i = 0; i <5; i++) {
        *object0 = array[i];
        if (fwrite(object0, sizeof(smallNode), 1, fp) != 1) {
            puts("IO error.");
            exit(-3);
        }
    }
    fclose(fp);
    if ((fp = fopen("suka.blyad", "rb")) == NULL) {
        return 4;
    }
    Node * object = (Node *)malloc(sizeof(Node));
    while (1) {
        if (fread(object0, sizeof(smallNode), 1, fp) != 1) {
            break;
        }
        object->smallNode = *object0;
        queue(&head, object);
    }
    print(head);
    puts("After deleting odds: ");
    delOdds(head);
    print(head);
    return 0;
}

 void check(Node *head){ //function to check if the list exists 
    if(head == NULL){
        puts("NaL");
        exit(-1);
     }
 }

Node *getLast(Node *head) {
    if (head == NULL) {
        return NULL;
    }
    while (head->next) {
        head = head->next;
    }
    return head;
}

void queue(Node **head, Node *object) {
    Node *tmp = (Node *)malloc(sizeof(Node));
    Node *last = getLast((*head));
    *tmp = *object;
    tmp->next = NULL;
    if (last != NULL) {
        last->next = tmp;
    }
    else {
        *(head) = tmp;;
    }
}
void print(Node *head) {
    if (head == NULL) {
        puts("NaL");
        exit(-4);
    }
    int c = 0;
    while (1) {
        printf("Node: %d.\n", ++c);
        puts("-----------------------------------------");
        printf("|Int: %6d    |    String: %7s  %3c\n", head->smallNode.val, head->smallNode.str, '|');
        puts("-----------------------------------------");
        if (head->next!=NULL) {
            head = head->next;
        }
        else {
            break;
        }
    }
}

int countNodes(Node *head){  //use this function to check out of bounds
    check(head);
    int count = 0;
    while(1){
        count++;
        if(head->next){
            head = head->next;
        }
        else{
            return count; 
        }
    }
}

Node *getNth(Node *head, int n){ 
    check(head);
    if(n > countNodes(head) 
       || n < 0){
        puts("Out of bounds.");
        exit(-5);
    }
    int i; 
    for(i = 0; i < n-1; i++){
        head = head->next;
    }
    return head;
}

void delNth(Node **head, int n){  //cant delete the first node 
    check((*head));
    Node *prev = getNth((*head), n-1);
    Node *elm = prev->next;
    prev->next = elm -> next;
    free(elm);
}

void popHead(Node **head){ //can only delete the first node, called only if n == 1
    check((*head));
    Node *elm = (*head);
    (*head) = (*head)->next;
    free(elm);
}

void delOdds(Node *head){ //function to go throught the list, check for odds and call the functions doing the deletion
    check(head);
    int n = 0;
    while(1){
        ++n;
        if(head->smallNode.val % 2){
            if(n == 1){
                popHead(&head);
            }
            else{
                delNth(&head, n);
            }
        }
        if(head->next){
            head = head->next;
        }
        else{
            print(head);
            break;
        }
    }
}

我包含了整个代码,而不仅仅是有问题的函数,以便程序可以运行。 我认为我创建列表的方式可能是非正统的,因此我将简要解释它,这样您就不必费心去弄清楚:
使用了 2 种类型的对象。 smallNode 没有 next 指针,但它是从文件写入和读取的对象。它对应于object0

Node 是构成列表的对象,它也是传递给创建列表的 queue 函数的对象。

最佳答案

出现崩溃是因为您在每次迭代中递增本地 Head head = head->next; 并且将相同的本地 Head 传递给 delNth()使用getNth()函数获取第N个节点。由于您的 getNth() 函数计算并返回列表开头的第 N 个节点,因此您最终会指向无效地址。

如果您想继续采用自己的方法,则需要进行以下更改。

  1. 维护本地指针以迭代列表。
  2. delNth(Node **head, int n) 更改为 delNth(Node *head, int n) 以避免 更改头节点。
  3. 删除时传递实际的头。
  4. 删除后,减少 n,以便节点数和 n 保持不变。

以下是修改后的代码。

void delOdds(Node *head){ 
        check(head);
        Node *localHead = head;
        int n = 0;
        while(1){
       printf("processing node=%d n=%d\n", localHead->smallNode.val, n);
            ++n;
            if(localHead->smallNode.val % 2){
                if(n == 1){
                    popHead(&head);
                }
                else{
                    delNth(head, n);
                    n--;
                }
            }
            if(localHead->next){
                localHead = localHead->next;
            }
            else{
                print(localHead);
                break;
            }
        }
    }

我建议您采用以下方法。

void delOdds(Node **head){
        check(*head);
        Node *prev = NULL;
        Node *cur = *head;
        int n = 0;
        while(cur){
                if((cur)->smallNode.val % 2){
                        if (cur == *head)
                        {
                                *head = (*head)->next;
                                free(cur);
                                cur = *head;
                        }
                        else
                        {
                                (prev)->next = (cur)->next;
                                free(cur);
                                cur = NULL;
                                (cur)=(prev)->next;
                        }
                }
                else{
                        prev = cur;
                        (cur)=(cur)->next;
                }
        }
}

关于c - 从列表中删除节点时出现段错误 (C),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51800249/

相关文章:

python - 将字符串转换为嵌套元组 : Python

c - 进入main之前的段错误

c - 段错误检查月份

c - C中如何确定unsigned char的范围?

c - 定义 C 函数数组

c - __func__ 扩展为标准化的文本吗?

list - 查找文本中前 5 个单词长度

c# - 无效的表达式项 '>'

ios - sprintf上的SIGABRT

objective-c - 在预处理器宏中包装内联 C 函数