Makes integer from pointer without a cast - c

I'm writing a code to manipulate a linked list. But It won't compile because on line 36 i'm making an integer from a pointer without a cast. I'm not sure why this is happening. But it's affecting my function "Ins" which puts new characters into my list. Let me know what you think.
Please ignore functions del, fde, pst, prl, pcr, ppr, and psu. I haven't gotten to those yet, they shouldn't get in the way. Thanks
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MIN_LENGTH 4
#define MAX_LENGTH 11
struct node{
char list;
int count;
struct node *next;
};
typedef struct node Node;
typedef Node *ListNode;
void ins(ListNode *ptr, char value);
int main(void){
ListNode startPtr = NULL;
char com[MIN_LENGTH];
char cho[MAX_LENGTH];
while(strcmp(com, "end") != 0){
printf("Command? ");
scanf("%s", &com);
if(strcmp(com, "ins") == 0){
scanf("%s", &cho);
ins(&startPtr, cho);
printf("%s", cho);
}
else if(strcmp(com, "del") == 0){
// del();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strcmp(com, "fde") == 0){
// fde();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strcmp(com, "pst") == 0){
// pst();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strcmp(com, "prl") == 0){
// prl();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strcmp(com, "pcr") == 0){
// pcr();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strcmp(com, "ppr") == 0){
// ppr();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strcmp(com, "psu") == 0){
// psu();
scanf("%s", &cho);
printf("%s\n", cho);
}
else if(strlen(com) >= 4 || strlen(com) < 3){
printf("You have entered an incorrect command.\n");
}
}
}
void ins(ListNode *ptr, char value){
ListNode newPtr;
ListNode prevPtr;
ListNode currPtr;
newPtr = (struct node*) malloc(sizeof(Node));
if(newPtr != NULL){
newPtr->list = value;
newPtr->next = NULL;
prevPtr = NULL;
currPtr = *ptr;
while(currPtr != NULL && value > currPtr-> list){
prevPtr = currPtr;
currPtr = currPtr->next;
}
if(prevPtr == NULL){
newPtr->next = *ptr;
*ptr = newPtr;
}
else{
prevPtr->next = newPtr;
newPtr->next = currPtr;
}
}
else{
printf("No memory available\n");
}
}
void del(){
}
void fde(){
}
void pst(){
}
void prl(){
}
void pcr(){
}
void ppr(){
}
void psu(){
}

You have cho as a char array, you have function ins accepting two parameters, the second being a char.
Then you try to call function ins with the second parameter being cho. As cho is a char array, its name is considered to be equivalent to a pointer. So you are calling ins with the second parameter being a pointer, whereas that function expects a char, which is an integer type. You cannot reasonably expect the compiler to convert that pointer to that char.

if you need to store strings, you can read here:
you need to change your structure to:
struct node{
char *list;
then change method:
void ins(ListNode *ptr, char *value);
then change insert logic:
newPtr->list = (char*)malloc(strlen(value)+1); // NOTE: dont forget to free this memory
memcpy(newPtr->list, value, strlen(value)+1);
then, you have problem:
while(currPtr != NULL && value > currPtr-> list)
I don't understand what you're trying to compare here, if you need to compare strings - use strcmp here instead of >
if you need to store individual chars, read here:
change you insertion logic to:
char *tcho = cho;
while (!*tcho) {
ins(&startPtr, *tcho);
tcho++;
}

Declare your struct node to contain a char*,
struct node{
char* list;
int count;
struct node *next;
};
Change your ins() function declaration,
void ins(ListNode *ptr, char* value);
Call ins() with correct parameters,
main(void) {
//...
ins(&startPtr, cho);
//...
}
define your ins() function to allocate space for the data string passed,
void ins(ListNode *ptr, char* value){
//...
newPtr->list = strdup(value);
//...
}
You have three pointers declared in ins(), but typical single linked list inserts only need two, one to hold the new node, and one to hold the iterator to scan for the end of the list,
ListNode newPtr;
ListNode prevPtr; //we will omit this
ListNode currPtr;
After looking a little closer, the newPtr is your newly allocated list Node which you malloc, and check for successful malloc (good). And you seem to be using prevPtr and currPtr as a way to walk the list looking for the end of the list (often called the tail, while the front of the list is often called the head). This is a workable solution, but you can simplify it.
Here is a function to construct a new Node,
ListNode NodeNew(char* value)
{
ListNode newPtr;
if( (newPtr = (struct node*) malloc(sizeof(Node))) == NULL )
{
printf("ENOMEM memory available\n");
return newPtr=NULL;
}
newPtr->list = strdup(value);
newPtr->next = NULL;
newPtr->count = 0;
return newPtr;
}
And here is a simpler list insert,
void ins(ListNode *head, char* value)
{
ListNode newPtr;
ListNode prevPtr;
ListNode currPtr;
if( !(newPtr = NodeNew(value)) )
{
return;
}
if(*head == NULL)
{
*head = newPtr;
}
else
{
for( currPtr=*ptr; currPtr->next != NULL; )
{
currPtr = currPtr->next;
}
currPtr->next = newPtr;
}
}
And you want to implement the list print (prl),
void prl(ListNode head){
ListNode currPtr;
for( currPtr=head; currPtr != NULL; )
{
printf("n:%s\n",currPtr->list);
currPtr = currPtr->next;
}
}

Related

How can I insert/add and delete a string in a list through a function in C?

It seems that my code isn't working because I cannot add any string to the list. It seems like the list remains empty. After every input of a string like "asd" or a single character, the message that appears every time is:
List is empty
Also, I don't know if the 'delete' function could work, because the 'insert' function isn't working.
Here's my code(It is a bit long):
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct listnode
{
char data[100];
listnode *nextPtr;
};
Here is my insert function. PS: I want to insert names so they can be alphabetically ordered.
void insert(struct listnode *strPtr, char value[])
{
struct listnode *previousPtr, *currentPtr, *newPtr;
newPtr=(listnode*)malloc(sizeof(listnode));
strcpy(newPtr->data,value);
newPtr->nextPtr=NULL;
previousPtr=NULL;
currentPtr=strPtr;
if(newPtr!=NULL)
{
while(currentPtr!=NULL && strcmp(currentPtr->data,value)>0)
{
previousPtr=currentPtr;
currentPtr=currentPtr->nextPtr;
}
if(previousPtr==NULL)
{
newPtr->nextPtr=strPtr;
strPtr=newPtr;
}
else
{
previousPtr->nextPtr=newPtr;
newPtr->nextPtr=currentPtr;
}
}else printf("%s was not inserted. Insuffiecient memory!",value);
}
Here is my delete function
const char *del(struct listnode* strPtr, char value[])
{
struct listnode *previousPtr, *currentPtr, *tempPtr;
if(strcmp(value, strPtr->data)==0) /*if the first node shall be
deleted*/
{
/*delete node*/
tempPtr=strPtr;
strPtr=strPtr->nextPtr;
free(tempPtr);
return value;
}
else
{
previousPtr=strPtr;
currentPtr=strPtr->nextPtr;
while(currentPtr!=NULL && strcmp(value, currentPtr->data)!=0)
{
previousPtr=currentPtr;
currentPtr=currentPtr->nextPtr;
}
if(currentPtr!=NULL)
{
tempPtr=currentPtr;
previousPtr->nextPtr=currentPtr->nextPtr;
free(tempPtr);
return value;
}
}
return '\0';//daca nu s-a gasit nodul
}
void instructions(void)
{
printf( "Options:\n"
" 1 to insert a name in the list.\n"
" 2 to delete a name from the list.\n"
" 3 to exit.\n" );
}
void printList(struct listnode *currentPtr)
{
if(currentPtr==NULL)
printf("List is empty\n");
else
{
printf("List is:\n");
while(currentPtr!=NULL)
{
printf("%s -->",currentPtr->data);
currentPtr=currentPtr->nextPtr;
}
}
}
int Empty(struct listnode *strPtr)
{
return strPtr == NULL;
}
int main()
{
struct listnode* startPtr;
startPtr=NULL;
int optiune;
char nume[100];
instructions();
printf("->> ");
scanf("%d",&optiune);
Here is the menu
while(optiune!=3)
{
switch(optiune)
{
case 1:
printf("Enter name:");
fflush(stdin);
gets(nume);
insert(startPtr, nume);
printList(startPtr);
break;
case 2:
printf("Search by name to delete from list:");
gets(nume);
if(!Empty(startPtr))
{
if(del(startPtr, nume))
{
printf("%s a fost sters din lista!\n");
printList(startPtr);
}else printf("%s nu a fost gasit!\n",nume);
}else
printf("List is empty!");
break;
case 3:
break;
default:
printf("No such option!\n\n");
instructions();
break;
}
printf("\n->> ");
scanf("%d",&optiune);
}
printf("Execution stopped.\n" );
return EXIT_SUCCESS;
}
I think I got it to work.
First thing I changed in your code was defining your struct as a typdef.
typedef struct{
char data[100];
struct listnode *nextPtr;
}listnode;
This is how I learned and it makes it easier to declare variables of this struct type, since we can just type "listnode" instead of "struct listnode" all the time.
Since you didn't give us the full code, I had to remove some things so I could compile it. As you are just asking why the list remains empty after the "insert" function I think this is fine for you.So here's the "main()" and "printlist()" functions that I used:
void printList(listnode *strPtr){
listnode *currentPtr = malloc(sizeof(listnode));
//Setting the ptr to run the list
currentPtr = strPtr;
if(strPtr == NULL) printf("Fail\n");
//Printing the list,while next is different than NULL keep going
printf("\nListing:\n");
while(currentPtr->data != NULL){
printf("%s\n",currentPtr->data);
currentPtr = currentPtr->nextPtr;
}
}
int main(){
char nume[128];
listnode *startPtr = NULL;//Initializing the fisrt ptr
//Reading the name
printf("Enter name:\n");
scanf("%s",nume);
//Inserting and printing the list
insert(&startPtr,nume);
insert(&startPtr,"Hello");
printList(startPtr);
return 0;
}
Some pretty basic stuff. Now to the main point:
As our friends told us in the comments, in C, the pointer is passed by value. It means that whatever changes you make in the function, it will not modify the startPtr variable in main().
To fix that all he have to do is to add one extra '*' on the function parameters. This means that we are now passing the strPtr argument by reference.
Here's the final function:
void insert(listnode **strPtr,char value[]){
listnode *previousPtr, *currentPtr,*newPtr;
//Allocating the nodes
newPtr = malloc(sizeof(listnode));
currentPtr = malloc(sizeof(listnode));
//Initializing the new node and setting the currentPtr
strcpy(newPtr->data,value);//Copying the name to the new node
newPtr->nextPtr = NULL;
currentPtr = strPtr;
//Previous is NULL
previousPtr = NULL;
if(newPtr != NULL){
//If there's already a node in the list let's find the right location
//For the new one(sorting)
while(currentPtr != NULL && strcmp(currentPtr->data,value) > 0){
previousPtr = currentPtr;
currentPtr = currentPtr->nextPtr;
}
//If previous is NULL than this is the first node,no while iterations
//Note:strPtr is passed by reference,extra '*' needed
if(previousPtr == NULL){
newPtr->nextPtr = *strPtr;
*strPtr = newPtr;
}else{
previousPtr->nextPtr = newPtr;
newPtr->nextPtr = currentPtr;
*strPtr = newPtr;
}
}else{
printf("%s was not inserted. Insuffiecient memory!",value);
}
}
Note that we are also using an extra '*' when setting the newPtr to strPtr.This will modify the actual variable startPtr from main().
From that I hope you can also fix the delete function!
Don't forget to free the memory!
Also, don't forget to comment your code. It's really important to help you and other people to understand it, no matter how easy it might be!
Cheers!

C structs and linked lists struggle

So, we just started learning linked lists and data structures in my online class, but I have been really struggling with this topic. I have a general understanding of pointers but when you combine everything, I get completely lost.
So for this program, I am supposed to process employee data and access it through the use of structs and pointers. However, I think I am not passing the correct values into the functions because the data is not being saved and I can't access it. Any help would be appreciated.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct address {
char street[49];
char city[29];
char state[2];
char zip[5];
};
struct data{
char name[39];
struct address addy;
float salary;
struct data *next;
} emp;
void LIST(struct data* head);
void INSERT(struct data* head, char* name, struct address addr, float salary);
void DELETE(char* name, struct data* head);
void EDIT(struct data* head, char* name, struct address addr, float salary);
void CALCPAYROLL(struct data* head);
void HELP();
int main()
{
char input[15];
int quitter = 1;
struct data *head = NULL;
head = malloc(sizeof(emp));
if (head == NULL){
return 1;
}
while(quitter == 1)
{
printf(" enter command: \n");
fgets(input,15, stdin);
input[strlen(input) -1] = '\0';
if((strcmp(input, "List") == 0) || (strcmp(input, "list") == 0))
{
LIST(head);
}
if((strcmp(input, "Insert") == 0) || (strcmp(input, "insert") == 0))
{
scanf("%s-%s-%s-%s-%s-%f", head->name, head->addy.street, head->addy.city, head->addy.state, head->addy.zip, &head->salary);
INSERT(head, head->name, head->addy, head->salary);
}
if ((strcmp(input, "Delete") == 0) || (strcmp(input, "delete") == 0))
{
DELETE(head->name, head);
}
if ((strcmp(input, "Edit") == 0) || (strcmp(input, "edit") == 0))
{
EDIT(head, head->name, head->addy, head->salary);
}
if ((strcmp(input, "Payroll") == 0) || (strcmp(input, "payroll") == 0))
{
CALCPAYROLL(head);
}
if ((strcmp(input, "Help") == 0) || (strcmp(input, "help") == 0))
{
HELP();
}
if ((strcmp(input, "Quit") == 0) || (strcmp(input, "quit") == 0))
{
printf("============\nGood bye!\n");
quitter = 0;
}
}
return 0;
}
void LIST(struct data* head)
{
struct data* temp = head;
while (temp) {
printf("%s\n%s\n%s, %2s %5s\n%9.2f\n-----\n", temp->name, temp->addy.street, temp->addy.city, temp->addy.state, temp->addy.zip, temp->salary);
temp = temp->next;
printf("%s\n%s\n%s, %2s %5s\n%9.2f\n-----\n", temp->name, temp->addy.street, temp->addy.city, temp->addy.state, temp->addy.zip, temp->salary);
temp = temp->next;
}
}
void INSERT(struct data* head, char* name, struct address addr, float salary)
{
struct data* newEmployee = NULL;
newEmployee = (struct data*)malloc(sizeof(emp));
strcpy(newEmployee->name, head->name);
newEmployee->salary = head->salary;
strcpy(newEmployee->addy.street, head->addy.street);
strcpy(newEmployee->addy.city, head->addy.city);
strcpy(newEmployee->addy.state, head->addy.state);
strcpy(newEmployee->addy.zip, head->addy.zip);
struct data* temp = head;
while(temp->next && temp->next->name > newEmployee->name)
{
temp = temp->next;
}
newEmployee->next = temp->next;
temp->next = newEmployee;
}
void DELETE(char* name, struct data* head)
{
char del[39];
scanf("%39s", del);
struct data * toBeDeleted = NULL;
struct data * temp = head;
while (strcmp(del, temp->name) == 0)
{
strcpy(temp->next->name, temp->name);
temp->addy = temp->next->addy;
temp->salary = temp->next->salary;
toBeDeleted = temp->next;
temp->next = temp->next->next;
free(toBeDeleted);
printf("RECORD DELETED\n");
}
temp = temp->next;
printf("RECORD NOT FOUND\n");
}
void EDIT(struct data* head, char* name, struct address addr, float salary)
{
char edit[39];
scanf("%39s", edit);
struct data* temp = head;
while (strcmp(edit, temp->name) == 0)
{
temp->addy = addr;
temp->salary = salary;
printf("RECORD EDITED\n");
return;
}
temp = temp->next;
printf("RECORD NOT FOUND\n");
}
void CALCPAYROLL(struct data* head)
{
struct data* temp = head;
float total;
while (temp)
{
total += temp->salary;
temp = temp->next;
}
printf("total payroll: %f", total);
}
void HELP()
{
printf("commands:\n");
printf("List - shows the list of employees\n");
printf("Insert - Creates a new employee record\n");
printf("Delete - Deletes an existing employee record\n");
printf("Edit - Modifies the contents of an employee record\n");
printf("Payroll - Calculates and displays the total payroll\n");
printf("Help - Displays the set of available commands\n");
printf("Quit - Prints the message ""good bye!"" and exits the program" );
}
First of all, I have to commend you for a very neat presentation. The code is readable and easy to follow. The only fault I find with it is that all uppercase names are usually reserved for macros and constants declared with #define.
Here:
struct data{
char name[39];
struct address addy;
float salary;
struct data *next;
} emp; // declaring a variable at the same time as the structure? Not very nice.
I see an issue that happens when you create your first list item, the head. Insert must have a way to modify the head parameter. This needs an extra level of indirection. INSERT should also return an error code, in case malloc fails, a common way to do this is to return a negative value (-1) on error.
void INSERT(struct data* head, char* name, struct address addr, float salary)
// should be
int INSERT(struct data** head, char* name, struct address addr, float salary)
You'll have to change the logic a little bit to set head with the newly allocated buffer when head is NULL on entry. Calling INSERT then becomes.
if (INSERT(&head, name, &addr, salary) < 0)
{
// error !
}
I see a problem in data allocation in INSERT.
struct data* newEmployee = NULL;
//newEmployee = (struct data*)malloc(sizeof(emp)); // ?? you allocate a struct data, what's emp?
// should read
newEmployee = (struct data*)malloc(sizeof(struct data));
DELETE and EDIT do not work. They cannot find the employee as written. You should consider using a find() function, something like this:
data* FindEmployeeData(data* head, const char* name)
{
while (head)
{
if (strcmp(head->name, name) == 0)
break;
head = head->next;
}
return head;
}
This could be a time saver when writing new operations on employees.
In INSERT:
while(temp->next && temp->next->name > newEmployee->name)
I thought strings were supposed to be compared with strcmp()...
In DELETE: same as for INSERT, the function could change the head of the list
int DELETE(data** head, const char* name); // returns -1 on error.
Here:
scanf("%s-%s-%s-%s-%s-%f", head->name, head->addy.street, head->addy.city, head->addy.state, head->addy.zip, &head->salary);
Terrible things will happen when the user enters a name, address, state, street, city or zip that are too long for the space you have allocated.
You can't access to the data because in INSERT function head must be a double pointer, because when you want to insert something in the head of a linked list you have to change the address stored in head. In your code you're modifying a copy of head. remember that in C everything is passed for value. This mean that for modify the address content in a pointer you have to pass the address of the pointer at your function.

Insert Node into BST on a loop in C

I'm trying to insert into my BST but I'm struggling with creating a loop out of it.
The code works when I insert one by one, but when I try to put it into a loop it doesn't insert correctly.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h> // for strcmp()
#include <ctype.h> // for toupper()
typedef struct BstNode{
//char name[20];
// int data;
struct BstNode* left;
struct BstNode* right;
char* name;
}BstNode;
typedef int (*Compare)(const char*, const char*); // makes comparisons easier
/* Returns pointer address to newly created node */
BstNode* createNode(char* name){
BstNode* newNode = (BstNode*)malloc(sizeof(BstNode)); // Allocates memory for the newNode
newNode->name = name; // newNode->data is like newNode.data
newNode->left= NULL;
newNode->right = NULL;
return newNode;
}
//insert node into Tree recursively
BstNode* insertNode(BstNode* node, char* name, Compare cmp){
int i;
/* char *s1 = node->name;
char *s2 = name;
printf("s1: %s, s2: %s\n", s1,s2);
i = strcmp(s1, s2); // if =1, s1 is greater
printf("i: %d\n", i); */
if(node == NULL){// if tree is empty
// printf("inside NULL\n");
node = createNode(name);
//return node;
}
else{
i = cmp (name, node->name); // sweet
if(i == -1){
// printf("inside left\n");
node->left = insertNode(node->left, name, cmp);
//return node;
}
else if(i == 1){
// printf("inside right\n");
node->right = insertNode(node->right, name, cmp);
//return node;
}
else if(i == 0 ){ //avoid duplicates for now
// printf("inside 0\n");
printf("Name is in BST\n");
return NULL;
}
}
return node;
}
BstNode* printTree(BstNode* node){
if(node == NULL){
return NULL;
}
printTree(node->left);
printf("%s\n",node->name);
printTree(node->right);
}
int CmpStr(const char* a, const char* b){
return (strcmp (a, b)); // string comparison instead of pointer comparison
}
//void Insert(Person *root, char name[20]);
int main(){
BstNode* root = NULL; // pointer to the root of the tree
char buf[100];
char option = 'a';
while(1) {
printf("Enter employee name");
scanf("%s",buf);
printf ("Inserting %s\n", buf);
root = insertNode(root, buf, (Compare)CmpStr);
printTree(root);
}
}
I can do root = insertNode(root, name, (Compare)CmpStr)
several times in code, but if I try to loop it with user input it won't insert correctly. I'm not sure if it has to do with the fact that I'm using scanf() or root not being set correctly. I've tried using fgets() as well but I'm not too sure how to use it and keep messing that up.
Any help is appreciated.
In your loop, you always pass the same buffer to your insert function; Your createNode does not copy the content of the buffer but rather stores a reference to the (always) same buffer; Hence, changing the buffer content after insert will also change the "content" of previously inserted nodes.
I'd suggest to replace newNode->name = name in createNode with newNode->name = strdup(name). This will actually copy the passed "contents" and gives your BST control over the memory to be kept. Thereby don't forget to free this memory when deleting nodes later on.

how to add a word in the link list while also checking and updating the frequency of the word in c

I'm trying to finish one of my assignments and I have some issues. I have to make a program that uses struct to create a link list in which I have to add words. If the word is already in the linked list then I just have to update the frequency.
I already have this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct words Words;
struct words{
char *word;
int freq;
Words *next;
};
/*
Inserts a copy of newWord into the list, in lexicographical order. If newWord is already
in the list, increment the freq member of the node. The function returns a pointer to
the list.
*/
Words *addWord(Words *headPtr, char* newWord){
Words *current = headPtr;
if(headPtr == NULL)
{
current->word = newWord;
current->freq = 1;
}
else
{
while(current != NULL)
if(strcmp(headPtr->word, newWord))
{
current->freq++;
return headPtr;
}
else
{
current->word = newWord;
current->freq = 1;
}
}
return headPtr;
}
//prints the words in the list, along with the frequency of each word
void printWords(Words *headPtr){
while(headPtr != NULL)
{
printf("%s: %d", headPtr->word, headPtr->freq);
headPtr = headPtr->next;
}
}
//frees the entire list. Note: Words **headPtr since the headPtr NULL upon return
void deleteList(Words **headPtr){
Words *current = *headPtr;
Words *next;
while(current != NULL)
{
next = current->next;
free(current);
current = next;
}
*headPtr = NULL;
}
int main(){
char word[20];
Words *list = NULL;
scanf("%s", word);
while(!feof(stdin)){
list = addWord(list, word);
scanf("%s", word);
}
printWords(list);
deleteList(&list);
}
There are some problems in your code. See comments embedded into your code:
Words *addWord(Words *headPtr, char* newWord){
Words *current = (Words*) malloc(sizeof(Words)); // Don't malloc here.
// You don't know yet
// whether you need
// a new node or you
// you just need to
// update freq
if(current == NULL) // If current is NULL you have
// serious problems, i.e. you
// are out of memory.
// Did you really intended to do:
// if (headPtr == NULL)
{
current->word = newWord;
*current->next = (*headPtr);
(*headPtr) = *current; // I'm not sure what you try here
// but it seems strange
}
else
{
while(current != NULL)
if(strcmp(headPtr->word, newWord)) // This is not the way to compare
// strings. Two strings compare
// when "strcmp" returns 0.
//
// Further you don't want to
// use headPtr here.
{
current->freq++; // Use of uninitialized value
return; // Missing argument to return
}
else
{
current->word = newWord; // Use of uninitialized value
*current->next = (*headPtr); // Use of uninitialized value
(*headPtr) = *current;
}
}
// Missing return
}
Here is some code to start with:
#define WORD_SIZE 20
struct words{
char word[WORD_SIZE]; // Use a char array
int freq;
Words *next;
};
Words *addWord(Words *headPtr, char* newWord)
{
Words *current = headPtr; // Make a copy of headPtr
Words* new;
if ((current == NULL) || (strcmp(current->word, newWord) > 0))
{
// Insert in front of list
new = malloc(sizeof(Words)); // Allocate memory
if (new == NULL)
{
// oh, dear - out of memory - print an error message and exit
exit(1);
}
strncpy(new->word, newWord, WORD_SIZE); // Make sure not to overflow
// the buffer, so use strncpy
(new->word)[WORD_SIZE-1] = '\0'; // Make sure to zero terminate
new->freq = 1;
new->next = headPtr;
return new;
}
while(1)
{
int cmp = strcmp(current->word, newWord);
if(cmp == 0)
{
current->freq++;
return headPtr;
}
if(cmp < 0)
{
if ((current->next == NULL) || (strcmp(current->next->word, newWord) > 0))
{
// Add code to insert node after current
return headPtr;
}
}
else
{
// This should never happen...
printf("BAD CODE 1\n");
exit(1);
}
current = current->next;
}
}

Program crashing at looking at address of next node in list; only happens in very strange circumstances

The first time addToEnd() is called it works but the second time it crashes the program. I've been trying to debug it and found it happens when head->next happens. I'm a little confused because it's just being read, can that crash the program? If yes how can you possible itterate through the file?
It seems to work on certain values of entry but not others. If two entry's are the same and composed all of one letter it crashes. So if addToEnd(head, "aaaaaaaaa") is called then addToEnd(head, "aaaaaaaaa") is called the program crashes but if addToEnd(head, "aaaaaaaaa") then addToEnd(head, "aaaaaaaab") it is fine.
Here is 100% all of the code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct node
{
char entry[21];
struct node* next;
} node;
void readDic();
void reverStr(char *str);
bool isInDic(char *reversed);
void addToEnd(node* head, char entry[21]);
unsigned int searchAndDestroy(node **head, char *entry);
void printList(node* head);
int main()
{
printf("Hello\n");
readDic();
printf("Goodbye!");
return EXIT_SUCCESS;
}
void readDic()
{
FILE* words;
char singleLine[21];
words = fopen("words.txt", "r");
node* head = malloc(sizeof(node));
fscanf(words, "%20s", head->entry);//need to do this initially
head->next = NULL;
printf("here 0");
printf("here 0.1");
if(words == NULL)
exit(EXIT_FAILURE);
printf("here 0.5");
while(fscanf(words, "%20s", singleLine) == 1)assigned input terms
{
printf("\nhere 0.6\n|%s|", singleLine);
addToEnd(head, singleLine);//problem here
printf("here 0.7");
reverStr(singleLine);
printf("here 1");
if(isInDic(singleLine)){
printf("here 2");
searchAndDestroy(&head, singleLine);
printf("here 3");
}
}
printf("here 4");
fclose(words);
printList(head);
printf("here 5");
}
//http://stackoverflow.com/questions/198199/how-do-you-reverse-a-string-in-place-in-c-or-c
/* PRE: str must be either NULL or a pointer to a
* (possibly empty) null-terminated string. */
void reverStr(char *str)
{
char temp, *end_ptr;
/* If str is NULL or empty, do nothing */
if(str == NULL || !(*str))
return;
end_ptr = str + strlen(str) - 1;
/* Swap the chars */
while( end_ptr > str )
{
temp = *str;
*str = *end_ptr;
*end_ptr = temp;
str++;
end_ptr--;
}
}
bool isInDic(char* reversed)
{
FILE* words;
char singleLine[21];
words = fopen("words", "r");
if(words == NULL)
exit(EXIT_FAILURE);
while(fscanf(words, "%20s", singleLine) == 1)//the length of the string has to be 1 less than declared size for the newline character
{
//printf("singline: %s reversed: %s\n", singleLine, reversed);
if(strcmp(singleLine, reversed) == 0)//strcmp returns 0 if both cstrings are equal
return true;
}
fclose(words);
return false;
}
void addToEnd(node* head, char entry[21])
{
printf("hi");
//printf("\naddress of next %p\n", (void *)head->next);
while(head->next != NULL)//just reading head->next screws it up
head = head->next;
printf("in addToEnd 2\n");
node* last = (node*)malloc(sizeof(node));
printf("in addToEnd 3\n");
head->next = last;
printf("in addToEnd 4\n");
strcpy(last->entry, entry);
printf("in addToEnd 5\n");
last->next = NULL;
printf("in addToEnd 6\n");
}
unsigned int searchAndDestroy(node **head, char *entry)
{
unsigned int count = 0;
while(*head)
{
node *del;
if(strcmp((*head)->entry, entry))
{ //this node stays
head = &(*head)->next;
continue;
}
/* this node goes
at this point head MUST point to the pointer that points at the node to be deleted
*/
del = *head;
*head = (*head)->next;
free(del);
count++;
}
return count; //number of nodes deleted
}
void printList(node* head)
{
printf("\nprinting everything\n");
if(head != NULL)
{
while(head->next != NULL)
{
printf("%s", head->entry);
head = head->next;
}
printf("%s", head->entry);
}
}
The answers are correct that head is being set to null but I don't see where?
When you create head, you don't set head->next to NULL.
One of three things:
If head is NULL this code will crash at the line you mention.
If last->entry is defined as char* you need to say 'last->entry = strdup(entry)
If the sizeof last->entry is less than 21, your strcpy will overflow it which
will result in undefined behavior.
Ok, with your recent edit, I assert that head is null or garbage when you call this function the second time.

Resources