C: Segmentation fault with printing Link List - c

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.

Related

Cannot implement Linked List in the given code

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'

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.

C read linked list from file and write to another file

I'm trying to make a program that would read a linked list and output all of the info that it has read. My problem is that I can't simply output. There is some problem that I can't find.
#include <stdio.h>
#include <stdlib.h>
struct sarasas
{
char *reiksme;
struct sarasas *kitas;
};
int main()
{
struct sarasas *sarasasPtr, *pradz, *pab, *elem;
pradz = NULL;
pab = NULL;
FILE *duomPtr;
printf("Iveskite duomenu failo pavadinima: ");
char failas[255];
scanf("%s", failas);
duomPtr = fopen(failas, "r");
if(duomPtr == NULL)
{
printf("Toks duomenu failas neegzistuoja \n");
exit(0);
}
int k = 0;
char paimtaReiksme[255];
while(fscanf(duomPtr, "%s", paimtaReiksme) != EOF)
{
if(k == 0)
{
sarasasPtr = (struct sarasas*)malloc (sizeof (struct sarasas));
sarasasPtr->reiksme = paimtaReiksme;
sarasasPtr->kitas = NULL;
pradz = sarasasPtr;
pab = sarasasPtr;
}
else
{
sarasasPtr = (struct sarasas*)malloc (sizeof (struct sarasas));
sarasasPtr->reiksme = paimtaReiksme;
sarasasPtr->kitas = NULL;
pab->kitas = sarasasPtr;
pab = sarasasPtr;
}
k++;
}
if(pradz == NULL && pab == NULL)
{
printf("Tuscia\n");
exit(0);
}
FILE *rptr;
printf("Iveskite rezultatu failo pavadinima: ");
char failas2[255];
scanf("%s", failas2);
rptr = fopen(failas2, "w");
while(sarasasPtr->kitas != NULL)
{
fprintf(rptr, "%s", sarasasPtr->reiksme);
}
return 0;
}
You have an infinite loop in your code.
while(sarasasPtr->kitas != NULL)
{
fprintf(rptr, "%s", sarasasPtr->reiksme);
}
Here in the above while loop, you are trying to print the same element over and over again and thus you end up in an infinite loop.instead, you must change the pointer to next element after each and every iteration. You can try something like this:
while(sarasasPtr != NULL) //check whether pointer points to NULL
{
fprintf(rptr, "%s", sarasasPtr->reiksme);
sarasasPtr = sarasasPtr->kitas; //make pointer point to next element
}
additionally, you need not cast the the return value of malloc : Here's why(click)

AddNumber Function Trouble

I am having trouble understanding how to take the user input from my program and pass it into the function AddNumber. The program will start and ask for user input and will store it into the input array, but I am not sure how to take the information from the array and pass it to the function AddNumber.
I have updated the code, from what I understand my 'AddNumber' function doesn't do anything. I was under the impression that I created the pointer 'previous' should previous = NULL?
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
typedef struct A_NewNumber {
struct A_NewNumber *next;
char newNum;
} NewNumber;
NewNumber *AddNumber(NewNumber *previous, char *input){
//char input[16];
//double numEntered = 0;
NewNumber *newNum = malloc(sizeof(NewNumber));
sscanf(input, "%lf", &newNum->newNum);
//sscanf(input, "%s", newNum->enterNumber);
//numEntered = atof(input);
//possible code
/*if (previous != NULL){
previous->newNum;
}
newNum->next = NULL;
newNum->newNum = 0;
return newNum;
}*/
void PrintList(NewNumber *numStart) {
NewNumber *currentNumber = numStart;
int count = 0;
while (currentNumber != NULL) {
count++;
printf("Number Position:%s\n", currentNumber->enterNumber);
currentNumber = currentNumber->next;
}
printf("Total Numbers Entered%d\n", count);
}
void CleanUp(NewNumber *start) {
NewNumber *freeMe = start;
NewNumber *holdMe = NULL;
while (freeMe != NULL) {
holdMe = freeMe->next;
free(freeMe);
freeMe = holdMe;
}
}
int main(){
//indexNum = 0;
char command[16];
char input[16];
//float userInput;
NewNumber *userEnter = NULL;
NewNumber *start = NULL;
NewNumber *newest = NULL;
while(fgets(input, sizeof input, stdin)){
printf("Please enter a number->");
printf("Enter 'quit' to stop or 'print' to print/calculate");
sscanf(input, "%s", command);
if(newest == NULL){
start = AddNumber(NULL, input);
newest = start;
}else{
newest = AddNumber(newest, input);
}
if( strncmp(command, "print", 5) == 0){
PrintList(start);
}else if( strncmp(command, "quit", 4)== 0){
printf("\n\nQuitting....\n");
break;
//userInput = enterNumber;
}
}
CleanUp(start);
return 0;
}
Without modifying your code too much, I would suggest that AddNumber takes a pointer to the previous NewNumber as well as the user input. Your intent seems to be to read in doubles as well so I'd modify the newNum field to be of type double. Something like this:
typedef struct A_NewNumber{
struct A_NewNumber *next;
double newNum;
} NewNumber;
NewNumber *AddNumber(NewNumber *previous, char *input){
NewNumber *newNum = malloc(sizeof(NewNumber));
/* use %lf to read in a double */
sscanf(input, "%lf", &newNum->newNum);
if (previous != NULL){
previous->next = newNum;
}
return newNum;
}
Then you can pass the previous and the input when you call the AddNumber function like
if(newest == NULL){
start = AddNumber(NULL, input);
newest = start;
} else {
newest = AddNumber(newest, input);
}
Some problmes:
Code has no effect
if (previous != NULL){
// Following line does no assignment
previous->newNum;
}
Certainly after allocation, all fields should be set
NewNumber *newNum = malloc(sizeof(NewNumber));
sscanf(input, "%s", newNum->enterNumber);
// add
newNum->next = NULL;
newNum->newNum = 0; // TBD code, but set to something
Wrong pointer type to function
NewNumber *AddNumber(NewNumber *previous){
....
char input[16];
....
start = AddNumber(input);
There is usually a built-in way to get user input in most programming languages. For example, in Java you can use the Scanner object to prompt for user input from the command line. Is this a command line application?
This is C so I encourage you to use the scanf() function, here is a short snippet of how it works https://en.wikibooks.org/wiki/C_Programming/Simple_input_and_output#Input_using_scanf.28.29
you just have to provide the data type (i.e. %s for string) and a memory address. This can be saved via a pointer and you can pass that to your AddNumber() function.
Hope this helps!

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;
}

Resources