Cannot implement Linked List in the given code - c

I want to insert the data in ascending order based on the partNumber.
When the function is called in main, then the node is successfully added at the first position. But on calling the function second time, there is some problem in insertion and I am unable to figure it out. When I enter the values(in second call), I get the error
Process exited after 8.277 seconds with return value 3221225477
typedef struct part {
int partNumber;
char partName[200];
int partQuantity;
struct part *nextPart;
} Part;
Part *inventory = NULL;
void insertPart();
int
main(int argc, char *argv[])
{
insertPart();
insertPart();
insertPart();
insertPart();
return 0;
}
void
insertPart()
{
Part *tempPart,
*traversePart,
*swapPart;
int counter = 0;
traversePart = inventory;
tempPart = (Part *) malloc(sizeof(Part *));
printf("Enter the Part Number\n");
scanf("%d", &(tempPart->partNumber));
getchar();
printf("Enter the Part Name\n");
fgets(tempPart->partName, 200, stdin);
printf("Enter the Part Quantity\n");
scanf("%d", &(tempPart->partQuantity));
getchar();
if (inventory == NULL) {
inventory = tempPart;
printf("Part added at the first position.\n");
}
else {
while (traversePart->nextPart->partNumber < tempPart->partNumber) {
counter++;
traversePart = traversePart->nextPart;
if (traversePart->nextPart == NULL) {
break;
}
}
if (counter == 0) {
swapPart = inventory;
inventory = tempPart;
tempPart->nextPart = swapPart;
}
else if (traversePart->nextPart == NULL) {
traversePart->nextPart = tempPart;
}
else {
swapPart = traversePart->nextPart;
traversePart->nextPart = tempPart;
tempPart->nextPart = swapPart;
}
}
printf("Element added at position : %d", counter);
}

The problem is traversePart->nextPart->partNumber traversePart->nextPart is not referring to anything or it is not holding any of the address. When you insert first value if condition is true
if (inventory == NULL) {
inventory = tempPart;
printf("Part added at the first position.\n");
}
inventory now holding the address of tempPart but while assigning values of tempPart you never assign an address to its nextvalue and it's not there because you only inserted the first value. For the second position
else{
while(traversePart->nextPart!=NULL)
{
traversePart=traversePart->nextPart;
}
if(traversePart->partNumber < tempPart->partNumber){
//here you can verify conditions
traversePart->nextPart = tempPart
}
}

You're intermixing fgets and scanf [and getchar]. Better to use just fgets and then apply strtol for numbers [or sscanf].
You're linked list code is a bit convoluted. It can be simplified.
Here's the refactored code. I've pulled some helper functions that I had lying around to do the prompting.
And, I added list printing.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
typedef struct part {
int partNumber;
char partName[200];
int partQuantity;
struct part *nextPart;
} Part;
Part *inventory = NULL;
void insertPart();
int getstr(char *buf,int buflen,const char *prompt);
long getnum_strtol(const char *prompt);
int
main(int argc, char **argv)
{
insertPart();
insertPart();
insertPart();
insertPart();
for (Part *cur = inventory; cur != NULL; cur = cur->nextPart)
printf("partNumber=%d partQuantity=%d partName='%s'\n",
cur->partNumber,cur->partQuantity,cur->partName);
return 0;
}
void
insertPart(void)
{
Part *tempPart;
Part *cur;
Part *prev = NULL;
int counter = 0;
#if 0
tempPart = (Part *) malloc(sizeof(Part *));
#else
tempPart = malloc(sizeof(*tempPart));
#endif
tempPart->partNumber = getnum_strtol("Enter the Part Number");
getstr(tempPart->partName,sizeof(tempPart->partName),"Enter the Part Name");
tempPart->partQuantity = getnum_strtol("Enter the Part Quantity");
tempPart->nextPart = NULL;
// find the tail/end of the list
for (cur = inventory; cur != NULL; cur = cur->nextPart) {
++counter;
// insert in sorted part order
if (cur->partNumber > tempPart->partNumber)
break;
prev = cur;
}
do {
tempPart->nextPart = cur;
// insert in the middle or end of list
if (prev != NULL) {
prev->nextPart = tempPart;
break;
}
// insert in new list or before first element of existing list
tempPart->nextPart = inventory;
inventory = tempPart;
} while (0);
printf("\nElement added at position : %d\n", counter);
}
// getstr -- get a string with prompt
// RETURNS: length or (<0 -> error)
int
getstr(char *buf,int buflen,const char *prompt)
{
char *cp;
int ret = 0;
// NOTE: usage of the error codes in errno.h is arbitrary
while (ret <= 0) {
// ensure buffer has enough space
if (buflen < 2) {
ret = -ENOMEM;
break;
}
// output prompt
if (prompt != NULL) {
printf("%s: ",prompt);
fflush(stdout);
}
// get a line
cp = fgets(buf,buflen,stdin);
// EOF
if (cp == NULL) {
ret = -ENODATA;
break;
}
// get buffer length
ret = strlen(buf);
// empty string
if (ret <= 0)
continue;
// point to last char
cp = &buf[ret - 1];
// ensure we got a newline -- if not, fgets had to chop the line (i.e.)
// the line is too long to fit in the buffer
if (*cp != '\n') {
ret = -ENOSPC;
break;
}
// strip the newline -- we are done
*cp = 0;
--ret;
}
return ret;
}
// getnum_strtol -- get number using strtol
long
getnum_strtol(const char *prompt)
{
int len;
int readflg = 1;
char *cp;
char buf[100];
long num = 0;
while (readflg) {
len = getstr(buf,sizeof(buf),prompt);
if (len < 0)
exit(1);
num = strtol(buf,&cp,10);
// ensure we got a least one digit
if (cp <= buf)
continue;
switch (*cp) {
case ' ':
case '\t':
case 0:
readflg = 0;
break;
default:
printf("getnum_strtol: not a valid number -- buffer '%s', invalid '%s'\n",
buf,cp);
break;
}
}
return num;
}
Here's the input file I used to test:
37
Hex Bolt
12
28
Machine Screw
6
23
Brad Nail
1000
27
Lock Nut
300
Here's the program output:
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 0
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 1
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 1
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 2
partNumber=23 partQuantity=1000 partName='Brad Nail'
partNumber=27 partQuantity=300 partName='Lock Nut'
partNumber=28 partQuantity=6 partName='Machine Screw'
partNumber=37 partQuantity=12 partName='Hex Bolt'

Related

How to access an element in the structure which not the first - Qsort

I am trying to sort the following structure. I am using the qsort to order the books according to date publish in order of the newest first. I completely don't understand why the pointer can't access the date-published element.
#include <string.h>
#include <stdlib.h>
#include "problem5.h"
int int_cmp(const void *a, const void *b)
{
//const int *ia = (const int *)a;
//const int *ib = (const int *)b;
//return *ia - *ib;
return (*(int*)a - *(int*)b);
}
int main()
{
struct book* books = NULL; // no books at all initially so we initialize to NULL
// so we can simply use realloc
int numberofbooks = 0;
int programend = 0;
while (programend == 0)
{
printf("1. Add Book\n");
printf("2. View Books\n");
printf("3. Quit\n");
int command;
int i, j;
scanf("%d", &command);
if (command == 1)
{
getchar(); // consume Enter key (due su scanf)
// allocate memory for one more book
books = realloc(books, sizeof(struct book) * (numberofbooks + 1));
printf("Enter Name\n");
gets(books[numberofbooks].name);
printf("Enter Author\n");
gets(books[numberofbooks].author);
printf("Enter Year Published\n");
scanf("%d", &books[numberofbooks].year_published);
numberofbooks++; // increment number of books
printf(books.year_published);
}
else if (command == 2)
{
qsort(books->year_published, numberofbooks, sizeof(int), int_cmp);
for (i = 0; i < numberofbooks; i++)
{
printf("%d - %s by %s\n", books[i].year_published, books[i].name, books[i].author);
}
}
else if (command == 3)
{
programend = 1;
}
//else if and the else will prevent infinite loop when the user enters invalid choice in the beginning.
else if (command != 1 || command != 2 || command != 3)
{
printf("Invalid choice!\n");
}
else {return 0;}
}
free(books);
return 0;
}
I think the problem is the pointer in the qsort() but I don't know how to correct that. I tried using qsort(books, numberofbooks, sizeof(int), int_cmp); but the books weren't ordered as expected.
Here is an example of a multikey sort:
int
cmp_multikey(const void *a,const void *b)
{
const struct book *booka = a;
const struct book *bookb = b;
int cmp;
do {
// sort by year published
cmp = booka->year_published - bookb->year_published;
if (cmp)
break;
// sort by author
cmp = strcmp(booka->author,bookb->author);
if (cmp)
break;
// sort by title
cmp = strcmp(booka->name,bookb->name);
if (cmp)
break;
} while (0);
return cmp;
}
Invoke with:
qsort(books,numberofbooks,sizeof(struct book),cmp_multikey);
Some other tips ...
[As others have mentioned] Never use gets. Use a switch/case instead of an if/else ladder.
Try to avoid intermixing scanf and fgets.
Personally, I prefer to [always] use fgets. Here is a [safe] replacement for gets and a replacment for scanf("%d",&num);:
int
getstr(const char *prompt,char *buf,int buflen)
{
char *cp;
printf("%s",prompt);
fflush(stdout);
cp = fgets(buf,buflen,stdin);
if (cp == NULL) {
fprintf(stderr,"unexpected EOF\n");
exit(1);
}
// find newline
cp = strchr(buf,'\n');
// ensure we had enough space
if (cp == NULL) {
fprintf(stderr,"response too large for buffer\n");
exit(1);
}
// strip newline
*cp = 0;
}
int
getnum(const char *prompt)
{
char buf[1000];
int num;
getstr(prompt,buf,sizeof(buf));
num = atoi(buf);
return num;
}

Program doesnt write to file and crashes when loading

So i need to write and read to and from a binary file, but cant seem to do it, and when using readFromFile, the program crashes. I need help write to binary file, and then reading from it and resuming my work later after turning off the program.I have no idea what i am doing wrong, and i have googled for a long time now, but with no results. Here is the code of my program:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char *subjName;
char *lectName;
char *lectSurname;
int credits;
int num_students;
}Subject;
typedef struct{
Subject **subjs;
int num_subjs;
}Subjects;
int numOfSubjs=0;
void listInput();
void listEdit();
void listDelete();
void listPrint();
int userChoice(int select);
int enterNumber(char *name);
void saveToFile(Subjects *subjects);
void readFromFile(Subjects *subjects);
int main() {
Subjects *subjects = malloc(sizeof(Subjects));
subjects->num_subjs = 0;
subjects->subjs = NULL;
readFromFile(subjects);
int r=1;
while(r!=0){
int select=userChoice(select);
switch(select){
case 1:
listPrint(subjects);
break;
case 2:
listInput(&subjects);
break;
case 3:
listDelete(subjects);
break;
case 4:
listEdit(subjects);
break;
case 0:
r=0;
break;
}
}
saveToFile(subjects);
return 0;
}
int userChoice(int select){ // menu options
int choice,input=0;
printf("(1). View all the data\n");
printf("(2). Enter new data\n");
printf("(3). Delete data\n");
printf("(4). Edit data\n");
printf("(0). Exit\n");
printf("-----------------------------\n");
while(input!=1){
choice = enterNumber("menu");
if(choice>4 || choice<0){
printf("Invalid input \n");
}
else
input = 1;
}
return choice;
}
void listPrint(Subjects *subjects){ // print data
int i;
for(i=0; i< numOfSubjs; i++){
printf("%d, %s, %s, %s, %d, %d\n",i+1, subjects->subjs[i]->subjName, subjects->subjs[i]->lectName, subjects->subjs[i]->lectSurname, subjects->subjs[i]->credits, subjects->subjs[i]->num_students);
}
printf("Number of entries: %d \n", numOfSubjs);
}
char *getln() //dynamically allocate input string
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = 1;
while (ch) {
ch = getc(stdin);
if (ch == '\n')
ch = 0;
if (size <= index) {
size += 1;
tmp = realloc(line, size);
if (!tmp) {
free(line);
line = NULL;
break;
}
line = tmp;
}
line[index++] = ch;
}
return line;
}
void saveToFile(Subjects *subjects){
FILE *data;
data = fopen("data.bin","wb");
printf("%s", subjects->subjs[0]);
for(int i=0; i<numOfSubjs; i++){
fwrite(&subjects->subjs[i],sizeof(Subject*),1,data);
}
fclose(data);
}
void readFromFile(Subjects *subjects){
FILE *data;
int i=0;
data = fopen("data.bin","rb");
while(!feof(data))
{
fread(&subjects->subjs[i],sizeof(Subject*),1,data);
i++;
}
fclose(data);
}
int isText(char *str,char *name){ // check if is text
for(int i = 0; i < strlen(str);i++){
if((str[i]<'A' || str[i]>'z') && str[i]!=' '){
printf("Error, %s must be a text \n",name);
return 0;
}
}
return 1;
}
int enterNumber(char *name){ // enter number and check if is number
int input=0, crash=0, num=0;
while(input!=1)
{
crash=0;
printf("Enter the number of %s\n", name);
scanf("%d", &num);
while(getchar()!='\n')
{
crash++;
}
if(crash>0 || num<0)
printf("Error, enter a not negative number of %s\n", name);
else if(crash==0)
input=1;
}
return num;
}
void listInput(Subjects **p_subjects){ // input new data
Subject *new_subj = malloc(sizeof(Subject));
new_subj->subjName = NULL;
new_subj->lectName = NULL;
new_subj->lectSurname = NULL;
new_subj->credits = 0;
new_subj->num_students = 0;
do{
printf("Enter the name of the subject \n");
new_subj->subjName = getln();
}while(!isText(new_subj->subjName,"Subject name"));
do{
printf("Enter the name of the lecturer \n");
new_subj->lectName = getln();
new_subj->lectName[0] &= '_';
}while(!isText(new_subj->lectName,"Lecturer's name"));
do{
printf("Enter the surname of the lecturer\n");
new_subj->lectSurname = getln();
new_subj->lectSurname[0] &= '_'; //Convert to uppercase if lowercase
}while(!isText(new_subj->lectSurname,"Lecturer's name"));
new_subj->credits = enterNumber("credits");
new_subj->num_students = enterNumber("students");
(*p_subjects)->subjs = realloc((*p_subjects)->subjs,sizeof(Subject*)*(++(*p_subjects)->num_subjs));
(*p_subjects)->subjs[(*p_subjects)->num_subjs-1] = new_subj;
numOfSubjs++;
printf("Added a new entry.\n\n");
}
void listDelete(Subjects *subjects){ // delete entries
int del;
if(numOfSubjs==0)
printf("Number of entries is 0, can't delete anything\n");
else{
printf("Enter 0 to exit. Number of subjects : %d \n", numOfSubjs);
while(1){
del = enterNumber("entry which you would like to delete");
if(del<=numOfSubjs && del>0){
for(int i = del-1; i<numOfSubjs-1; i++){
subjects->subjs[i]=subjects->subjs[i+1];
subjects->subjs = realloc(subjects->subjs,sizeof(Subject*)*(--subjects->num_subjs));
}
numOfSubjs--;
break;
}
if(del>numOfSubjs)
printf("Error, input a number between 1 and %d (or enter 0 to exit)\n", numOfSubjs);
else
break;
}
}
}
void listEdit(Subjects *subjects){ // edit entries
int choice=0, editEntry=0, editSubj=0;
if(numOfSubjs == 0)
printf("Number of entries is 0, can't edit anthing\n");
else{
while(1){
printf("Number of entry must be between 1 and %d \n", numOfSubjs);
choice = enterNumber("entry you would like to edit.");
if(choice>0 && choice<=numOfSubjs){
while(1){
editEntry = enterNumber("what would you like to edit\n 1 - Subject name\n 2 - Lecturer's name\n 3 - Lecturer's surname\n 4 - Number of credits\n 5 - Number of students");
if(editEntry>0 && editEntry <=5){
switch(editEntry){
case 1:
do{
printf("Enter the name of the subject \n");
subjects->subjs[choice-1]->subjName = getln();
}while(!isText(subjects->subjs[choice-1]->subjName,"Subject name"));
break;
case 2:
do{
printf("Enter Lecturer's name \n");
subjects->subjs[choice-1]->lectName = getln();
}while(!isText(subjects->subjs[choice-1]->lectName,"Lecturer's name"));
break;
case 3:
do{
printf("Enter Lecturer's surname \n");
subjects->subjs[choice-1]->lectSurname = getln();
}while(!isText(subjects->subjs[choice-1]->lectSurname,"Lecturer's surname"));
break;
case 4:
subjects->subjs[choice-1]->credits = enterNumber("credits");
break;
case 5:
subjects->subjs[choice-1]->num_students = enterNumber("students");
break;
}
}
break;
}
}
break;
}
}
}
&subjects->subjs[i], This is Undefined behavior. Accessing garbage value. You need to properly initialize it proper memory address. You ddin't do it anywhere.
(*subjects).subjs or subjects->subjs -> This is not pointing anywhere. It is NULL.
Also here you don't need the double pointer. A single pointer would do the thing you want to do.
typedef struct{
Subject *subjs;
int num_subjs;
}Subjects;
For single pointer this would be like
Subjects *subjects = malloc(sizeof(Subjects));
subjects->num_subjs = 10;
subjects->subjs = malloc(subjects->num_subjs * sizeof Subject);
subjects->subjs[0].subjName = malloc(40);
Each of the malloc should be checked with it's return Value. If it's NULL then it would be error to proceed further or access it.
And free() it accordingly when you are done working with it.
Some basic things:-
typedef struct{
Subject *subjs;
int num_subjs;
}Subjects;
Now let's look a bit in the code.
Op asked why OP should initialize and isn;t subjects->num_subjs = 0;
subjects->subjs = NULL; not enough?
A pointer is a variable that is supposed to hold address. here Subject* will hold the address of the variables of type Subject.
Now here initially you initialized it.
You have allocated a memory and assigned it's address to the Subject* variable subjects.
Now let's see what else you do.
subjects->num_subjs = 0;
subjects->subjs = NULL;
You initialized it. And then you try to access it(subjects->subjs[i]). Can you tell me where it points to? (subject->subjs)?
Answer is nope. It is pointing to nowhere. It contains NULL value now. Don't you think you should tell it how many subject you want to hold and allocate accordingly? Yes you should and that's what I did precisely in the example shown.
Whenever you have a pointer variable ask yourself what it contains - and if the value is something you know about, not some random garbage value.

Segmentation fault when reading text file to array of linked list

The read_to_list function is designed to scan the contents of a file - dump.txt - and load it into the array of singly linked lists.
The problem lies in LINE 2 of the main function: read_to_list(argv[1]);
The dump.txt file contains the following information:
Name Group Size
----------------------------------
Anna 2
Bill 4
Connor 6
Denise 8
The argv[1] correlates to a text file that I declare on the command line to dump data from my linked list after running the program. After exiting the program the .txt file saves the data in the above format format.
I do not know why I am getting a segmentation fault when calling the read_to_list function on the file passed in the CLI as it appears to me that the function should load the data correctly and the function is called at the right position in the main function.
Thank you for any and all help that I can get!
The code is below:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct node
{
char name[20];
int size;
struct node *next;
}node;
node* head[4]={NULL,NULL,NULL,NULL};
node* tail[4]={NULL,NULL,NULL,NULL};
void read_to_list(char *filename)
{
FILE *fp;
int mined_partysize;
char mined_partyname[20];
char header = "Name\t\tGroup Size\n----------------------------------\n";
fp = fopen(filename, "r");
if (fp == NULL)
return;
fseek(fp, strlen(header), SEEK_SET);
printf("This is working1");
while(fscanf(fp, "%s%d", mined_partyname, &mined_partysize) == 2)
{
printf("This is working2");
if(mined_partysize == 0)
{
printf("\nThat is not a valid command. Party not added!\n");
}
if(mined_partysize >= 1 && mined_partysize <= 2)
{
add_party(0, mined_partyname, mined_partysize);
}
else if(mined_partysize >= 3 && mined_partysize <= 4)
{
add_party(1, mined_partyname, mined_partysize);
}
else if(mined_partysize >= 5 && mined_partysize <= 6)
{
add_party(2, mined_partyname, mined_partysize);
}
else if(mined_partysize >= 7)
{
add_party(3, mined_partyname, mined_partysize);
}
}
fclose(fp);
return;
}
//
// main function
//
int main(int argc, char *argv[])
{
int x;
read_to_list(argv[1]);
while (1)
{
fflush(stdin);
printf("\n\nEnter 1 to add a party\nEnter 2 to remove a party\nEnter 3 for the list of the party\nEnter 4 to change party size.\nEnter 5 to quit.\n\n");
// user interface
scanf("%d",&x);
char name[20];
int size;
switch(x)
{
case 1:
printf("\nParty Name: ");
scanf("%s", name);
printf("\nParty Size: ");
scanf("%d", &size);
if(size == 0)
{
printf("\nThat is not a valid command. Party not added!\n");
}
if(size >= 1 && size <= 2)
{
add_party(0, name, size);
}
else if(size >= 3 && size <= 4)
{
add_party(1, name, size);
}
else if(size >= 5 && size <= 6)
{
add_party(2, name, size);
}
else if(size >= 7)
{
add_party(3, name, size);
}
break;
case 2:
printf("\nSize of party to delete: ");
scanf("%i", &size);
delete_party(NULL, size);
break;
case 3:
list_parties();
break;
case 4:
change_partysize(name, size);
break;
case 5:
write_to_file(argv[1]);
exit(0);
break;
default:
continue;
}
}
}
//
//add function
//
void add_party(int h, char *name, int size)
{
//declare file pointer
FILE *fp;
//to be used by fscanf
int number;
//create a new node
int i=0;
int breaker = 0;
node *p;
node *new_item;
new_item = (node *)malloc(sizeof(node)); // allocate memory the size of the struct
strcpy(new_item->name,name);
new_item->size = size;
if(head[h] == NULL && tail[h] == NULL) // if an empty list, create a head and tail
{
head[h] = new_item;
tail[h] = head[h];
new_item->next = NULL;
return;
}
//traversal
for(i=0; i<4; i++)
{
p = head[i];
while(p != NULL)
{
//check that no repeating names. delete nodes that do have repeating names
if(strcmp(p->name,name) == 0)
{
printf("\nSorry, that name is already taken\n");
free(new_item);
return;
}
p = p->next; //go to the next node in the list
}
}
tail[h]->next = new_item;
new_item->next = NULL;
tail[h] = new_item;
}
You're de-referencing a null pointer.

Incorrect code to check if a word can be made of smaller given words (word break)

Incorrect code to check if a word can be made of smaller given words (word break).This is the code I wrote for the above mentioned problem, however an online judge declares it as incorrect, what could be the possible reasons? And how should I modify my code?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Node structure */
typedef struct node {
int letter[26];
struct node* next[26];
int is_word;
} node;
/* Create node */
node* getnode(void) {
node* p = malloc(sizeof(node));
int i;
for (i = 0; i < 1004; i++) {
p->letter[i] = 0;
p->next[i] = NULL;
}
p->is_word = 0;
return p;
}
/* make dictionary */
void fill_dictionary(char word[], node* start) {
int len = strlen(word), i;
node* temp = start;
for (i = 0; i < len; i++) {
if (temp->letter[word[i] % 'a'] == 0) {
temp->letter[word[i] % 'a'] = 1;
temp->next[word[i] % 'a'] = getnode();
temp = temp->next[word[i] % 'a'];
} else {
temp = temp->next[word[i] % 'a'];
}
}
temp->is_word = 1;
return;
}
int spell_check(char line[100003], node* start) {
int len = strlen(line), i, flag = 0;
node* temp = start;
for (i = 0; i < len; i++) {
if (temp->letter[line[i] % 'a'] == 0) {
return 1;
} else {
temp = temp->next[line[i] % 'a'];
flag = 0;
if (temp->is_word == 1) {
flag = 1;
temp = start;
}
}
}
if (flag == 1) {
return 0;
} else {
return 1;
}
}
int main(void) {
int n, i, ans, m;
scanf("%d %d", &n,&m); // no. of words in dictionary
node* start = getnode();
for (i = 0; i < n; i++) {
char word[11]; // max length of dictionary word
scanf("%s", word);
fill_dictionary(word, start);
}
scanf("%d", &n); // no. of lines to be checked
for (i = 0; i < n; i++) {
char line[100003]; // max length of a line
scanf("%s", line);
ans = spell_check(line, start);
if (ans == 0) {
printf("YES\n");
} else {
printf("NO\n");
}
}
return 0;
}
Here's one way to to it. This compiles and runs. It displays the parsed result. It tries to read the dictionary from a file called "dictionary.text" in the current directory. You can change it to put the dictionary wherever you want. I commented it heavily to help you understand it but it has some subtle C things you may need to really think about and figure out. One bit of advice: Name everything in a program as extremely accurately for what it is/does as possible (but reasonably succinct). That will help immensely when trying to debug or figure out what you did wrong. Careless names really make code confusing and hard to debug.
Good luck!
Example:
$ gcc -o wordsplitter wordsplitter.c
$ wordsplitter xyzhellogoodbyefoodogcatpigcarwhereareyouhorse
xyz "hello" "goodbye" foo "dog" "cat" pigcar "where" "are" "you" horse
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DICTIONARY_FILEPATH "dictionary.txt"
#define MAX_WORD_SIZE 100
/*
* Error codes (usually this is put in a header file and included)
*/
#define SUCCESS 0
#define FILE_NOT_FOUND -1
#define OUT_OF_MEMORY -2
typedef struct word {
struct word *next;
char *word;
} word_t;
word_t *dictionaryListhead = NULL;
typedef struct wordsubcomponent {
struct wordsubcomponent *next;
char *text;
int isDictionaryWord;
} wordsubcomponent_t;
int
loadDictionaryFromFile(char *filename, word_t **listhead)
{
char wordFromFile[MAX_WORD_SIZE];
word_t *lastWordStored = NULL;
FILE *dictionaryFile = fopen(filename, "r");
if (dictionaryFile == NULL) {
return FILE_NOT_FOUND;
}
while(fgets(wordFromFile, sizeof(wordFromFile), dictionaryFile)) {
word_t *newDictionaryWordNode;
if ((newDictionaryWordNode = calloc(sizeof(word_t), 1)) == NULL) { // calloc automatically zeroes memory
return OUT_OF_MEMORY;
}
char *cp = strchr(wordFromFile, '\n');
if (cp != NULL)
*cp = '\0'; // get rid of trailing \n
newDictionaryWordNode->word = strdup(wordFromFile);
if (*listhead == NULL) {
lastWordStored = *listhead = newDictionaryWordNode;
} else {
lastWordStored = lastWordStored->next = newDictionaryWordNode;
}
}
fclose(dictionaryFile);
return SUCCESS;
}
wordsubcomponent_t
*newsubcomponent() {
wordsubcomponent_t *subcomp = NULL;
if ((subcomp = calloc(sizeof(wordsubcomponent_t), 1)) != NULL) {
subcomp->text = strdup(""); // seed with empty string (instead of NULL) so we can append
} else {
fprintf(stderr, "out of memory (fatal). program exiting\n");
exit(-1);
}
return subcomp;
}
/*
* Returns an linked list of word subcomponents for the given word, split up around dictionary words
*/
wordsubcomponent_t *getWordSubcomponents(char *wordToParse, word_t *listhead) {
wordsubcomponent_t *subcomponents, *currSubcomp;
subcomponents = currSubcomp = newsubcomponent();
for (char *cp = wordToParse; cp < wordToParse + strlen(wordToParse);) { // exit when cp gets to end of word to parse.
int matchFlag = 0;
for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
if (strncasecmp(cp, wordNode->word, strlen(wordNode->word)) == 0) { // prefix of cur. ptr is dict word.
if (strlen(currSubcomp->text) != 0) // Detected non-dict text in subcomp.
currSubcomp = currSubcomp->next = newsubcomponent(); // leave in list & add new subcomp for dict word.
currSubcomp->text = wordNode->word; // save dict-word in subcomp
currSubcomp->isDictionaryWord = 1;
currSubcomp = currSubcomp->next = newsubcomponent(); // dict-word in list, so get new subcomp
cp += strlen(wordNode->word); // advance cp past extracted dict-word
matchFlag = 1;
break; // break out of inner-loop
}
}
if (!matchFlag) { // No dict-word found at cp
char oneNullTerminatedLetter[2] = { *cp++, '\0' }; // put 1st ltr into NULL-terminated string & adv cp.
strcat(currSubcomp->text, oneNullTerminatedLetter); // append letter-as-string to curr subcomp
}
}
return subcomponents;
}
void
dumpDictionary(word_t *listhead) {
printf("\nList of dictionary words:\n");
printf("----------------\n");
for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
printf(" %s\n", wordNode->word);
}
printf("----------------\n\n");
}
int
main(int argc, char **argv)
{
int status;
if ((status = loadDictionaryFromFile(DICTIONARY_FILEPATH, &dictionaryListhead)) < 0) {
switch(status) {
case FILE_NOT_FOUND:
fprintf(stderr, "Error accessing dictionary: %s\n", argv[0]);
break;
case OUT_OF_MEMORY:
fprintf(stderr, "Out of memory");
break;
}
return EXIT_FAILURE;
}
/*
* Load dictionary first so we can show them the list of words if they didn't
* pass in a command line argument with the word to parse.
*/
if (argc < 2) {
fprintf(stderr, "Usage: %s <word_to_parse>\n\n", argv[0]);
dumpDictionary(dictionaryListhead);
return EXIT_FAILURE;
}
wordsubcomponent_t *subcomp = getWordSubcomponents(argv[1], dictionaryListhead);
while(subcomp != NULL && strlen(subcomp->text) > 0) {
if (subcomp->isDictionaryWord)
printf("\"%s\" ", subcomp->text);
else
printf("%s ", subcomp->text);
subcomp = subcomp->next;
}
printf("\n");
return EXIT_SUCCESS;
}
#nerdist colony:
There is a resource leak in loadDictionaryFromFile. This means a file pointer was not closed when returning from this function in case of an error.
Here is a corrected copy of this function
int loadDictionaryFromFile(char *filename, word_t **listhead)
{
char wordFromFile[MAX_WORD_SIZE];
word_t *lastWordStored = NULL;
FILE *dictionaryFile = fopen(filename, "r");
if (dictionaryFile == NULL) {
return FILE_NOT_FOUND;
}
while(fgets(wordFromFile, sizeof(wordFromFile), dictionaryFile)) {
word_t *newDictionaryWordNode;
if ((newDictionaryWordNode = calloc(sizeof(word_t), 1)) == NULL) { // calloc automatically zeroes memory
fclose(dictionaryFile); // <-- Close the file pointer
return OUT_OF_MEMORY;
}
char *cp = strchr(wordFromFile, '\n');
if (cp != NULL)
*cp = '\0'; // get rid of trailing \n
newDictionaryWordNode->word = strdup(wordFromFile);
if (*listhead == NULL) {
lastWordStored = *listhead = newDictionaryWordNode;
} else {
lastWordStored = lastWordStored->next = newDictionaryWordNode;
}
}
fclose(dictionaryFile);
return SUCCESS;
}

C: Segmentation fault with printing Link List

I'm pretty new to C, but I wanted to build a program that could allows users store ip addresses obtained from a traceroute/tracert that is first stored into a text file. It then allows them to print the next/previous hop. I used a linked list, but the printing gives me a segmentation error.
I tried looking through it but I can't find any error, would someone point out my error and guide me? Thanks in advance!!
(Sorry for the poor indentation!!)
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
int id = 0;
int list = 0;
int nodes = 0;
FILE *readFile(char *fileName)
{
FILE *rawdata = fopen(fileName, "r");
return rawdata;
}
void printMenu()
{
printf(" ========== MENU =============\n\n");
printf("1. Report ID of Previous Hops of a network node\n");
printf("2. Identify the next hops of a network node\n");
printf("3. Quit\n");
}
int getInput()
{
int choice;
printf("Please select your choice (1 to 3) =>: ");
scanf("%d", &choice);
return choice;
}
struct NodeInfo {
int ID;
int IP1;
int IP2;
int IP3;
int IP4;
struct NodeInfo *next;
struct NodeInfo *prev;
};
typedef struct NodeInfo Node;
Node *Topology;
Node *createNode(int ip1, int ip2, int ip3, int ip4)
{
Node *newNode = malloc(sizeof(Node));
newNode->IP1 = ip1;
newNode->IP2 = ip2;
newNode->IP3 = ip3;
newNode->IP4 = ip4;
newNode->next = 0; // NULL Pointer
newNode->prev = 0; // NULL Pointer
return newNode;
}
void addToBack(Node * tempnode)
{
Node *n = Topology;
Node *tail = 0;
while (n != NULL) {
tail = n;
n = n->next;
}
tail->next = tempnode;
tempnode->prev = tail;
}
void printFile(FILE * newFile)
{
char data[256], nth1[50], nth2[50], nth3[50], nth4[50], nth5[50],
nth6[50], nth7[50], ip[50], ip2[15], ip2new[14];
int linecount = -1, strlength;
int ip1, ip2x, ip3, ip4;
int ip11, ip21, ip31, ip41;
if (newFile == NULL) {
printf("There is an error with opening this file\n");
} else {
while (fgets(data, 256, newFile) != NULL) {
if (linecount != 3) {
linecount++;
continue;
} else {
if (linecount == 3 && data[2] != '\0') {
sscanf(data, "%s %s %s %s %s %s %s %s", nth1, nth2, nth3, nth4,
nth5, nth6, nth7, ip);
sscanf(data, "%s %s %s %s %s %s %s %d.%d.%d.%d", nth1, nth2,
nth3, nth4, nth5, nth6, nth7, &ip1, &ip2x, &ip3, &ip4);
if ((ip[0] <= 'z' && ip[0] >= 'a')
|| (ip[0] <= 'Z' && ip[0] >= 'A')) {
sscanf(data, "%s %s %s %s %s %s %s %s %s",
nth1, nth2, nth3, nth4, nth5, nth6, nth7, ip, ip2);
//Rescanning for anomaly results with additional hostname
strncpy(ip2new, ip2 + 1, strlen(ip2) - 2);
ip2new[strlen(ip2) - 2] = '\0';
int i;
char *temp;
char *ipcmp[4];
i = 0;
temp = strtok(ip2new, ".");
while (temp != NULL) {
ipcmp[i++] = temp;
temp = strtok(NULL, ".");
}
Node *tempnode = createNode(ip2new);
if (Topology != 0) {
addToBack(tempnode);
} else {
Topology = tempnode;
}
} else {
printf("%s\n", ip);
printf("%d.%d.%d.%d\n", ip1, ip2x, ip3, ip4);
Node *tempnode2 = createNode(ip);
if (Topology != 0) {
addToBack(tempnode2);
} else {
Topology = tempnode2;
}
continue;
}
}
if (linecount == 3 && data[2] == '\0') {
linecount = -2;
printf("\n");
}
}
}
}
}
void printNodes()
{
Node *n = Topology;
while (n != 0) {
printf("The node is %d.%d.%d.%d\n", n->IP1, n->IP2, n->IP3, n->IP4);
n = n->next; // Jump to next node
}
}
int main(int argc, char *argv[])
{
int option, fail;
FILE *filedata;
char *file;
file = argv[1];
filedata = readFile(file); //open file
printFile(filedata); //prints the ip addresses
do {
printMenu();
option = getInput();
switch (option) {
case 1:
printf("You have selected 1\n\n");
fail = 0;
printNodes();
break;
case 2:
printf("You have selected 2\n\n");
fail = 0;
break;
case 3:
fail = 1;
break;
default:
printf("Please enter a valid choice (1-3) \n");
fail = 0;
break;
}
} while (fail != 1);
while (Topology != 0) {
free(Topology);
Topology = Topology->next;
}
}
Your create node method have 4 parameters:
Node *createNode(int ip1, int ip2, int ip3, int ip4)
But you invoke this method by passing only one parameter:
Node *tempnode = createNode(ip2new);
Node *tempnode2 = createNode(ip);
Also you pass arrays when your method accept only integers.
This is at least two sources of errors in your code.
There are two corrections that I can spot. First is that you are calling createNode() with the wrong number of arguments. You have defined createNode() to take 4 integral arguments, but in each of your calls, you are passing it a string argument. The compiler should have given you a diagnostic about this issue (my compiler refuses to compile the code). You should never ignore a compiler diagnostic (at least, not without first fully understanding what the diagnostic means).
Change those calls to use the 4 integral variables that you scanned.
Node *tempnode = createNode(ip1, ip2x, ip3, ip4);
Node *tempnode2 = createNode(ip1, ip2x, ip3, ip4);
The second error is that your if (linecount != 3) { only allows you to process data when linecount is equal to 3, which is probably not what you want to do. You probably mean to process all lines of data after linecount becomes 3.
if (linecount < 3) {
linecount++;
continue;
} else {
I find it odd that you have initialized linecount to -1, but it just means you won't start processing the file until you reach the fourth line of input.
As has been mentioned by others, you cannot read from memory that has already been freed. Doing so causes undefined behavior. In your loop to release the memory held by Topology, save the pointer to the next item before freeing the current item.
while (Topology != 0) {
void *cur = Topology;
Topology = Topology->next;
free(cur);
}
There's a few issues here.
You mix your usage of NULL and 0. While both will work, in C it is idiomatic to use NULL, and it is best to be consistent in your usage.
Your createNode function expects 4 integers, but your code is calling this function and only providing one argument.
You have undefined behaviour in your loop:
while (Topology != 0) {
free(Topology);
Topology = Topology->next;
}
It is undefined behaviour to access Topology once it has been freed. In your case, you are attempting to access the next member of Topology after it has been freed.

Resources