I start learning linked lists.
My problem is that the conditional statement is not working. Here is the problem code.
'''
Node* search_word(Node* head, Word target)
{
Node*p=head;
while(p != NULL)
{
if(p->data.name==target.name)
{
printf("%s founded", target.name);
return p;
};
p=p->nextNodeAddress;
};
printf("There is no %s. \n", target.name);
return NULL;
}
'''
Here is my full source code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
# create struct named Word that have char name[100]
typedef struct Word
{
char name[100];
} Word;
# create struct named Node
typedef struct node
{
Word data;
struct node* nextNodeAddress;
} Node;
# Function that can insert node to the first of list
Node* insert_first(Node*head, Word newData)
{
Node* p=(Node*)malloc(sizeof(Node));
p->data = newData;
p->nextNodeAddress=head;
head=p;
return head;
};
# Function that can print out list
void print_listedNode(Node* head)
{
for(Node* i=head; i!=NULL; i=i->nextNodeAddress)
{
printf("%s->", i->data.name);
};
printf("NULL\n");
}
# Function that can search word (conditional statement is not working. But no error.)
Node* search_word(Node* head, Word target)
{
Node*p=head;
while(p != NULL)
{
if(p->data.name==target.name)
{
printf("%s founded", target.name);
return p;
};
p=p->nextNodeAddress;
};
printf("There is no %s. \n", target.name);
return NULL;
}
# int main()
int main(int argv, char* argc)
{
Node* head = NULL;
Word data;
strcpy(data.name, "APPLE");
head = insert_first(head, data);
print_listedNode(head);
strcpy(data.name, "LEMON");
head = insert_first(head, data);
print_listedNode(head);
strcpy(data.name, "BANANA");
head = insert_first(head, data);
print_listedNode(head);
strcpy(data.name, "BANANA");
head = search_word(head, data);
print_listedNode(head);
return 0;
}
and the result is
APPLE->NULL
LEMON->APPLE->NULL
BANANA->LEMON->APPLE->NULL
There is no BANANA.
NULL
I expect to get
APPLE->NULL
LEMON->APPLE->NULL
BANANA->LEMON->APPLE->NULL
BANANA founded
BANANA->LEMON->APPLE->NULL
Thank you for reading the eye-breaking code.
In this if statement
if(p->data.name==target.name)
there are compared two pointers (after the implicit conversion of the array designators to pointers to their first elements) instead of the strings pointed to by the pointers.
You need to write
if( strcmp( p->data.name, target.name ) == 0 )
Related
I have a project that I'm working on for a Systems Programming course. I'm building off of my professor's code. (Please don't mind her lack of labelling, etc. - I'm gonna try to clean this up as best as I can.)
Does anybody know why her linked list code is printing backwards?
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char name[15];
char title[15];
int year;
struct Node *next;
struct Node *prev;
};
typedef struct Node *Box;
Box print_list(Box pointer);
Box insert_node(FILE *inputp);
int main() {
Box head = NULL, temp;
FILE *inputp, *outputp;
int i;
inputp = fopen("input.txt", "r");
outputp = fopen("output.txt", "w");
head = insert_node(inputp);
for (i = 0; i < 4; i++) {
temp = insert_node(inputp);
temp->next = head;
head = temp;
}
print_list(head);
return 0;
}
Box print_list(Box pointer) {
Box here = pointer;
while (here != NULL) {
printf("%s, %s, %d \n", here->name, here->title, here->year);
here = here->next;
}
return pointer;
}
Box insert_node(FILE *inputp) {
Box temp = NULL;
temp = (Box)malloc(sizeof(struct Node));
fscanf(inputp, "%s", &temp->name);
fscanf(inputp, "%s", &temp->title);
fscanf(inputp, " %d", &temp->year);
temp->next = NULL;
temp->prev = NULL;
return temp;
}
This program's purpose is to read a .txt file "playlist" of songs and create a linked list out of them. The input is:
Rachmaninov Concerto_No_2 1999
Mozart Symphony_No_41 2000
Vivaldi The_Seasons 2003
Beethoven Symphony_No_5 1994
Bach Toccatas 2005
While the program outputs:
Bach, Toccatas, 2005
Beethoven, Symphony_No_5, 1994
Vivaldi, The_Seasons, 2003
Mozart, Symphony_No_41, 2000
Rachmaninov, Concerto_No_2, 1999
(I also don't know why she included an output file in the code, all of the output is in the console, not stored in a file. Ignore that.)
The list prints in reverse order because you insert each new node at the beginning of the list. You should use a tail pointer to keep track of the end of the list.
Also note these remarks:
both the next and the prev links should be updated.
hiding pointers behind typedefs as in typedef struct Node *Box; is considered bad practice because it is confusing and error prone.
insert_node is a confusing name for a function that merely allocates a new node from file data.
insert_node should test if fscanf() succeeded at reading the data
fscanf(inputp, "%s", &temp->name); has undefined behavior if the name of the composer exceeds 14 bytes. The same applies to the title. The maximum number of characters to store into the destination arrays before the null terminator should be specified as %14s and these arrays should be defined with a larger length.
main should check if a node was successfully allocated and initialized from file data. Instead of hardcoding the number of nodes, one should iterate as long as nodes can be read from the file.
Here is a modified version:
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char name[40];
char title[40];
int year;
struct Node *next;
struct Node *prev;
};
void print_list(const Node *pointer);
Node *read_node(FILE *inputp);
int main() {
Node *head = NULL;
Node *tail = NULL;
Node *node;
FILE *inputp, *outputp;
int i;
inputp = fopen("input.txt", "r");
if (!inputp) {
fprintf(stderr, "cannot open input.txt: %s\n", strerror(errno));
return 1;
}
outputp = fopen("output.txt", "w");
if (!outputp) {
fprintf(stderr, "cannot open output.txt: %s\n", strerror(errno));
return 1;
}
while ((node = read_node(inputp)) != NULL) {
if (!head) {
head = tail = node;
} else {
node->prev = tail;
tail = tail->next = node;
}
}
print_list(head);
// should free node list
return 0;
}
void print_list(const Node *pointer) {
while (pointer != NULL) {
printf("%s, %s, %d\n", pointer->name, pointer->title, pointer->year);
pointer = pointer->next;
}
}
Node *read_node(FILE *inputp) {
Node *temp = malloc(sizeof(*temp));
if (temp != NULL
&& fscanf(inputp, "%39s%39s%d", &temp->name, &temp->title, &temp->year) == 3) {
temp->next = NULL;
temp->prev = NULL;
return temp;
} else {
free(temp);
return NULL;
}
}
I'm new to C and I'm stuck with the insert function in a linked list. When I try printing the list. The result isn't what I expect. I know it has something to do with pointers but I just can't get my head around it. What am I doing wrong here?
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
typedef struct CELL_NODE CellNode;
struct CELL_NODE {
int row;
int column;
CellNode *next;
};
struct LinkedList {
CellNode *head;
};
typedef struct LinkedList LinkedList;
void printList(LinkedList *myList) {
CellNode *curr = (*myList).head;
if (curr != NULL) {
printf("(%d,%d)", (*curr).row, (*curr).column);
if ((*curr).next != NULL) {
curr = (*curr).next;
printf(" - (%d,%d)", (*curr).row, (*curr).column);
}
} else {
printf("The list is empty");
}
printf("\n");
}
void insert(LinkedList *myList, CellNode *node) {
CellNode *ref = (*myList).head;
if (ref == NULL) {
(*myList).head = node;
} else {
while ((*ref).next != NULL) {
ref = (*ref).next;
}
(*ref).next = node;
}
}
int main(int argc, char *argv[]) {
LinkedList myList = { NULL };
for (int k = 0; k < 2; k++) {
CellNode myNode = { 1, k, NULL };
insert(&myList, &myNode);
printList(&myList);
printf("\n");
}
return 1;
}
The result I get is:
(1,0)
(1,1) - (1,1)
I'm expecting:
(1,0)
(1,0) - (1,1)
You should first change every instance of (*x).y to x->y to make your code much more readable.
Then, look at this code:
int main(int argc, char *argv[])
{
LinkedList myList = {NULL};
for(int k = 0 ; k<2 ; k++) {
CellNode myNode = {1,k,NULL};
insert(&myList,&myNode);
printList(&myList);
printf("\n");
}
return 1;
}
You create myNode as a local variable inside the for loop. That means that each iteration of the loop gets a new instance of myNode, destroying the previous one. So you've connected myNode to your linked list through pointers, and then you let it get destroyed the next time through the for loop.
If you're going to let some piece of code stash a pointer to something, you must ensure that something remains valid until there is no longer any possibility of those pointers being dereferenced.
You need to make a decision -- what will own the objects that the linked list contains pointers to? When will that lifetime end? And when they end, what will destroy them?
You haven't done this. So you have objects whose lifetimes end too early.
With
CellNode myNode = {1,k,NULL};
insert(&myList,&myNode);
you are passing a pointer to a local variable. The life time of this variable is just as long as the respective iteration of the loop, i.e. in the second iteration, the object of the first iteration is out of scope. So you will access an object which's life time has already ended by the pointer you stored in your list. This yields undefined behaviour.
Use dynamically generated objects instead (and don't forget to free them later on):
CellNode *myNode = malloc(sizeof(CellNode));
myNode->row = ...
You repeatedly insert a node into the linked list from a local variable that immediately goes out of scope. The behavior is undefined, your program might fail in many unpredictable ways.
You should modify the code this way:
change the insert function to take the element data as arguments and allocate a new node with malloc().
make printList() print the full list, not just the first couple of cells.
change the clumsy (*pointer).member notation into the equivalent but more idiomatic pointer->member notation.
return 0 from main for successful operation.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
typedef struct CellNode CellNode;
struct CellNode {
int row;
int column;
CellNode *next;
};
typedef struct LinkedList LinkedList;
struct LinkedList {
CellNode *head;
};
void printList(LinkedList *myList) {
CellNode *curr = myList->head;
if (curr != NULL) {
printf("(%d,%d)", curr->row, curr->column);
while (curr->next != NULL) {
curr = curr->next;
printf(" - (%d,%d)", curr->row, curr->column);
}
} else {
printf("The list is empty");
}
printf("\n");
}
CellNode *insert(LinkedList *myList, int row, int column) {
CellNode *node = malloc(sizeof(*node));
CellNode *ref = myList->head;
if (node != NULL) {
if (ref == NULL) {
myList->head = node;
} else {
while (ref->next != NULL) {
ref = ref->next;
}
ref->next = node;
}
}
return node; // return node pointer to allow the caller to detect out of memory error
}
int main(int argc, char *argv[]) {
LinkedList myList = { NULL };
CellNode *node;
for (int k = 0; k < 2; k++) {
insert(&myList, 1, k);
printList(&myList);
printf("\n");
}
// free the nodes
while ((node = myList->head) != NULL) {
myList->head = node->next;
free(node);
}
return 0;
}
I'm adding words (character per node) on a trie data structure - that happens correctly based on a implementantion I found on the web -
http://www.techiedelight.com/trie-implementation-insert-search-delete/
Although I want to extend this and add a list containing some data based on the words, such term frequency etc.
Right now I'm facing an issue with the pointer of the list when adding the first element on a trie node - in the method append_posting_list - and getting a segmetation fault.
Here is the code so far.
main.h
#ifndef TRIE_H
#define TRIE_H
#define CHAR_SIZE 26
typedef struct posting_list {
int doc_id;
int tf;
int df;
struct posting_list *next;
} posting_list_node ;
struct Trie
{
posting_list_node *p_node; // this will be the head of the posting list for every word;
int isLeaf; // 1 when node is a leaf node
struct Trie* character[CHAR_SIZE];
};
struct Trie* getNewTrieNode();
void insert(struct Trie* *head, char* str, int doc_id);
int search(struct Trie* head, char* str);
#endif //TRIE_H
main.c
#include <stdio.h>
#include <stdlib.h>
#include "main.h"
int main(){
struct Trie* head = getNewTrieNode();
insert(&head, "hello", 1);
return 0;
}
// Function that returns a new Trie node
struct Trie* getNewTrieNode()
{
struct Trie* node = (struct Trie*)malloc(sizeof(struct Trie));
node->isLeaf = 0;
for (int i = 0; i < CHAR_SIZE; i++)
node->character[i] = NULL;
return node;
}
posting_list_node* get_mem(){
posting_list_node* p;
p = (posting_list_node *)malloc(sizeof(posting_list_node));
if (p == NULL){
printf("Memory allocation failed\n");
exit(EXIT_FAILURE);
}
return p;
}
void append_posting_list(int doc_id, posting_list_node **n){
posting_list_node *new, *q;
new = get_mem();
new->doc_id = doc_id;
new->tf = 1;
new->next = NULL;
// if new is the first element of the list
if(n == NULL) {
*n = new;
} else {
q = *n;
while( q->next!=NULL) {
q = q->next;
}
q->next = new;
}
}
// Iterative function to insert a string in Trie.
void insert(struct Trie* *head, char* str, int doc_id)
{
// start from root node
struct Trie* curr = *head;
while (*str)
{
// create a new node if path doesn't exists
if (curr->character[*str - 'a'] == NULL)
curr->character[*str - 'a'] = getNewTrieNode();
// go to next node
curr = curr->character[*str - 'a'];
// move to next character
str++;
}
// already found this word, increase frequency
if(curr->isLeaf) {
curr->p_node->tf += 1;
} else {
append_posting_list(doc_id, curr->p_node);
// mark current node as leaf
curr->isLeaf = 1;
}
}
// Iterative function to search a string in Trie. It returns 1
// if the string is found in the Trie, else it returns 0
int search(struct Trie* head, char* str)
{
// return 0 if Trie is empty
if (head == NULL)
return 0;
struct Trie* curr = head;
while (*str)
{
// go to next node
curr = curr->character[*str - 'a'];
// if string is invalid (reached end of path in Trie)
if (curr == NULL)
return 0;
// move to next character
str++;
}
// if current node is a leaf and we have reached the
// end of the string, return 1
return curr->isLeaf;
}
I'm really stuck here.
Any suggestions would be really appreciated.
I found a couple things that when fixed, got rid of your segmentation fault.
In getNewTrieNode() I think you need to set p_node to NULL
struct Trie* getNewTrieNode() {
struct Trie* node = (struct Trie*)malloc(sizeof(struct Trie));
node->isLeaf = 0;
for (int i = 0; i < CHAR_SIZE; i++)
node->character[i] = NULL;
node->p_node = NULL;
return node;
}
append_posting_list() takes post_list_node **, but in insert(), you are passing just post_list_node *
void append_posting_list(int doc_id, posting_list_node **n)
append_posting_list(doc_id, curr->p_node);
looks like it should be
append_posting_list(doc_id, &(curr->p_node));
In append_posting_list()
if (n == NULL) {
should be
if (*n == NULL) {
in order to see if a pointer to an empty list is being passed in.
You should really have some functions to print out your data structure while you are working on it, so you can test each piece as you develop it. Simply compiling and running code and not getting any errors is no gurantee the code is working correctly with complex data structures like this. Making sure that each piece works perfectly before going on to the next piece will save you hours in trying to track down segmentation faults and other errors like this.
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.
I'm working in C and am having some trouble. I need to store an array of chars (string) across a linked list. In other words, convert a string to a linked list. Basically, one character per node. For example string, dog\0, rather then storing a null character in the last node it would just point to a null pointer to signify the end of the string…… d->o->g->NULL
An suggestions would be great, thank you
int main(){
char *string;
string = malloc(sizeof(char)*100);
strcpy(string,"cheese");
node *list = NULL;
list = createNode(string[0]);
int i;
for(i=1;i<strlen(string);i++){
// this is where I'm stuck, the first char 'c'is in,
// I'm guessing i wanna loop through and
// store each char in a new node ?
}
return 0;
}
node *createNode(char data){
node *ptr = malloc(sizeof(node));
if (ptr == NULL)
{
return NULL;
}
ptr->data = data;
ptr->next = NULL;
return ptr;
}
Here is how to do this in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
node *next;
char data;
};
node *createNode(char data, node *parent) {
node *ptr=(node*)malloc(sizeof(node));
if(ptr==NULL) {
fprintf(stderr, "Memory allocation error.\n");
exit(1);
}
if(parent!=NULL) parent->next=ptr;
ptr->data=data;
ptr->next=NULL;
return ptr;
}
int main() {
char str[]="cheese";
// Store the string to the list
node *first=NULL, *cur=NULL;
for(int i=0, len=strlen(str); i<len; i++) {
cur=createNode(str[i],cur);
if(first==NULL) first=cur;
}
// Now print it out
cur=first;
while(cur!=NULL) {
printf("%c\n", cur->data);
cur=cur->next;
}
_getwch();
return 0;
}
If C++ is OK then here is a working sample:
#include <iostream>
#include <list>
using namespace std;
int main() {
char str[]="cheese", chr;
// Store the string in the list
std::list<char> clist;
for (int i=0, len=strlen(str); i<len; i++)
clist.push_back(str[i]);
clist.push_back('\0');
// Display the list
do {
chr=clist.front();
cout<<chr<<endl;
clist.pop_front();
} while(chr);
_getwch();
return 0;
}