C - Doubly Linked List always null - c

I am writting a program on doubly linked list with the following data structure:
typedef struct telephoneBookNode {
int id;
char name[NAME_LENGTH];
char telephone[TELEPHONE_LENGTH];
struct telephoneBookNode * previousNode;
struct telephoneBookNode * nextNode;
} TelephoneBookNode;
typedef struct telephoneBookList {
TelephoneBookNode * head;
TelephoneBookNode * tail;
TelephoneBookNode * current;
} TelephoneBookList;
In the following function, I read data from a text file to the linked list, the file content look like this:
/*100, Alice, 0411112222
101, Bob, 0411112222
102, Ali, 0411112223*/
TelephoneBookList * commandLoad(char* fileName) {
TelephoneBookList *(*createList)(TelephoneBookNode*, char[]) = createTelephoneBookList;
char entry[100], *temp1, *temp2;
TelephoneBookList* aList = NULL;
TelephoneBookNode* aNode = NULL;
FILE* telephoneListFile = NULL;
int countEntry = 0;
Boolean check;
telephoneListFile = fopen(fileName, "r");
if (!telephoneListFile)
return NULL;
else {
while (fgets(entry, 100, telephoneListFile)) {
temp2 = strcpy(temp2, entry);
temp1 = strtok(entry, "\n");
check = addressBookEntryCheck(temp1);
if (!check)
return NULL;
else
//here I pass aNode pointer to the below function
aList = (*createList)(aNode, temp2);
}
fclose(telephoneListFile);
printf("printed"); //This line is reached when program complied
return aList;
}
}
This is the function to create the list, problem may be here: it doesnot add new node to the list, it just replaces the first node with the new one. Finally, the linked list only has 1 record which was the last one in text file. How can I fix the code? Thank you!
TelephoneBookList * createTelephoneBookList(TelephoneBookNode* node, char entry[]) {
TelephoneBookList* aList = malloc(sizeof *aList);
TelephoneBookNode* aNode = (TelephoneBookNode*) malloc(sizeof *aNode);
char *tokens;
tokens = strtok(entry, ", ");
aNode->id = atoi(tokens);
tokens = strtok(NULL, ", ");
strcpy(aNode->name, tokens);
tokens = strtok(NULL, ", ");
strcpy(aNode->telephone, tokens); //Just assigning values to a node
//program always go to this block, means `node` is always null
if (node == NULL) {
aNode->nextNode = NULL;
aNode->previousNode = NULL;
node = aNode;
aList->current = node;
aList->head = node;
aList->tail = node;
}
else { //This block is not reached
while (node->nextNode)
node = node->nextNode;
node->nextNode = aNode;
aNode->previousNode = node;
aList->tail = node->nextNode;
}
return aList;
}
This is the function to check entry:
Boolean addressBookEntryCheck(char entry[]) {
char *tokens;
tokens = strtok(entry, ", ");
if(!tokens || strlen(tokens) < 1 || strlen(tokens) > 3)
return FALSE;
else {
if (!isNumber(tokens))
return FALSE;
else {
tokens = strtok(NULL, ", ");
if (!tokens)
return FALSE;
else
{
tokens = strtok(NULL, ", ");
if (!tokens)
return FALSE;
else if (!isNumber(tokens) || strlen(tokens) != 10)
return FALSE;
else
return TRUE;
}
}
}
}

Every time you call
createTelephoneBookList
you create a new list
TelephoneBookList* aList = malloc(sizeof *aList);
You also copy to an uninitialized pointer
temp2 = strcpy(temp2, entry);
I would suggest you create one function to create the list header, one function to add new items e.g.
aList = createList()
while (fgets(entry,sizeof(entry),fp)!=NULL)
{
if (!addEntry(aList,entry))
{
fprintf(stderr, "failed additem item %s\n", entry);
}
}
...
In addEntry parse the string
int id = 0;
char name[NAME_LENGTH];
char telephone[TELEPHONE_LENGTH];
p = strtok(entry, ","); // id
if (p != NULL)
{
id = atoi(p);
p = strtok(NULL, ","); // name, store to temporary string
if (p != NULL )
{
strcpy(name,p);
p = strtok(NULL, ","); // telephone number, store to temporary string
if ( p != NULL )
{
strcpy(telephone,p);
// here you can allocate the new node
}
}
}
// disclaimer omitted checks for length etc which any good program should have. also make sure you have room for \0
if any of the strtok above fail return 0 otherwise allocate a new entry
TelephoneBookNode* aNode = malloc(sizeof(TelephoneBookNode));
aNode->id = id;
strcpy(aNode->name, name);
strcpy(aNode->telephone, telephone);
Then add to your aList

//program always go to this block, means `node` is always null
if (node == NULL) {
....
This is because the caller of the function passed aNode and it never changes within that loop. So it will always pass same value of aNode which is NULL.
I haven't looked at the logic of your code in details, but I think you may want to pass aList->head or rather you already pass aList so just use that.

Related

Changing the variable assigned as a pointer to the parameter in C

Firstly I'm using C language. I want a variable that I refer to as a parameter to change outside the function when it is changed inside the function. But the problem is that the variable is of type linked list and I want to add to the linked list.
So what I'm trying to do is add the linked list outside the function with the save function.
Is this possible? If possible how can I do it? Sorry for the English, I used a translator.
My codes:
#include <stdio.h>
#include <stdlib.h>
typedef struct NS
{
char * name;
char * value;
struct NS * next;
} n_t;
void save(char * name, char * value, n_t ** item)
{
n_t * link = malloc(sizeof(struct NS));
link->name = name;
link->value = value;
link->next = NULL;
n_t ** pointer = NULL;
if (*item == NULL)
*item = link;
pointer = &(*item);
while ((*pointer)->next != NULL)
*pointer = (*pointer)->next;
(*pointer)->next = link;
}
int main()
{
n_t * mem = NULL;
save("hello", "val123", &mem);
printf("-> %s\n", mem->value);
save("abc", "hello", &mem);
printf("-> %s\n", mem->value);
printf("-> %s\n", mem->next->value);
return 0;
}
The output for the first arrow (->) should be "val123"
The result that should also appear in the second arrow output is "val123"
The result that should appear in the third arrow output is "hello"
All this part of the function
n_t ** pointer = NULL;
if (*item == NULL)
*item = link;
pointer = &(*item);
while ((*pointer)->next != NULL)
*pointer = (*pointer)->next;
(*pointer)->next = link;
does not make sense. For example in the while loop
while ((*pointer)->next != NULL)
*pointer = (*pointer)->next;
there is rewritten the value of the passed original pointer to the function by reference,
The function can look the following way
int save( n_t **item, char *name, char *value )
{
n_t * link = malloc( sizeof( struct NS ) );
int success = link != NULL;
if ( success )
{
link->name = name;
link->value = value;
link->next = NULL;
while ( *item != NULL ) item = &( *item )->next;
*item = link;
}
return success;
}
In general you need to dynamically allocated memory to store copies of the strings name and value in the nodes of the list.
The body of the function main can look like
n_t * mem = NULL;
save( &mem, "hello", "val123" );
printf("-> %s\n", mem->value);
save( &mem, "abc", "hello" );
printf("-> %s\n", mem->next->value );
printf("-> %s\n", mem->next->next->value);
You're really only missing a single return when the list is empty still:
if (*item == NULL) {
*item = link;
return;
}

Insert a string in a single linked list

I am trying to insert a string into a linked list of other strings.
The goal is to have the user enter whatever string they want (str_insert). Then, the user has to enter after which word they want to insert the string (new_node).
Unfortunately, the code manages to insert the word but it only ever inserts it in second position. The function used to insert the word is called insertion.
typedef struct dll {
char data;
int count;
struct dll* next;
} dll;
typedef struct dictionary {
dll * data;
struct dictionary* next;``
struct dictionary* prev;
} dictionary;
dll* entry(){
char data = getc(stdin);
if (data != '\n'){
dll* curr = create_dico(data);
curr->next=entry();
return curr;
}
return NULL;
}
dictionary* insertion(dictionary *dico) {
printf("Please enter the string you want to insert in your already
existing list: \n");
dictionary * str_insert = malloc(sizeof(dictionary));
str_insert->data = entry();
str_insert->next = NULL;
printf("Please enter after which word you would like to insert the
previous entry: \n");
dictionary* new_node =(dictionary*)malloc(sizeof(dictionary));
new_node->data = entry();
new_node->next = dico->next;
new_node->prev = dico;
if (dico->next != NULL) {
str_insert->next = dico->next;
dico->next = str_insert;
}
}
I managed to make it work by implementing another function that compared the input with the already existing list.
Here is the final result:
dictionary* research(dictionary* dico, dll *search){
dll *save = search;
while (dico != NULL) {
dll *tmp = dico->data;
search = save;
while(tmp->data == search->data && tmp->next != NULL && search->next != NULL){
tmp = tmp->next;
search = search->next;
}
if(tmp->data == search->data){
return dico;
}
dico = dico->next;
}
return NULL;
}
void insertion(dictionary *dico) {
printf("Please enter the string you want to insert in your already existing list: \n");
dictionary * str_insert = malloc(sizeof(dictionary));
str_insert->data = entry();
str_insert->next = NULL;
printf("Please enter after which word you would like to insert the previous entry: \n");
dictionary* search =(dictionary*)malloc(sizeof(dictionary));
search->data = entry();
search = research(dico, search->data);
if (search == NULL){
printf("Sorry, this word isn't in the list.\n");
}
else{
if(search->next != NULL){
search->next->prev = str_insert;
}
str_insert->next = search->next;
search->next = str_insert;
str_insert->prev = search;
}
}

Linked lists Node being overwritten incorrectly

I am creating a music library program in C using linked lists. Users should be able to create a node containing: song name, artists, and genre. These nodes should be sorted alphabetically by song name.
I am having trouble, however, creating new nodes without affecting my current head node. The picture below will illustrate this better. I call a line of code that is meant to receive a new value from the user and it resets the song name value in the head node and I have no clue why. Any help is appreciated.
(Problem occurs between Test Point 1 and Test Point 2 printf statements, I intend for Test Point 2 to display "zz" instead of "aa").
Code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
typedef struct node
{
char* artist;
char* songName;
char* genre;
struct node* nextNode;
} Node;
const int MAX_LENGTH = 1024;
void inputStringFromUser(char prompt[], char s[], int arraySize);
int main(void)
{
// Declare the head of the linked list.
// ADD YOUR STATEMENT(S) HERE
Node* head = NULL;
// Announce the start of the program
printf("Personal Music Library.\n\n");
printf("%s",
"Commands are I (insert), D (delete), S (search by song name),\n"
"P (print), Q (quit).\n");
char response;
char input[MAX_LENGTH + 1];
char input4[MAX_LENGTH + 1];
char input2[MAX_LENGTH + 1];
char input3[MAX_LENGTH + 1];
inputStringFromUser("\nCommand", input, MAX_LENGTH);
response = toupper(input[0]);
if (response == 'I') {
//insert a node code
char* promptName = "Song name";
char* promptArtist = "Artist";
char* promptGenre = "Genre";
char* newName;
char* newArtist;
char* newGenre;
//test points for the songname in the head node
if (head != NULL) {
printf("Test Point 1: %s\n", head->songName);
}
inputStringFromUser(promptName, input4, MAX_LENGTH);
newName = input4;
if (head != NULL) {
printf("Test Point 2: %s\n", head->songName);
}
inputStringFromUser(promptArtist, input2, MAX_LENGTH);
newArtist = input2;
inputStringFromUser(promptGenre, input3, MAX_LENGTH);
newGenre = input3;
//if it is the first node then just create a node then assign the values to the user input
if (head == NULL) {
head = malloc(sizeof(Node));
head->artist = newArtist;
head->genre = newGenre;
head->songName = newName;
} else {
//sorts through list until it finds the first node where the song name is not alphabetically ahead
//of the current entered name
Node* current = head;
while (strcmp(current->songName, newName) == 1) {
//if the loop goes to the end of the list place the new node at the end
if (current->nextNode != NULL) {
current = current->nextNode;
} else {
current->nextNode = malloc(sizeof(Node));
current = current->nextNode;
current->artist = newArtist;
current->genre = newGenre;
current->songName = newName;
break;
}
}
//if the loop finds the correct place for a node it shifts all the other ones down
//then create a new end node
char* tempName = " ";
char* tempName2 = " ";
char* tempArtist = " ";
char* tempArtist2 = " ";
char* tempGenre = " ";
char* tempGenre2 = " ";
tempName = current->songName;
tempArtist = current->artist;
tempGenre = current->genre;
current->artist = newArtist;
current->genre = newGenre;
current->songName = newName;
while (current->nextNode != NULL) {
current = current->nextNode;
tempName2 = current->songName;
tempArtist2 = current->artist;
tempGenre2 = current->genre;
current->songName = tempName;
current->artist = tempArtist;
current->genre = tempGenre;
tempName = tempName2;
tempGenre = tempGenre2;
tempArtist = tempArtist2;
}
current->nextNode = malloc(sizeof(Node));
current = current->nextNode;
current->songName = tempName;
current->artist = tempArtist;
current->genre = tempGenre;
}
}
}
// Support Function Definitions
// Prompt the user for a string safely, without buffer overflow
void inputStringFromUser(char prompt[], char s[], int maxStrLength)
{
int i = 0;
char c;
printf("%s --> ", prompt);
while (i < maxStrLength && (c = getchar()) != '\n')
s[i++] = c;
s[i] = '\0';
}
This is one example of what's wrong:
current->genre = newGenre;
You saving the value of the pointer newGenre (which is pointing to input3). So all nodes will end pointing to same object, i.e. when changing input3 all nodes will point the new value.
Try:
typedef struct node
{
char artist[MAX_LENGTH + 1];
char songName[MAX_LENGTH + 1];
char genre[MAX_LENGTH + 1];
struct node* nextNode;
} Node;
and then do:
strcpy(current->genre, newGenre);
to copy the value into the node.
Alternatively, you can keep the pointers and use dynamic memory allocation.

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

Pointer NULL issues

void addWord(char *word, bucket **bkt, int size)
{
bucket *node, *auxNode;
if(findWord(word, bkt[hash(word, size)]) == 1)
{
return;
}
node = (bucket*) malloc (sizeof(bucket));
node->data = (char*) malloc (strlen(word) * sizeof(char));
memset(node->data, 0, strlen(word));
sprintf(node->data, "%s", word);
if(*bkt == NULL)
{
node->next = NULL;
*bkt = node;
}
else
{
auxNode = (bucket*) malloc (sizeof(bucket));
auxNode = *bkt;
while(auxNode->next != NULL)
{
auxNode = auxNode->next;
}
node->next = NULL;
auxNode->next = node;
}
}
int main(int argc, char **argv)
{
............
bkt = (bucket**) malloc (*sizeHash * sizeof(bucket*));
for(i = 0 ; i < (*sizeHash) ; i++)
{
printf("%d\n", i);
bkt[i] = NULL;
}
.........
if(bkt[hash(pch, *sizeHash)] == NULL)
{
printf("NULL: %s -> %d\n",pch, hash(pch, *sizeHash));
bkt[hash(pch, *sizeHash)] = NULL;
}
addWord(pch, &bkt[hash(pch, *sizeHash)], *sizeHash);
Every time enters in that if, that means that the node send is NULL; But after two inserts, the third although enters in that if, in addWord it arrives not NULL(i put a printf before findWord). I don't understand why this happens. This is a hash table, hash() is djb2 of Dan Bernstein. Could somebody tell my why the NULL pointer isn't send in addWord()?
Surely this:
if(findWord(word, bkt[hash(word, size)]) == 1)
is supposed to be this:
if(findWord(word, *bkt) == 1)
?
Remember that the bkt inside addWord is the &bkt[hash(pch, *sizeHash)] from main: it already points to the hash-entry for word.

Resources