当我在控制台上按顺序插入节点时,将被插入
如何确保我照顾所有边界条件?例如,如果用户输入的位置大于列表的大小该怎么办?另外,当我尝试在节点之后插入时会遇到分段错误,但在节点之前可以正常工作。这是一张有助于更好地解释我的问题的照片
另外,当我尝试在节点之后插入时会遇到分段错误,但在节点之前可以正常工作。
#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()
的任何返回值,因此您的函数原型应该只是void insert (int x, int pos)
。虽然应该避免使用指向列表的全局指针,但出于此有限示例的目的,这很好。知道您的列表通常应该在所需的范围内声明,并且应该将指向列表开头的指针(或指向指针的指针)作为参数传递,以使列表可用于对其进行操作的任何函数,而不是对其进行操作的函数全球化。
将各个部分放在一起,您的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
内存使用/错误检查
在您编写的任何可以动态分配内存的代码中,对于任何分配的内存块,您都有2个责任:(1)始终保留指向该内存块起始地址的指针,因此,(2)在不分配该内存块时可以将其释放需要更长的时间。
必须使用内存错误检查程序来确保您不尝试访问内存或不在分配的块的边界之外/之外写,尝试读取或基于未初始化的值进行条件跳转,最后确认您可以释放已分配的所有内存。
对于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/