How to use struct in a function - c

typedef struct node {
int num_children;
struct node *children[ALPHABET_LENGTH];
} trie_node;
void add(char* a, trie_node* node){//need to make sure a is not NULL at beginning
trie_node* newNode;
int i;
if (a != NULL && node->children[(int)a[0] - 97] == NULL)
{
node->num_children++;
//initialize the children array
for (i = 0; i < ALPHABET_LENGTH; i++)
{
if (newNode->children[i] != NULL)
{
newNode->children[i] = NULL;
}
}
newNode -> num_children = 0;
a++;
add(a, newNode);
}
else if (a != NULL && node->children[(int)a[0] - 97] != NULL){
a++;
node->num_children++;
add(a, node->children[(int)a[0] - 97]);
} else{//a == NULL, which means end of the add procedure
return;
}
}
int main()
{
char* s = "add abc";
trie_node* contacts;
add(s,contacts);
return 0;
}
When I intialize the struct trie_node in main function, I can access all member of contacts. However, when I do that in my add function, the newNode doesn't work. I cannot access members like num_children under newNode. How could I fix that if I want to add a new node to the contacts

You don't allocate any stoarge to contacts or set it to NULL in main or test if it is null in add.
If you are lucky, because you are right at the start of the program, contacts is NULL when you pass it in, so the if test at the top of add crashes with a segmentation violation.
Also, you use newNode without allocating space to it.

Related

C: getchar() destroys pointer

typedef struct LinkedList LinkedList;
struct LinkedList {
LinkedList* next;
char* head;
char current;
};
LinkedList makeList()
{
char* headPointer = calloc(60, sizeof(char));
LinkedList temp = { 0xCCCCCCCC, headPointer, 0 };
return temp;
}
int addToList(LinkedList* lstPointer, char toAdd) {
if (lstPointer->head == NULL || lstPointer->head == 0xCCCCCCCC)
return -1;
if (lstPointer->current + 1 < 60) { /* enough space in the list to add */
*(lstPointer-> head + lstPointer -> current) = toAdd;
lstPointer->current = lstPointer->current + 1;
}
else /* not enough space, will create new node in the list */
{
if (lstPointer->next == 0xCCCCCCCC) {
LinkedList nextNode = makeList();
lstPointer->next = &nextNode;
}
return addToList(lstPointer->next, toAdd);
}
/*Added succsessfully*/
return 0;
}
int main(){
char chr;
LinkedList lst = makeList();
while ((chr = getchar()) != EOF) {
if (addToList(&lst, chr) == -1)
return -1;
}
return 0;
}
i am trying to use linked list but after i fill the first, i create a new one and able to add an item to it. on the second item the next list pointer get destroyed by getchar(). i have no idea why or how is it related.
In makelist you need to allocate a new list, but then instead of returning it, you copy it into a local variable, leaking the memory that you just allocated. Instead, return a pointer:
LinkedList *makeList() // Note *
{
LinkedList *temp = calloc(1, sizeof(LinkedList));
temp->head = calloc(60, sizeof(char));
temp->next = 0;
temp->current = toAdd;
return temp; // Note temp is a pointer
}
In addToList you don't need the nextNode variable:
lstPointer->next = makelist();

Can you tell me why my function to select a random string from a linked list isn't working?

I am building a program for a project. One of the requirements for the project is a function that selects a random node from my linked list of 3000 words.
I tried to do this by creating a function that generates a random number from 0 to 2999. After this, I created another function that follows a for loop starting from the head and moving to the next node (random number) times.
My random number generator is working fine, but my chooseRand() function is not.
Please help, the random number generator and the chooseRand() function are the last two functions above main. Also, my code is a bit messy, sorry.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int nodeNum;
int chances;
char* secret;
/*Node of linked list*/
typedef struct node {
char *data;
struct node *next;
} node;
node *start = NULL;
node *current;
/*Void function to print list*/
void printList(struct node *node)
{
while (node != NULL) {
printf("%s ", node->data);
node = node->next;
}
}
/*Appending nodes to linked list*/
void add(char *line) {
node *temp = malloc(sizeof(node));
temp->data = strdup(line);
temp->next = NULL;
current = start;
if(start == NULL) {
start = temp;
} else {
while(current->next != NULL) {
current = current->next;
}
current->next = temp;
}
}
void readfile(char *filename) {
FILE *file = fopen(filename, "r");
if(file == NULL) {
exit(1);
}
char buffer[512];
while(fgets(buffer, sizeof(buffer), file) != NULL) {
add(buffer);
}
fclose(file);
}
node *listSearch(node* start, char *nodeSearched){
node *p;
for (p = start; p != NULL; p = p->next)
if (strcmp(p->data, nodeSearched) == 0)
printf("%s", p->data);
return NULL;
}
node *letterSearch(node* start, int i){
node *p;
for (p = start; p != NULL; p = p->next)
if (strlen(p->data) == i)
{
printf("\n %s", p->data);
free(p);
p = NULL;
}
return NULL;
}
void chooseRand(struct node* start)
{
node* p;
int n;
p = start;
for(n = 0; n != nodeNum; n++)
{
p = p->next;
}
printf("%s", p->data);
}
void randNum(int lower, int upper)
{
srand(time(0));
nodeNum = (rand() % (upper - lower + 1)) + lower;
}
int main(){
randNum(0, 2999);
chooseRand(start);
return 0;
}
As others has said, the problem is that you don't have initialized the linked list yet, because of what your are getting a segmentation fault. So, in addition to initializing the list first, you must also introduce checks in the implementation of the chooseRand function, to check that if you reach the end of the list, without reaching the desired index, you stop executing the foor loop, otherwise you will be potentially exposed to segmentation faults.
Improve chooseRand implementation, to prevent segmentation fault either, when the linked list is empty, or when the randomly generated nodeNum is grater than the the index of the list's last item:
void chooseRand(struct node* start)
{
node* p;
int n;
p = start;
if(p == NULL){
printf("The list is empty!");
return;
}
// Also, we must stop the iteration, if we are going to pass the end of the list, you don't want a segmentation fault because trying to access a NULL pointer:
for(n = 0; n != nodeNum && p->next != NULL; n++)
{
p = p->next;
}
// If p == NULL, the list was not big enough to grab an item in the `nodeNum` index:
printf("%s", (n != nodeNum) ? "Not found!" : p->data);
}
Initialize the linked list, with the content of some file on disk:
int main(){
randNum(0, 2999);
// Fill the linked list with the content of a file in disk, calling your method:
char fileName[] = "PutYourFileNameHere.txt";
readfile(fileName);
chooseRand(start);
return 0;
}
There is another fix that you must do, and it is free the memory being hold by the pointer field data of your structure, in the implementation of your method letterSearch. Inside the if statement, you're de-allocating the memory hold by the p pointer, but you aren't de-allocating the memory assigned to the pointer p->data, this will cause a memory leak. When you in the function add, initialized p->data with the result of the call to the function strdup(line), what this function does is allocate enough memory in the heap, copies to it the buffer pointed by the line argument, and give to you back a pointer to the new allocated memory, that you're storing in the p.data field; a pointer that you should free when you're done with it, otherwise your program will have potential memory leaks. So I will modify your function letterSearch as folollows:
node *letterSearch(node* start, int i){
node *p;
for (p = start; p != NULL; p = p->next)
if (strlen(p->data) == i)
{
printf("\n %s", p->data);
// Free p->data before free p:
free(p->data);
free(p);
p = NULL;
}
return NULL;
}
References:
strdup

Function to insert node in linked list

I'm reading in words from a dictionary and then adding them to linked lists in a hash table. This works fine when I try inserting the nodes for each word within the while loop.
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
FILE *dict = fopen(dictionary, "r");
if (dict == NULL)
{
return false;
}
// Set all next pointers to NULL in hash table
for (int i = 0; i < N; i++)
{
table[i] = NULL;
}
char word[LENGTH + 1];
while(fscanf(dict, "%s", word) != EOF)
{
// Get key from hash function
unsigned int key = hash(word);
node *pNode = getNode(word);
if (table[key] != NULL)
{
pNode->next = table[key];
}
table[key] = pNode;
words++;
}
fclose(dict);
return true;
}
I've tried refactoring this to a function insertNode with the exact same code but it doesn't work and the nodes seem to get lost and cause a memory leak. I assume it has something to do with how the arguments are passed into the function but as head is a pointer I would've thought it would work fine.
void insertNode(node *head, const char *key)
{
// Create node
node *pNode = getNode(key);
// Insert node into linked list
if (head != NULL)
{
// Make new node point to first item in linked list (a.k.a head)
pNode->next = head;
}
// Now point head to new node
head = pNode;
}
so the while loop within load would just call the function (which is defined before)
char word[LENGTH + 1];
while(fscanf(dict, "%s", word) != EOF)
{
// Get key from hash function
unsigned int key = hash(word);
// Add value to Hash table with head of linked list
insertNode(table[key], word);
words++;
}
As the 'head' variable is a pointer, you can just pass the value of 'head' by this pointer not the pointer itself, and in this case you try to override the local pointer inside the function.
Well look at this example to assign/change value to the pointer:
#include <stdio.h>
class A {
public:
int x;
};
// pass pointer by copy
void initialize(A* obj) {
obj = new A(); // obj not null here
obj->x = 2;
printf("x: %d\n", obj->x);
}
int main() {
A *a = nullptr;
initialize(a);
// a is still null here (pointer passed by copy)
printf("x: %d\n", a->x); // seg fault here, read on null
return 0;
}
The following code as you can see is incorrect. To fix this example you have to change the function prototype, and pass the pointer by pointer so it should lool like this:
#include <stdio.h>
class A {
public:
int x;
};
// pass pointer by pointer
void initialize(A** obj) {
*obj = new A(); // obj not null here
(*obj)->x = 2;
printf("x: %d\n", (*obj)->x);
}
int main() {
A *a = nullptr;
initialize(&a); // get the pointer address
// a is valid object here
printf("x: %d\n", a->x); // no error, x == 2
return 0;
}
So in your case it should be:
insertNode(&table[key], word);
and
void insertNode(node **head, const char *key)
{
// Create node
node *pNode = getNode(key);
// Insert node into linked list
if (*head != NULL)
{
// Make new node point to first item in linked list (a.k.a head)
pNode->next = *head;
}
// Now point head to new node
*head = pNode;
}

Insert node in a linkedlist

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

How can I display the data I created in a linked list?

I think there is something wrong with my create.
void add(N *p) {
N *current, *start;
current = malloc(sizeof(p));
scanf("%d", &current->data);
current->next = NULL;
if (p == NULL) {
p = current;
start = current;
} else {
start->next = current;
start = current;
}
}
I think that my display() is correct.
void display(N *p) {
N *current;
current = p;
while (current != NULL) {
printf("\n%d", current->data);
current = current->next;
}
}
Your malloc(sizeof(p)) only returns enough space for a pointer. You instead want malloc(sizeof(N)).
Also, you need to return the new value of p instead of throwing it away at the end of add(). (Your start has a similar issue; pick one to be the head of your linked list.)
There are problems:
function add() does not allocate the correct amount of memory. Use this method:
current = malloc(sizeof(*current));
The way you are inserting the newly allocated object into the list does not work: you modify p, which is an argument with local scope, and you set start which also has local scope. No side effect is performed on the N pointer is the callers scope.
Your display function is correct, but I would favor adding the newline at the end of the output instead of at the beginning.
Here is an updated version with a better API:
int add(N **headp) {
N *current = calloc(sizeof(*current));
if (current == NULL) {
fprintf(stderr, "cannot allocate memory for new object\n");
return -1;
}
if (scanf("%d", &current->data) != 1) {
fprintf(stderr, "cannot read value for new object\n");
return -2;
}
current->next = *headp;
*headp = current;
return 0;
}
void display(const N *list) {
for (const N *p = list; p != NULL; p = p->next) {
printf("%d\n", p->data);
}
}
The add function is used this way from the caller:
#include <stdio.h>
#include <stdlib.h>
typedef struct N {
int data;
struct N *next;
} N;
int main(void) {
N *list = NULL;
for (i = 0; i < 10; i++) {
if (add(&list))
break;
}
display(list);
return 0;
}

Resources