I'm trying to create a double linked list with strings. The problem is that when I send a word and try to print it out - only the first letter (the ASCII value) comes out. For example if I write "Joe" I will get 74 back (74 is the ASCII value of "J")
I do remember something to do with strncopy but can't recall. Any suggestions? :)
struct Item
{
char e;
Position previous;
Position next;
};
void Insert(char x, List l, Position p)
{
Position TmpCell;
TmpCell = (struct Item*) malloc(sizeof(struct Item));
if(TmpCell == NULL)
printf("Memory out of space\n");
else
{
TmpCell->e = x;
TmpCell->previous = p;
TmpCell->next = p->next;
p->next = TmpCell;
}
}
This is the method used to display:
void Display(List l)
{
printf("The list element are :: ");
Position p = l->next;
while(p != NULL)
{
printf("%d -> ", p->e);
p = p->next;
}
}
Faults - it just didnt work as expected
you can try
printf("%c",p->e);
Related
I implemented the list using
typedef int type;
typedef struct node{
int val;
struct node *next;
} node;
typedef struct list{
node *head;
}listtype ;
(The typedef type is just there so I can change the datatype of the list by just changing that one line)
And I implemented an insert function using
void insert(listtype *l, type elem, int pos) {
node *p = (node*)malloc(sizeof(node));
p->val = elem;
if (pos == 0) {
p->next = l->head;
l->head = p;
}
else {
node *q;
int i;
for (q = l->head, i = 0; i < pos - 1; i++) {
q = q->next;
}
p->next = q->next;
q->next = p;
}
}
The join function I came up with looks like this
void list_join(listtype *l,listtype *c) {
if (list_empty(*l)) {
printf("List empty");
}
else {
node *q;
int i = 0;
q = l->head;
while (q->next != NULL) {
insert(&c ,q->val, i + list_size(*c));
q = q->next;
i++;
}
}
}
But it doesn't work, or more accurately when I put it through my list view function it doesn't print out the correct contents (or anything at all really).
My function that prints the contents of the list:
void list_view(listtype l) {
if (list_empty(l))
printf("List empty");
else {
node *q;
q = l.head;
int i = 0;
while (q->next != NULL) {
printf("%d \t %d \n", i, q->val);
q = q->next;
i++;
}
printf("%d \t %d \n", i, list_tail(l));
}
}
I'm want to assume this function works properly and the issue is in the join function, but that's giving it a lot of credit.
The logic in the else block of the list_join function has a few issues:
The while condition should not test the ->next member, but the node itself, otherwise you'll not insert the tail value of the first list.
The insert function expects a listype* argument, not listype**, so you shouldn't pass &c, but c as first argument.
As in each iteration of the loop the c list will get longer, it is wrong to do i + list_size(*c), since both i and the size of the list will have increased. You'll want to calculate the length of the c list only once, and treat that as a constant that applies to all iterations equally. You could even initialise i with that list size instead of 0.
Here is a correction:
node *q;
int i = list_size(*c); // <-- get the list size only once
q = l->head;
while (q != NULL) { // No ->next
// Not &c; no list_size call
insert(c, q->val, i);
q = q->next;
i++;
}
This will fix the issue. But please note that there is lot of inefficiency in your approach which could be avoided if you would maintain a reference to the tail node of a list, and keep it updated. Then if you also create a separate method for appending a value at the end of a list (instead of providing a position), you can avoid some of the loops you currently have.
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
I am attempting to delete several occurrences of a word stored in a linked list. However, these words are stored by character in a single node instead of as a whole word in a list. For example, The pink flamingo is stored as:
T->h->e-> ->p->i->n->k-> ->f->l->a->m->i->n->g->o. Say the user wants to find pink. They have to loop through and delete each of these nodes.
I have attempted to create a loop which copies the contents of the linked list into a search function. I think copy this search function into another string. I am able to successfully delete the first occurrence of the desired character. However, I'm unable to do much else. I've attempted several times to push the node to the next node after deletion, but that also hasn't worked. It produced the same error.
void nodeDeletions(struct node** reference_to_headNode, struct node* deleteNode){
if(*reference_to_headNode == NULL){
return;
}
if(*reference_to_headNode == deleteNode){
printf("Test A\n");
*reference_to_headNode = deleteNode->nextNode;
}
if(deleteNode->nextNode != NULL){
printf("Test B\n");
deleteNode->nextNode->previousNode = deleteNode->previousNode;
}
if(deleteNode->previousNode != NULL){
printf("Test C\n");
deleteNode->previousNode->nextNode = deleteNode ->nextNode;
}
free(deleteNode);
}
void deleteWord(struct node** reference_to_headNode, char word_to_delete[]){
struct node *tempNode;
struct node *nextNode;
int searchIndex = 0;
int characterIndex = 0;
const int arraySize = 101;
const int arraySize2 = 202;
char searchWordIndex[arraySize];
char searchWordCopyIndex[arraySize2];
if(*reference_to_headNode == NULL){
return;
}
else {
for (tempNode = *reference_to_headNode; tempNode != NULL; tempNode = tempNode->nextNode) {
searchWordIndex[searchIndex] = tempNode->character;
searchIndex++;
}
strcpy_s(searchWordCopyIndex, searchWordIndex);
int length_of_searchIndex = strlen(searchWordCopyIndex);
int length_of_deletionWord = strlen(word_to_delete);
tempNode = *reference_to_headNode;
for (searchIndex = 0; searchIndex < length_of_searchIndex; searchIndex++) {
printf("Test 1\n");
if(tempNode != NULL) {
if(tempNode->character == word_to_delete[0]) {
for (characterIndex = 0; characterIndex < length_of_deletionWord; characterIndex++) {
printf("Test 2\n");
if (searchWordCopyIndex[searchIndex] == word_to_delete[characterIndex]) {
printf("Test 3\n");
if (tempNode->character == word_to_delete[characterIndex]) {
printf("Test 4\n");
printf("%c\n", tempNode->character);
printf("%c\n%c\n", word_to_delete[characterIndex], searchWordCopyIndex[searchIndex]);
nextNode = tempNode->nextNode;
nodeDeletions(reference_to_headNode, tempNode);
tempNode = nextNode;
}
else {
printf("Test 5\n");
tempNode = tempNode->nextNode;
}
}
}
}
}
tempNode = tempNode->nextNode;
}
}
}
Phew! That's a lot of indented clode blocks. And a lot of auxiliary arrays and indices. And very long variable names. :)
Basically, you are dealing with three different types of iterating forwards through stuff, which are all present in your code:
Traverse a character string:
while (*s) {
// do stuff with *s
s++;
}
Traverse a linked list:
while (p) {
// do stuff with *p
p = p->next;
}
Traverse a linked list via a reference to the source, so that you can modify it:
while (*p) {
// do stuff with **p
p = &(*p)->next;;
}
You only have to combine these three basic loops.
You can walk through the list with the third method (because you need to be able to update the head or next links when you delete). For each node you visit, compare the "tail" of that node with an auxiliary pointer p and the string s using the other two methods simultaneously. When the string matches, *s == '\0' and p points to the first node after the word. Delete all nodes by advancing the head until the head is p.
In other words:
Traverse the list via *head.
At each node:
set p = *head and s to the begining of the string;
traverse the list and the word while the letters match;
If *s == '\0', there is a match. Now, *head points to the start of the word to delete in the list, p points to the first node after the word in the list, which may be NULL.
If there is a match, advance *head until *head == p, deleting the nodes as you go.
Or, in code:
void delete_word(struct node **head, const char *str)
{
while (*head) {
struct node *p = *head;
const char *s = str;
while (p && *s && p->c == *s) {
p = p->next;
s++;
}
if (*s == '\0') {
while (*head != p) {
struct node *del = *head;
*head = (*head)->next;
delete_node(del);
}
} else {
head = &(*head)->next;
}
}
}
I am trying to print out the results of the linked list in the reverse order that they were entered in. The program takes 3 inputs, Song name, song length (in seconds) and copyright. The program should take the list of songs and print the in the reverse order that they were entered in.
I am not too familiar with linked list. This is my first time using it as sort of a database.
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)
//defining struct
typedef struct node
{
char songName[20];
int songLength;
int copyright;
struct node * next;
}node;
//defining prototypes
node *create(int n);
void display(node *head);
int main()
{
int n = 0;
node *head = NULL;
printf("How many entries?\n");
scanf("%d", &n);
//call to create list
head = create(n);
printf("\nThe linked list in order is:\n");
display(head);
return 0;
}
node *create(int n)
{
node *head = NULL;
node *temp = NULL;
node *p = NULL;
for (int i = 0; i < n; i++)
{
temp = (node*)malloc(sizeof(node));
printf("What is the name of song %d\n", i + 1);
//fgets(temp->songName, 20, stdin);
scanf("%s", &temp->songName);
printf("What is the length of song %d (in seconds)?\n", i + 1);
scanf("%d", &temp->songLength);
printf("Is song %d copyrighted?(1 = YES, 0 = NO)\n", i + 1);
scanf("%d", &temp->copyright);
temp->next = NULL;
if (head == NULL)
{
head = temp;
}
else
{
// if not empty, attach new node at the end
p = head;
while (p->next != NULL)
{
p = p->next;
}
p->next = temp;
}
}
return head;
}
void display(node *head)
{
node *p = NULL;
if (head == NULL)
{
printf("List is empty\n");
}
else
{
p = head;
while (p != NULL)
{
printf("Song: %s, ", p->songName);
printf("%d minutes, ", p->songLength);
if (p->copyright == 1)
{
printf("Copyrighted\n");
}
else if (p->copyright == 0)
{
printf("No copyright\n");
}
p = p->next;
}
}
}
So if Input the following:
Song 1 - All Star (song name), 237 (seconds), 0 (no copyrights)
song 2 - Crab Rave, 193, 0
song 3 - 7 rings, 185, 1(copyrights)
The output should be:
7 rings, 185, 1
Crab Rave, 193, 0
All Star, 237, 0
If you have a single (forward) linked list, the probably easiest way to print it in reverse order is using recursion:
void display_recursive(node *n) {
if (!n) {
return;
}
display_recursive(n->next);
printf("Song: %s, ", n->songName);
...
}
Recursion means that a function is calling itself (until some end-condition, the anchor, is reached).
By that way, program flow will build up a "stack" of display_recursive- function calls, with the first node, then the second node, ..., until it reaches the last node; by then, recursion stops, and the print part of display_recursive is handled, starting with the last node backwards.
Hope this explanation helps; Try it out in the debugger to see what happens.
I've read half a dozen answers with regards to this here and am relatively loathe to ask such a question, but I'm attempting to create a linked list using a struct in C, and was having some issues in passing pointers to the linked list. I think it's mostly sorted, but honestly am having acute issues trying to get the linked list working.
#include <stdio.h>
#include <stdlib.h>
typedef struct cell
{
int value;
struct cell *next;
} cell;
int inputplace = 0;
cell * createlist()
{
cell curElement = (cell *) malloc(sizeof(cell));
cell *head = &curElement;
cell *curEl = &curElement;
curEl->value = 900;
FILE *fp;
char *mode = "r";
fp = fopen("input",mode);
if(fp==NULL)
{
fprintf(stderr, "Unable to open input file 'input'");
exit(1);
}
int val;
int tempplace = 0;
while(tempplace < inputplace)
{
if(fscanf(fp, "%d", &val) != EOF)
{
tempplace++;
printf("%d", &val);
}
else
break;
}
while(fscanf(fp, "%d", &val)!=EOF)
{
inputplace++;
printf("%d\n", curEl);
if(val < 0)
{
curEl->value = -1;
curEl->next = -1;
break;
}
printf("%d\n", val);
curEl->value = val;
curEl->next = malloc(sizeof(struct cell));
curEl= curEl->next;
}
return head;
}
cell* reverse(cell* p)
{
cell * prev = -1;
cell * current = p;
cell * next;
while(current->value != -1)
{
next = current->next;
current->next = prev;
prev = current;
current = next;
}
return prev;
}
cell* append(cell* p, cell* q)
{
cell * current = p;
cell * r = p;
while(1)
{
if(current->value == -1)
{
current->value = q->value;
current->next = q->next;
}
}
return r;
}
int last(cell *p)
{
cell q = *p;
int last = -1;
while(1)
{
if(q.value == -1)
{
return last;
}
else
{
last = q.value;
q = *q.next;
}
}
}
cell * delete(int n, cell *p)
{
cell * head = p;
cell * prev = -1;
cell * current = p;
if(current-> value == n)
{
return current->next;
}
else
{
while(current->value != -1)
{
if(current->value==n)
{
prev->next = current->next;
break;
}
prev = current;
current = current->next;
}
}
return head;
}
int member(int n, cell *p)
{
cell q = *p;
while(1)
{
if(q.value == n)
{
return 1;
}
if(q.value == -1)
{
return 0;
}
q = *q.next;
}
}
int display(cell *p)
{
printf(" %c", '[');
cell q = *p;
while(1)
{
if(q.value == -1)
{
printf("%c ",']');
return 1;
}
if(q.next != p->next)
printf("%c ",',');
printf("%d", q.value);
q = *q.next;
}
printf("\n\n");
}
int main()
{
cell *head = createlist();
cell *headk = createlist();
cell *head3 = delete(5, head);
printf("%d, %d\n", head->value, head->next->value);
printf("Last head: %d\n", last(head));
display(headk);
display(head);
display(head3);
cell *head4 = delete(6, head);
display(head4);
cell *head5 = delete(7, head);
display(head5);
printf("Member2 6, head: %d\n", member(6,head));
printf("Member2 3, head: %d\n", member(3, head));
cell *head2 = reverse(head);
//print(head2);
printf("%d, %d\n", head2->value, head2->next->value);
}
So the input file contains numerical data with a negative one terminating the list:
Example input I'm using:
5
6
7
-1
1
2
3
-1
The issue I'm having is the second list is apparently overriding the first or some such, and my pointer-fu is weak, what do I need to do to successfully allocate the new structs?
Charles B.
You return a pointer to a local variable, and local variables goes out of scope once the function returns and that leaves you with a stray pointer. Using that stray pointer will lead to undefined behavior.
The problem starts with the declaration of curElement, and the compiler should really have screamed at you for that:
cell curElement = (cell *) malloc(sizeof(cell));
Here you declare curElement to be an actual structure, and not a pointer to the structure.
There's also the problem that you don't really have an end to the list. You allocate the next pointer of the last node you add, regardless if there's going to be a next node or not, and you don't initialize that node so the memory you allocate will be uninitialized, and trying to access it will lead to yet another undefined behavior.
I suggest something like the following abbreviated code:
cell *head = NULL;
cell *tail = NULL;
...
while (fscanf(fp, "%d", &val) == 1)
{
...
cell *current = malloc(sizeof(*current));
current->val = val;
current->next = NULL; // Very important!
// Check if this is the first node in the list
if (head == NULL)
head = tail = current;
else
{
// List is not empty, append node to end of list
tail->next = current;
tail = current;
}
}
Beside the change in how the list is handled and added to, there are also two other changes: The first is that the return value from the fscanf function is compared against 1, because fscanf (and family) will return the number of successfully parsed items, and this allows you to find format errors in the input file.
The second change is to not cast the return of malloc. In C you should never cast from or to void *, cast like that can hide subtle bugs.