如何在C中删除链表中的某个元素

如何在C中删除链表中的某个元素,c,C,我正在尝试删除链接列表中的某个元素 当我在屏幕上打印所有元素时,它们有一定的顺序(参见案例2)。在案例7中,我可以根据顺序选择要删除的元素 案例7中的代码不起作用。这是我的密码: #include "stdio.h" #include "ctype.h" #include "stdlib.h" #include "math.h" #include "string.h" #define SIZE 100 double dummy = sin(0.0); struct sputnik { ch

我正在尝试删除链接列表中的某个元素

当我在屏幕上打印所有元素时,它们有一定的顺序(参见案例2)。在案例7中,我可以根据顺序选择要删除的元素

案例7中的代码不起作用。这是我的密码:

#include "stdio.h"
#include "ctype.h"
#include "stdlib.h"
#include "math.h"
#include "string.h"
#define SIZE 100
double dummy = sin(0.0);

struct sputnik {
  char nazvanie[30];
  char nazvanie_main[30];

  int year;
  float d;
  int period;
  struct sputnik *next;
};

int main(void) {
  char choice;
  int punkt;
  int i, count = 0;
  struct sputnik *head = NULL;
  struct sputnik *prev, *current;
  int res, kolvo, j, number;
  struct sputnik a[SIZE];
  system("clear");

  while (1) {
    printf("Menu: ");
    printf("1- Create table with sputniks  \n 2-All sputniks \n 3-Write      4-Read \n 5-Add \n 6-Change \n 7-Delete \n 8-Exit \n");
    scanf("%d", &punkt);

    while (getchar()!='\n') 
      continue;

    switch(punkt) {
      case 1:
        while (1) {
          printf("Create new table? (N-new; O-old)");
          choice = toupper(getchar());
          if (choice == 'N') {
            count = 0;
            prev = head;
            while (prev != NULL) {
              current = prev->next;
              free(prev);
              prev = current;
            }
            head = NULL;
          }
          if (choice != 'N' && choice != 'O') {
            while (getchar() != '\n')
              continue;
            continue;
          }
          while (getchar()!='\n')
            continue;
          break;
        }
        for ( ; ; count++) {
          current = (struct sputnik *)malloc(sizeof(struct sputnik));
          if (head == NULL) {
            head = current;
          } else {
            prev->next = current;
          }
          current->next = NULL;
          printf("Name %d sputnika:", count + 1);
          gets(current->nazvanie);
          printf("Name planet:");
          gets(current->nazvanie_main);
          printf("Open year:");
          scanf("%d", &current->year);
          while (getchar() != '\n')
            continue;
          printf("Diameter:");
          scanf("%f", &current->d);
          while (getchar() != '\n')
            continue;
          printf("Period:");
          scanf("%d", &current->period);
          while (getchar() != '\n')
            continue;
          prev = current;
          printf("Finish vvod?: y/n: \n");
          if (toupper(getchar()) == 'Y') {
            count++;
            break;
          } else {
            while (getchar() != '\n')
              continue;
            continue;
          };
        }
        break;
      case 2:
        if (head == NULL) {
          printf ("No data \n");
        } else {
          printf(" Sputniks: \n");
        }
        current = head;
        i = 0;
        while (current != NULL) {
          printf("%d sputnik - %s planet %s god %d diametr %4.3f period %d\n", ++i, current->nazvanie, current->nazvanie_main, current->year, current->d, current->period);
          current = current->next;
        }
        break;
      case 3:
        break;
      case 4:
        break;
      case 5:
        break;
      case 6:
        break;
      case 7:
        int nummer;
        printf("Number for sputnik to delete:\n");
        scanf("%d", &nummer);
        while (getchar() != '\n')
          continue;
        current = head;
        i = 0;
        while (current != NULL) {
          if (i == nummer - 1) {
            prev = current;
            free(current);
            current = prev->next;
          } else {
            current = current->next;
            i = i + 1;
          }
        }
        break;
      case 8:
        prev = head;
        while (prev != NULL) {
          current = prev->next;
          free(prev);
          prev = current;
        }
        printf("Finish \n");
        return 0;
        break;
      default:
        printf ("Dont right choose!\n");
        break;
    }
  } 
  return 0; 
}

您的删除逻辑不正确

struct sputnik *prev = NULL, *current = NULL;
current = head;

if (number == 1) {
  head = head->next;
  free(current);
  current = NULL;
  return;
}

while (i < (number - 1)) {
  current = current->next;
  i++;
} 

prev = current;
current = current->next;

if (current->next == NULL) {
  free(current);
  current = NULL;
  prev->next = NULL;
  return;
} else {
  prev->next = current->next;
  free(current);
  current = NULL;
  return;
}
struct-sputnik*prev=NULL,*current=NULL;
电流=水头;
如果(数字==1){
头部=头部->下一步;
自由(电流);
电流=零;
返回;
}
而(一)(一){
当前=当前->下一步;
i++;
} 
prev=当前值;
当前=当前->下一步;
如果(当前->下一步==NULL){
自由(电流);
电流=零;
prev->next=NULL;
返回;
}否则{
上一个->下一个=当前->下一个;
自由(电流);
电流=零;
返回;
}

删除列表项时,应正确重新链接列表。并且也不要尝试从已删除的元素中读取(
prev=current;current=prev->next;free(prev);

因此,您的
案例7
可能类似于以下代码:

        int nummer;
        printf(" Number for sputnik to delete:\n");
        scanf ("%d",&nummer);
        while(getchar()!='\n') continue;
        current=head; prev=NULL;
        i=0;
        while(current!=NULL) {
          if (i==nummer-1){
              if (prev==NULL) {
                // move head pointer if first element should be removed
                head=current->next;
              } else {
                prev->next = current->next; // relink list items
              }
              free(current); // free allocated memory
              break;
          }
          else 
          {
            prev=current; current=current->next; i=i+1; // go to next item
          }
        }
        break;

您当前的算法已完全崩溃

  • 永远不要将删除节点之前的节点与以下节点链接
  • 您的算法根本不考虑删除头部节点
  • 即使在删除目标后,您也不必遍历列表的其余部分
简言之,这需要重新进行

有很多方法可以做到这一点,许多方法至少使用一对指针(一个prev和一个current)并将它们按列表的顺序排列,这似乎就是您尝试过的,以及几个答案试图解决的问题。不同的是,我将向您展示如何使用一个指向指针的指针来实现这一点。这样做的另一个好处是不需要特殊情况下的头指针检查

包括基本的错误检查,它是这样做的:

int nummer;
printf("Number for sputnik to delete:\n");
if (scanf("%d", &nummer) == 1 && nummer > 0)
{
    struct sputnik** pp = &head;
    while (--nummer && *pp)
        pp = &(*pp)->next;;
    if (*pp)
    {
        struct sputnik *p = *pp;
        *pp = p->next;
        free(p);
    }
}
while (getchar() != '\n')
    continue;
这将遍历链表中的实际指针;不仅仅是他们的价值观。因此,当我们到达指向我们要删除的节点的指针时,我们使用列表中的指针(如果请求是针对节点(1)的,则包括头指针)来执行此操作。这允许我们将该指针更新到其后续地址,然后删除节点并完成

当涉及到单链表操作时,指针到指针算法通常提供令人惊讶的优雅解决方案和通常简洁的代码。盯着它看一会儿,也许将它与不同的二/三指针方法进行比较


祝你好运。

你需要在else块中设置
prev=current
(在更新current之前),而不是在if块中。在if中,您将设置
prev->next=current->next
,然后设置
free(current)
。您是否理解编译器正在(或应该)给您的警告:“get”是不推荐的消息?虽然与您的逻辑问题无关,但使用
get
(除非这是您的系统上唯一可用的东西-几乎从不适用)它为缓冲区溢出创建了大量的安全漏洞。如果应该删除head元素,那么head呢?@Ziumin在某个位置删除已编辑的代码应该是精细的、简短的、切中要害的、防弹的。从一个有学问的人手里多抓几块鹅卵石总是好的。