gpt4 book ai didi

c - 将节点插入单链表时如何避免段错误?

转载 作者:行者123 更新时间:2023-11-30 16:09:02 26 4
gpt4 key购买 nike

当我在控制台上按顺序插入节点时,节点就会被插入
如何确保考虑到所有边界条件?例如,如果用户输入的位置大于列表的大小怎么办?另外,当我尝试在节点之后插入时出现段错误,但在节点之前却工作得很好。这是一张图片,可以帮助更好地解释我的问题

此外,当我尝试在节点之后插入时,我遇到了段错误,但在节点之前它工作得很好。

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

struct Node
{
int data;
struct Node *next;
};

struct Node *head = NULL;

struct Node *insert(int x,int pos)
{
if(head == NULL)
{
struct Node *temp = (struct Node*)malloc(sizeof(struct Node));
temp->data = x;
temp->next = head;
head = temp;
return head;
}
else
{
int len = 0;
struct Node *temp = head;
while(temp!=NULL)
{
++len;
temp = temp->next;
}

if(pos == 1)
{
struct Node *temp = (struct Node*)malloc(sizeof(struct Node));
temp->data = x;
temp->next = head;
head = temp;
return head;
}
else
{
struct Node *temp = (struct Node*)malloc(sizeof(struct Node));
temp->data = x;
temp->next = NULL;
struct Node *temp1 = head;
for(int i = 2; i<pos; i++)
{
temp1 = temp1->next;
}
temp->next = temp1->next;
temp1->next= temp;
}

}

}
void print()
{
struct Node *temp = head;
while(temp!=NULL)
{
printf("%d ",temp->data);
temp = temp->next;
}
printf("\n");
}
int main()
{
int n,i,x,pos;
printf("How many elements?\n");
scanf("%d",&n);
for(i = 0; i<n; i++)
{
printf("enter the value and the position: \n");
scanf("%d %d",&x,&pos);
insert(x,pos);
print();
}
printf("Linked list is: \n");
print();
}

输出1

How many elements?
3
enter the value and the position:
3 2
List is: 3
enter the value and the position:
4 3
Segmentation fault (core dumped)

输出2

How many elements?
3
enter the value and the position:
3 2
List is: 3
enter the value and the position:
4 1
List is: 4 3
enter the value and the position:
5 3
List is: 4 3 5
Linked list is:
4 3 5

最佳答案

您使插入件变得比需要的更加困难。您只需使用 2 个条件进行迭代 (1) pos 次或更少,以及 (2) 当下一个指针不为 NULL 时。您可以通过使用下一个节点的地址指向下一个节点的指针进行迭代,从而大大简化插入操作。您使用地址维护当前节点,并且指针始终指向下一个节点。当您迭代 pos 次或您的下一个指针为 NULL 时,您将插入节点。请参阅Linus on Understand Pointers

此外,您没有使用来自 insert() 的任何返回,因此您的函数原型(prototype)应该只是 void insert (int x, int位置)。虽然您应该避免使用指向列表的全局指针,但出于此有限示例的目的,这很好。知道你的列表通常应该在需要的范围内声明,并且应该将指向列表开头的指针(或指向指针的指针)作为参数传递,以使列表可用于对其进行操作的任何函数而不是它全局化。

将各个部分放在一起,您的 insert() 函数简化为:

void insert (int x, int pos)
{
struct Node **ppn = &head, /* pointer to pointer to node */
*pn = head, /* pointer to node */
*node = malloc (sizeof *node); /* allocate for new node */

if (!node) { /* validate allocation */
perror ("malloc-node");
exit (EXIT_FAILURE);
}
node->data = x; /* initialize members values */
node->next = NULL;

while (pos-- && pn) { /* iterate pos times && while pn != NULL */
ppn = &pn->next;
pn = pn->next;
}

node->next = pn; /* set next to pointer to node */
*ppn = node; /* set node at address to node */
}

将其添加到示例的其余部分,完整的示例将是:

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

struct Node {
int data;
struct Node *next;
};

struct Node *head = NULL;

void insert (int x, int pos)
{
struct Node **ppn = &head, /* pointer to pointer to node */
*pn = head, /* pointer to node */
*node = malloc (sizeof *node); /* allocate for new node */

if (!node) { /* validate allocation */
perror ("malloc-node");
exit (EXIT_FAILURE);
}
node->data = x; /* initialize members values */
node->next = NULL;

while (pos-- && pn) { /* iterate pos times && while pn != NULL */
ppn = &pn->next;
pn = pn->next;
}

node->next = pn; /* set next to pointer to node */
*ppn = node; /* set node at address to node */
}

/** print all nodes in list */
void print (void)
{
if (!head) {
puts ("list-empty");
return;
}
for (struct Node *n = head; n; n = n->next)
printf (" %d", n->data);
putchar ('\n');
}

/** delete all nodes in list */
void del_list (void)
{
struct Node *n = head;
while (n) {
struct Node *victim = n;
n = n->next;
free (victim);
}
}

int main()
{
int n,i,x,pos;

printf ("How many elements?\n");
if (scanf ("%d",&n) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}

for (i = 0; i < n; i++)
{
printf ("enter the value and the position: \n");
if(scanf("%d %d",&x, &pos) == 2) {
insert (x, pos);
fputs ("list is: ", stdout);
print();
}
}

puts ("\nLinked list is:");
print();
del_list(); /* free all memory allocated to list */
}

(注意:del_list() 函数已添加到 free() 与列表关联的内存。)

示例使用/输出

继续您的 SegFaulting 示例,您现在可以完成插入,例如:

$ ./bin/llatpos
How many elements?
3
enter the value and the position:
3 2
list is: 3
enter the value and the position:
4 3
list is: 3 4
enter the value and the position:
1 0
list is: 1 3 4

Linked list is:
1 3 4

内存使用/错误检查

在您编写的动态分配内存的任何代码中,对于分配的任何内存块,您都有两个责任:(1) 始终保留指向起始地址的指针内存块,因此,(2) 当不再需要它时可以释放

您必须使用内存错误检查程序来确保您不会尝试访问内存或在分配的 block 的范围之外进行写入,尝试读取或基于未初始化的值进行条件跳转,最后,确认您释放了已分配的所有内存。

对于 Linux,valgrind 是正常选择。每个平台都有类似的内存检查器。它们使用起来都很简单,只需通过它运行您的程序即可。

$ valgrind ./bin/llatpos
==16615== Memcheck, a memory error detector
==16615== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16615== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==16615== Command: ./bin/llatpos
==16615==
How many elements?
3
enter the value and the position:
3 2
list is: 3
enter the value and the position:
4 3
list is: 3 4
enter the value and the position:
1 0
list is: 1 3 4

Linked list is:
1 3 4
==16615==
==16615== HEAP SUMMARY:
==16615== in use at exit: 0 bytes in 0 blocks
==16615== total heap usage: 5 allocs, 5 frees, 2,096 bytes allocated
==16615==
==16615== All heap blocks were freed -- no leaks are possible
==16615==
==16615== For counts of detected and suppressed errors, rerun with: -v
==16615== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放分配的所有内存并且不存在内存错误。

仔细检查一下,如果您还有其他问题,请告诉我。

关于c - 将节点插入单链表时如何避免段错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59223994/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com