c语言 - 分段错误(核心转储)使用链表的队列操作



我用 c 编写了一段代码来使用链表实现队列操作,如插入、删除、查看和显示。

我使用 vscode 来运行和编译我的代码。

#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
int data;
struct Node *next;
}node;
typedef struct Queue{
node *front;
node *rear;
}queue;
queue *q=NULL;
int isempty(queue *);
void create(queue *);
queue *insert(queue *);
queue *delete(queue *);
void display(queue *);
void peek(queue *);
int main(){
int o;
create(q);
do{
printf("nQueue Operations");
printf("n1. Insert");
printf("n2. Delete");
printf("n3. Peek");
printf("n4. Display");
printf("n5. Exit");
printf("nEnter Option : ");
scanf("%d",&o);
switch(o){
case 1:
insert(q);
break;
case 2:
delete(q);
break;
case 3:
peek(q);
break;
case 4:
display(q);
break;
case 5:
break;
default:
printf("Invalid Option");
break;
}
}
while(o!=5);
}
void create(queue *q)
{
q->front=NULL;
q->rear=NULL;
}
queue *insert(queue *q){
node *p;
p=(node *)malloc(sizeof(node));
printf("Enter Data : ");
scanf("%d",&p->data);
if(q->front=NULL){
q->front=p;
q->rear=p;
q->front->next=q->rear->next=NULL;
}
else{
q->rear->next=p;
q->rear=p;
q->rear->next=NULL;
}
return q;
}
int isempty(queue *q){
if(q->front==NULL)
return 1;
else 
return 0;
}
queue *delete(queue *q){
node *p;
int t;
p=q->front;
t=isempty(q);
if(t==1)
printf("Queue Empty");
else{
q->front=q->front->next;
printf("Value Deleted : %d",p->data);
free(p);
}
return q;
}
void peek(queue *q){
int t;
t=isempty(q);
if(t==1)
printf("Queue Empty");
else
printf("Peek:%d",q->front->data);
}
void display(queue *q){
node *p;
p=q->front;
if(p==NULL)
printf("Queue is Empty");
else{
while(p!=q->rear){
printf("%dt",p->data);
p=p->next;
}
printf("%dt",p->data);
}
}

我不明白为什么我在这个问题上遇到分段错误。

这段代码在我的书中,我只是盲目地复制了这段代码,但仍然收到错误。 我也在在线编译器中测试了代码,以确保我的机器没有任何故障,但仍然遇到同样的问题。

如果有人可以帮助我。

对于初学者来说,当函数依赖于文件范围变量时,这是一个坏主意,就像在您的程序中一样,函数依赖于变量q

queue *q=NULL;

其次,您在函数创建中使用空指针。

void create(queue *q)
{
q->front=NULL;
q->rear=NULL;
}

调用未定义的行为。

声明queue类型的指针而不是声明类型为queue的对象没有多大意义。

因此,而不是在文件范围内使用此定义

queue *q=NULL;

用 Main 写要好得多

queue q = { .front = NULL, .rear = NULL };

queue q;
create( &q );

函数isempty可以写得更简单

int isempty( const queue *q )
{
return q->front == NULL;
}

函数insert不应提出任何问题。添加到队列的值应作为参数传递给函数。

它是应该提供值的函数的调用方。

注意内存分配可能会失败,您应该在函数中处理这种情况。否则,该函数可以再次调用未定义的行为。

此外,您在此if语句中使用赋值,而不是使用比较

if(q->front=NULL){

该函数可以按以下方式编写

int insert( queue *q, int data )
{
node *p = malloc( sizeof( *p ) );
int success = p != NULL;
if ( success )
{
p->data = data;
if ( q->front == NULL )
{
q->front = p;
}
else
{
q->rear->next = p;
}
q->rear = p; 
}
return success;
}

在函数delete中,如果队列仅包含一个节点,则不会更新q->rear

同样,该函数不应发出任何消息。它是函数的调用方决定是否输出消息。

函数应按以下方式定义

int delete( queue *q )
{
int success = !isempty( q );
if ( success )
{
node *p = q->front;
q->front = q->front->next;
if ( q->front == NULL ) q->rear = NULL;
free( p );
}
return success;
}      

函数peek应通过引用返回其数据成员data,因为函数的用户可能需要处理该值。

该函数可以如下所示

int peek( queue *q, int *data )
{
int success = !isempty( q );
if ( success )
{
*data = q->front->data;
}
return success;
}

函数display的参数应具有限定符const因为队列在函数内不会更改。

函数可以通过以下方式定义

void display( const queue *q )
{
if ( isempty( q ) )
{
puts( "Queue is Empty" );
}
else
{
for ( const node *p = q->front; p != NULL; p = p->next )
{ 
printf( "%d", p->data );
if ( p != q->rear ) putchar( 't' );
}
putchar( 'n' );
}
}

这是您更新的程序。

#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int data;
struct Node *next;
} node;
typedef struct Queue
{
node *front;
node *rear;
} queue;
int isempty( const queue *q )
{
return q->front == NULL;
}
void create(queue *q)
{
q->front=NULL;
q->rear=NULL;
}
int insert( queue *q, int data )
{
node *p = malloc( sizeof( *p ) );
int success = p != NULL;
if ( success )
{
p->data = data;

if ( q->front == NULL )
{
q->front = p;
}
else
{
q->rear->next = p;
}
q->rear = p; 
}
return success;
}
int delete( queue *q )
{
int success = !isempty( q );
if ( success )
{
node *p = q->front;
q->front = q->front->next;
if ( q->front == NULL ) q->rear = NULL;
free( p );
}
return success;
} 
int peek( queue *q, int *data )
{
int success = !isempty( q );
if ( success )
{
*data = q->front->data;
}
return success;
}
void display( const queue *q )
{
if ( isempty( q ) )
{
puts( "Queue is Empty" );
}
else
{
for ( const node *p = q->front; p != NULL; p = p->next )
{ 
printf( "%d", p->data );
if ( p != q->rear ) putchar( 't' );
}
putchar( 'n' );
}
}
int main( void ) 
{
queue q;
create( &q );

int option = 5;

do
{
printf("nQueue Operations");
printf("n1. Insert");
printf("n2. Delete");
printf("n3. Peek");
printf("n4. Display");
printf("n5. Exit");

printf("nEnter Option : ");

scanf( "%d", &option );

switch( option )
{
case 1:
{
printf( "Enter Data : " );
int data;

if ( scanf( "%d", &data ) == 1 )
{
if ( !insert( &q, data ) )
{
puts( "Error: not enough memory." );
}
}
else
{
puts( "Invalid input." );
}

break;
}
case 2:
{
if ( !delete( &q ) )
{
puts( " Error: queue is empty." );              
}
else
{
puts( "First element of the queue has been deleted." );
}

break;
}

case 3:
{
int data;
if ( peek( &q, &data ) )
{
printf( "The value is %dn", data );
}
else
{
puts( "Error: the queue is empty." );
}

break;
}

case 4:
{
display( &q );
break;
}           

case 5:
{
break;
}

default:
{
puts( "Invalid Option" );
break;
}
}       
} while( option != 5 );
return 0;
}

程序输出可能如下所示

Queue Operations
1. Insert
2. Delete
3. Peek
4. Display
5. Exit
Enter Option : 1
Enter Data : 1
Queue Operations
1. Insert
2. Delete
3. Peek
4. Display
5. Exit
Enter Option : 1
Enter Data : 2
Queue Operations
1. Insert
2. Delete
3. Peek
4. Display
5. Exit
Enter Option : q
Enter Data : 3
Queue Operations
1. Insert
2. Delete
3. Peek
4. Display
5. Exit
Enter Option : 4
1   2   3
Queue Operations
1. Insert
2. Delete
3. Peek
4. Display
5. Exit
Enter Option : 5

请注意,您还需要编写一个函数来清除队列,该队列将释放队列中所有分配的内存。

q没有指向任何东西。 当你在create()中尊重它时,你正在写入随机内存,这通常会导致崩溃。

您应该将 q 定义为类型队列(无指针),并将其地址传递给子函数。

每当指针被取消引用时,都应该在使用之前通过 malloc 为其分配相当数量的内存。因此,在创建链表时,应分配队列指针并将其传递回 main 以供使用。下面附上修改后的队列创建代码以供参考,

queue* create(queue *q)
{
q= (queue*)malloc(sizeof(queue));
q->front=NULL;
q->rear=NULL;
return q;
}

同时更新主中的调用函数。

创建函数需要分配内存,只要您在创建函数中分配内存或传递具有已分配内存的队列(您不能同时执行两个解决方案,则只能使用其中一个)分配内存,第一个是制作有组织代码的首选。

queue* create(queue *q)
{
q= (queue*)malloc(sizeof(queue));
q->front=NULL;
q->rear=NULL;
return q;
}

插入函数中的另一个错误if(q->front=NULL){会使q->front实际分配给null,并会导致分割错误,您应该需要检查==不分配=

if(q->front==NULL){会让它更正确地工作

最新更新