I encounter a problem when I use the function,update(), written by me, supposed that there are three nodes of my linked list, Part number is no.1, no.5, and no.10,when I update information of these parts and input the Part number between the max part number and the min part number of linked list,it work.But it doesn't work when I input a Part number which exceeds the max part number of linked list, and the program even terminates.What is the cause the program terminate?How could I revise it? Following is my code,Thanks for answer.
/* Maintains a parts database (linked list version) */
#include <stdio.h>
#include <stdlib.h>
#include "readline.h"
#define NAME_LEN 25
struct part{
int num;
char name[NAME_LEN 1];
int on_hand;
struct part *next;
};
struct part *inventory = NULL;
int num_parts = 0; //number of parts currently stored//
struct part *find_part(int number);
void insert(void);
void search(void);
void update(void);
void print(void);
/************************************************************************
*main: Prompts the user to enter an operation code, then calls a function
to perform the requested action. Repeats until the user enters the
command 'q'. Print an error message if the user enters an illegal
code.
************************************************************************/
int main(void){
char code;
for(;;){
printf("Enter operation code: ");
scanf(" %c" ,&code);
while (getchar() != '\n') // skips to end of line//
;
switch (code){
case 'i' : insert();
break;
case 'u' : update();
break;
case 'p' : print();
break;
case 'q' : return 0;
default: printf("Illegal code\n");
}
printf("\n");
}
}
void insert(void){
struct part *cur, *pre, *new_node;
new_node = malloc(sizeof(struct part));
if (new_node == NULL){
printf("Database is full; can't add more parts.\n");
return;
}
printf("Enter part number: ");
scanf("%d", &new_node->num);
for ( pre = NULL,cur = inventory;
(cur != NULL) && (new_node->num) > (cur->num);
pre = cur,cur = cur ->next)
;
if( cur != NULL && new_node->num == cur->num){
printf("Part already exists\n");
free(new_node);
return;
}
printf("Enter Part name: ");
read_line(new_node->name, NAME_LEN);
printf("Enter quantity on hand: ");
scanf("%d" , &new_node->on_hand);
new_node->next = cur;
printf("%p",new_node->next); //test
if (pre == NULL)
inventory = new_node;
else
pre->next = new_node;
}
void update(void){
int number , change;
struct part *p;
printf("Enter the part number you want to change: ");
scanf("%d", &number);
for (p = inventory ; (p != NULL)&&(number > (p->num)); p = p->next)
printf("%d\n" , p->num);
printf("now pointer point to no.%d\n" , p->num);
if (p->num == number){
printf("Enter change in quantity on hand: ");
scanf("%d",&change);
p->on_hand = ((p->on_hand) change);
printf("Already changed\n");
print();
return;
}
else
printf("No.%d Part is not found.\n",number);
}
void print(void){
struct part *p;
printf("Part Number Part Name Quantity on hand\n");
for ( p = inventory; p != NULL; p = p->next)
printf("m %-25s}\n",p->num,p->name,p->on_hand);
}
CodePudding user response:
You are likely getting a silent segmentation fault. On most systems you will get an error message if a program running on the command line exits due to a segmentation fault (On Linux is usually looks like Segmentation Fault (core dumped)
), however this message can usually be disabled, modified, or omitted due to the configuration of the terminal. Segmentation faults are caused by attempting to read memory from a pointer that points to data outside of the current process.
As mentioned by @MOehm the issue is that update reads too far and attempts to dereference NULL
. It is an easy fit to just add an extra check after your for loop.
for (p = inventory ; (p != NULL)&&(number > (p->num)); p = p->next)
printf("%d\n" , p->num);
if (p == NULL) {
printf("No node with part number %d exists\n", number);
return;
}
printf("now pointer point to no.%d\n" , p->num);
CodePudding user response:
There are several issues in your code worth noting. In your update function you don't ever check if p is a valid pointer in case the function is called before a list is created. This will crash your for loop &(number > (p->num))
. You also aren't clearing your input stream after using scanf and this can work a lot of the times but in my case when I tested it with insert the next read failed. Lastly as pointed out you're de-referencing the pointer p within your for loop before you know p is even valid printf("%d\n" , p->num);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define NAME_LEN 25
struct part{
int num;
char name[NAME_LEN 1];
int on_hand;
struct part *next;
};
struct part *inventory = NULL;
int num_parts = 0; //number of parts currently stored//
struct part *find_part(int number);
void insert(void);
void search(void);
void update(void);
void print(void);
/************************************************************************
*main: Prompts the user to enter an operation code, then calls a function
to perform the requested action. Repeats until the user enters the
command 'q'. Print an error message if the user enters an illegal
code.
************************************************************************/
int main(void){
char code;
for(;;){
printf("Enter operation code: ");
scanf(" %c" ,&code);
while (getchar() != '\n') // skips to end of line//
;
switch (code){
case 'i' : insert();
break;
case 'u' : update();
break;
case 'p' : print();
break;
case 'q' : return 0;
default: printf("Illegal code\n");
}
printf("\n");
}
}
void clearinput(void){
while(fgetc(stdin)!='\n');
}
void insert(void){
struct part *cur, *pre, *new_node;
new_node = malloc(sizeof(struct part));
if (new_node == NULL){
printf("Database is full; can't add more parts.\n");
return;
}
printf("Enter part number: ");
scanf("%d", &new_node->num);
for ( pre = NULL,cur = inventory;
(cur != NULL) && (new_node->num) > (cur->num);
pre = cur,cur = cur ->next)
;
if( cur != NULL && new_node->num == cur->num){
printf("Part already exists\n");
free(new_node);
return;
}
clearinput();
printf("Enter Part name: ");
read_line(new_node->name, NAME_LEN);
printf("Enter quantity on hand: ");
scanf("%d" , &new_node->on_hand);
new_node->next = cur;
printf("%p",new_node->next); //test
if (pre == NULL)
inventory = new_node;
else
pre->next = new_node;
}
void update(void){
int number , change;
struct part *p;
printf("Enter the part number you want to change: ");
scanf("%d", &number);
p = inventory;
assert(p);
for (; (p != NULL)&&(number > (p->num)); p = p->next){
assert(p);
printf("%d\n" , p->num);
}
printf("now pointer point to no.%d\n" , p->num);
if (p->num == number){
printf("Enter change in quantity on hand: ");
scanf("%d",&change);
p->on_hand = ((p->on_hand) change);
printf("Already changed\n");
print();
return;
}else{
printf("No.%d Part is not found.\n",number);
}
}
void print(void){
struct part *p;
printf("Part Number Part Name Quantity on hand\n");
for ( p = inventory; p != NULL; p = p->next)
printf("m %-25s}\n",p->num,p->name,p->on_hand);
}