This is a toy version of the code I really want to write:
#include <stdio.h>
#include <stdlib.h>
typedef struct node_s {
char val;
struct node_s *next;
} node;
int n;
char obtain_next_char(){
if (n<100) {
return 'a';
} else {
return 0;
}
}
int main() {
char c;
node *start, *curr;
n = 0;
start = malloc(sizeof(node));
curr = start;
while ((c=obtain_next_char()) != 0) {
curr->val = c;
curr->next = malloc(sizeof(node));
curr = curr->next;
}
curr->next = NULL;
printf("chain made, %d links\n", n);
curr = start;
while (curr != NULL) {
printf(">>>%c<<<\n",curr->val);
curr=curr->next;
}
}
First, regarding obtain_next_char, the function is highly simplified here. With the real function, there is no way to know ahead of time what the return value will be.
Now, the code works, but it results in an empty node at the end of the list, which I'm going to have to get rid of. Can this code be re-written to remedy this deficiency? I am trying to avoid duplicate code at the head of the loop, i.e. I don't want to set up the first node with code outside the loop and then set up the following nodes with the same code inside the loop.
node dummy, *start, *curr;
curr = &dummy;
while ((c=obtain_next_char()) != 0) {
curr->next = malloc(sizeof(node));
curr = curr->next;
curr->val = c;
}
curr->next = NULL;
start = dummy.next;
How about this:
start = NULL;
while ((c=obtain_next_char()) != 0) {
if (!start) {
start = malloc(sizeof(node));
curr = start;
} else {
curr->next = malloc(sizeof(node));
curr = curr->next;
}
curr->val = c;
curr->next = NULL;
}
I'm not sure what you want to achieve with this function because, here you are not scanning in any input :
char obtain_next_char(){
if (n<100) {
return 'a';
} else {
return 0;
}
}
maybe you need this :
char obtain_next_char()
{
char c;
scanf(" %c",&c); //scanning input
if (n<100) //if number of links < 100 then, return character
{
return c;
}
else //else return '0' (ascii character)
{
return '0';
}
}
but it results in an empty node at the end of the list
reason :
The problem is that a new node is being created at the end of while loop
while ((c=obtain_next_char()) != 0)
{
curr->val = c;
curr->next = malloc(sizeof(node)); //new node at end of each iteration
curr = curr->next;
}
So, when you end input, the last empty node remains
solution : (without first node with code outside the loop)
To avoid this, try creating node at the start of each iteration
while ((c=obtain_next_char()) != '0')
{
if(n != 0) //to avoid again creating for head node
{
curr->next = malloc(sizeof(node));
curr = curr->next;
}
curr->val = c;
n++; //increasing number of links
}
This way, you can avoid creating extra empty node at the end of each iteration.
I don't want to set up the first node with code outside the loop
while ((c=obtain_next_char()) != '0')
{
if(n != 0) //any other node
{
curr->next = malloc(sizeof(node));
curr = curr->next;
}
else //for head node
{
start = malloc(sizeof(node));
curr = start;
}
curr->val = c;
n++; //increasing number of links made
}
putting altogether your code would be :
#include <stdio.h>
#include <stdlib.h>
typedef struct node_s {
char val;
struct node_s *next;
} node;
int n;
char obtain_next_char()
{
char c;
scanf(" %c",&c);
if (n<100)
{
return c;
}
else
{
return '0';
}
}
int main() {
char c;
node *start=NULL, *curr=NULL;
n = 0;
while ((c=obtain_next_char()) != '0')
{
if(n != 0) //any other node
{
curr->next = malloc(sizeof(node));
curr = curr->next;
}
else //for head node
{
start = malloc(sizeof(node));
curr = start;
}
curr->val = c;
n++;
}
curr->next = NULL;
printf("chain made, %d links\n", n);
curr = start;
while (curr != NULL) {
printf(">>>%c<<<\n",curr->val);
curr=curr->next;
}
}
input :
1 2 3 4 5 0
output :
chain made, 5 links
>>>1<<<
>>>2<<<
>>>3<<<
>>>4<<<
>>>5<<<
Related
I'm trying to implement radix sort on a linked list based on an integer with the code below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_DIGITS 10 // maximum number of digits in a key
// Structure for a node in the linked list
typedef struct node
{
int key; // the key to be sorted
char value[20]; // the value associated with the key
struct node *next; // pointer to the next node in the list
} Node;
// Function prototypes
void radixSort(Node **head);
Node *createNode(int key, const char *value);
Node *append(Node *head, int key, const char *value);
void printList(Node *head);
int main(void)
{
Node *head = NULL; // head of the linked list
// Create a linked list with some random keys and values
head = append(head, 456, "apple");
head = append(head, 345, "banana");
head = append(head, 123, "cherry");
head = append(head, 789, "date");
head = append(head, 231, "elderberry");
head = append(head, 567, "fig");
head = append(head, 876, "grape");
// Print the original list
printf("Original list:\n");
printList(head);
// Sort the list using radix sort
radixSort(&head);
// Print the sorted list
printf("Sorted list:\n");
printList(head);
return 0;
}
// Function to sort the linked list using radix sort
void radixSort(Node **head)
{
Node *bucket[10]; // array of buckets
Node *curr; // pointer to the current node
Node *tail[10]; // array of tails for each bucket
int i, j, k;
int factor; // factor to sort on
int digits[MAX_DIGITS]; // array to store the digits of the keys
// Initialize the buckets and tails
for (i = 0; i < 10; i++)
{
bucket[i] = NULL;
tail[i] = NULL;
}
// Find the maximum number of digits in the keys
int maxDigits = 0;
curr = *head;
while (curr != NULL)
{
int key = curr->key;
int numDigits = 0;
while (key > 0)
{
numDigits++;
key /= 10;
}
if (numDigits > maxDigits)
{
maxDigits = numDigits;
}
curr = curr->next;
}
// Loop through each digit, starting with the least significant digit
for (factor = 1; maxDigits > 0; factor *= 10, maxDigits--)
{
// Extract the digits of the keys
curr = *head;
while (curr != NULL)
{
digits[curr->key / factor % 10]++;
curr = curr->next;
}
// Cumulative sum of the digits
for (i = 1; i < 10; i++)
{
digits[i] += digits[i - 1];
}
// Sort the nodes into the appropriate buckets
curr = *head;
while (curr != NULL)
{
int digit = curr->key / factor % 10;
if (bucket[digit] == NULL)
{
bucket[digit] = curr;
tail[digit] = curr;
}
else
{
tail[digit]->next = curr;
tail[digit] = curr;
}
curr = curr->next;
}
// Rebuild the list in sorted order
*head = NULL;
for (i = 9; i >= 0; i--)
{
//printf("%dA\n",i);
if (bucket[i] != NULL)
{
//printf("%dB\n",i);
if (*head == NULL)
{
*head = bucket[i];
// printf("%dC\n",i);
}
else
{
//printf("%dD\n",i);
tail[9 - i]->next = bucket[i];
//printf("%dF\n",i);
}
// tail[9 - i] = tail[i];
}
else{
// printf("%dE\n",i);
}
//printf("here\n");
}
}
}
// Function to create a new node with the given key and value
Node *createNode(int key, const char *value)
{
Node *node = (Node*) malloc(sizeof(Node));
node->key = key;
strcpy(node->value, value);
node->next = NULL;
return node;
}
// Function to append a new node with the given key and value to the end of the list
Node *append(Node *head, int key, const char *value)
{
Node *newNode = createNode(key, value);
Node *curr = head;
if (head == NULL)
{
return newNode;
}
while (curr->next != NULL)
{
curr = curr->next;
}
curr->next = newNode;
return head;
}
// Function to print the linked list
void printList(Node *head)
{
Node *curr = head;
while (curr != NULL)
{
printf("(%d, %s) ", curr->key, curr->value);
curr = curr->next;
}
printf("\n");
}
The segmentation fault occurs when tail[9 - i]->next = bucket[i]; is executed.
I added printf statements (turned them into comment blocks) to trace where the error is. Can someone please help me figure out a way to get this to work?
There are a few issues:
tail[9 - i]->next = bucket[i]; sets the wrong pointer. There is no reason why it should be 9 - i. It could even be that tail[9 - i] is NULL. So this leads to indefined behaviour. Instead you should keep track of what the current tail node is in the list that is being built. You could use curr for that purpose. Let it start (before the loop) with curr = NULL and then when you find a non-null bucket, end that process by setting curr = tail[i]. When a bucket is found when the *head is no longer NULL, make the link with curr->next = bucket[i].
The new list is not terminated with a NULL pointer. When the above point is implemented, continue after the loop with curr->next = NULL.
In the next iteration of the factor loop, both digits and buckets need to be reset. You could do this with a loop or with memset.
Here is the corrected factor loop code -- comments indicate where corrections were made:
for (factor = 1; maxDigits > 0; factor *= 10, maxDigits--)
{
memset(digits, 0, sizeof(digits)); // reset!
memset(bucket, 0, sizeof(bucket)); // reset!
curr = *head;
while (curr != NULL)
{
digits[curr->key / factor % 10]++;
curr = curr->next;
}
for (i = 1; i < 10; i++)
{
digits[i] += digits[i - 1];
}
curr = *head;
while (curr != NULL)
{
int digit = curr->key / factor % 10;
if (bucket[digit] == NULL)
{
bucket[digit] = curr;
tail[digit] = curr;
}
else
{
tail[digit]->next = curr;
tail[digit] = curr;
}
curr = curr->next;
}
*head = NULL;
curr = NULL; // <-- track the current tail of the newly built list
for (i = 9; i >= 0; i--)
{
if (bucket[i] != NULL)
{
if (*head == NULL)
{
*head = bucket[i];
}
else
{
curr->next = bucket[i]; // Append bucket after the current tail
}
curr = tail[i]; // The tail is now at the end of this bucket
}
}
curr->next = NULL; // Terminate the list properly
}
I'm writing a programm in c that reads words from a file, and adds the different from them in a linked list. However, i don't get the right result.I have problem finding if a word exists in the list. Any help could be appreciated.Thanks.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct list_el {
char val[30];
struct list_el * next;
};
typedef struct list_el item, item2;
void main() {
item * curr, * head, * curr2, * head2;
FILE *fp;
char words[30];
int i;
head = NULL;
head2 = NULL;
if ((fp=fopen("file.txt","r"))==NULL)
printf("cannot open file\n");
i=0;
while (fscanf(fp,"%s",&words)!=EOF) {
if (i!=0)
while(curr2) {
if (!strcmp(words,curr2->val)){
break;
}
curr2 = curr2->next ;
}
if (curr2==0 || i==0){
curr = (item *)malloc(sizeof(item));
curr2 = (item2 *)malloc(sizeof(item2));
strcpy(curr->val,words);
strcpy(curr2->val,words);
curr->next = head;
curr2->next = head2;
head = curr;
head2 = curr2;
}
i++;
}
while(curr) {
printf("%s\n", curr->val);
curr = curr->next ;
}
fclose(fp);
}
int main(void) {//void main() is invalid.
item *curr, *head = NULL;
FILE *fp;
char words[30];
if ((fp=fopen("file.txt","r"))==NULL){
printf("cannot open file\n");
return EXIT_FAILURE;//can't continue
}
while (fscanf(fp,"%29s", words) != EOF) {//remove &
curr = head;
while(curr) {//Search the current list
if (!strcmp(words, curr->val)){
break;
}
curr = curr->next;
}
if (curr == NULL){//not find words
item *node = malloc(sizeof(*node));
strcpy(node->val, words);
node->next = head;
head = node;
}
}
fclose(fp);
curr = head;
while(curr) {
printf("%s\n", curr->val);
curr = curr->next ;
}
}
I'm working on a FIFO page replacement algorithm and have it almost working. My code uses scanf() to read in a page number then it adds that item to a linked list, up to 16 pages. However, if the page already exists in the lined list, it does not add the page to this list again. There are three page frames (slots). Everything works properly, but, it does not add that item to the list until scanf() reads another integer to add to the list. I am utterly confused.
#include<stdio.h>
#include<stdlib.h>
typedef struct node {
int num;
struct node * next;
} node_t;
void print_list(node_t * head) {
node_t * current = head;
while (current != NULL) {
printf("%d\n", current->num);
current = current->next;
}
}
int fault(node_t * head, int check) {
node_t * current = head;
while(current->next != NULL){
if(current->num == check)
return 0;
current = current->next;
}
return 1;
}
void addNode(node_t * head, int num) {
node_t * current = head;
while (current->next != NULL) {
current = current->next;
}
/* now we can add a new variable */
current->next = malloc(sizeof(node_t));
current->next->num = num;
current->next->next = NULL;
}
int pop(node_t ** head) {
int retnum = -1;
node_t * nextNode = NULL;
if (*head == NULL) {
return -1;
}
nextNode = (*head)->next;
retnum = (*head)->num;
free(*head);
*head = nextNode;
return retnum;
}
///////////////////////////////////////////////////////
int main(){
int num;
int faults = 0;
int n = 0;
int j = 0;
node_t * head = malloc(sizeof(node_t));
if (head == NULL) {
return 1;
}
head->num = -1;
printf("Input page number up to 16 pages. Enter 'q' to quit.\n");
for(j=0;j<16;j++){
if(scanf("%d\n",&num) == 1) {
if (fault(head, num) == 1 && n < 3) {
n++;
faults++;
addNode(head, num);
}
else if (fault(head, num) == 1 && n >= 3) {
pop(&head);
addNode(head,num);
faults++;
}
}
else{
int c = getchar();
if( c == 'q' ){
break;
}
}
if (n == 1 && faults == 1)
pop(&head);
printf("\nPage Table:\n");
print_list(head);
printf("\nInput page number: \n");
}
printf("Number of page faults: %d\n", faults);
}
I ran it through gdb and it doesn't even call the addNode function until the second integer has been scanned.
(And yes I know scanf is garbage, I just didn't want to bother learning how to do something else)
Thanks for the help!
Your code:
if(scanf("%d\n",&num) == 1) {
should be :
if(scanf("%d",&num) == 1) {
And head needs to be initialized.
node_t * head = malloc(sizeof(node_t));
if (head == NULL) {
return 1;
}
head->next = NULL;
I was tasked with implementing a merge sort algorithm on a list written in C/C++. I have the general idea down, wrote my code and have successfully compiled it. However, when I run it, it will begin fine but then hang on "prepared list, now starting sort" without giving any kind of error. I have tried to look through my code but I am at a complete loss as to what the issue could be. I am also pretty amateurish with debugging, so using gdb to the best of my abilities has lead me no where. Any advice or tips would be a tremendous help, thank you all!
#include <stdio.h>
#include <stdlib.h>
struct listnode
{
struct listnode *next;
int key;
};
//Finds length of listnode
int
findLength (struct listnode *a)
{
struct listnode *temp = a;
int i = 0;
while (temp != NULL)
{
i++;
temp = temp->next;
}
return i;
}
struct listnode *
sort (struct listnode *a)
{
// Scenario when listnode is NULL
if (findLength (a) <= 1)
return a;
//Find middle
int mid = findLength (a) / 2;
struct listnode *temp = a;
struct listnode *first = a;
struct listnode *second;
for (int i = 0; i < mid - 1; i++)
{
temp = a->next;
}
second = temp->next;
temp->next = NULL;
//Recursive calls to sort lists
first = sort (first);
second = sort (second);
if (first != NULL && second != NULL)
{
if (first->key < second->key)
{
a = first;
first = first->next;
}
else
{
a = second;
second = second->next;
}
}
struct listnode *head = a;
struct listnode *tail = a;
while (first != NULL && second != NULL)
{
if (first->key < second->key)
{
tail = first;
first = first->next;
tail = tail->next;
}
else
{
tail = second;
second = second->next;
tail = tail->next;
}
}
if (first == NULL)
{
while (second != NULL)
{
tail = second;
second = second->next;
tail = tail->next;
}
}
while (first != NULL)
{
tail = first;
first = first->next;
tail = tail->next;
}
return a;
}
Here is the test code provided, written in C:int
main (void)
{
long i;
struct listnode *node, *tmpnode, *space;
space = (struct listnode *) malloc (500000 * sizeof (struct listnode));
for (i = 0; i < 500000; i++)
{
(space + i)->key = 2 * ((17 * i) % 500000);
(space + i)->next = space + (i + 1);
}
(space + 499999)->next = NULL;
node = space;
printf ("\n prepared list, now starting sort\n");
node = sort (node);
printf ("\n checking sorted list\n");
for (i = 0; i < 500000; i++)
{
if (node == NULL)
{
printf ("List ended early\n");
exit (0);
}
if (node->key != 2 * i)
{
printf ("Node contains wrong value\n");
exit (0);
}
node = node->next;
}
printf ("Sort successful\n");
exit (0);
}
You're close, but with some silly errors. Check the append operations in the merge step. They're not doing what you think they are. And of course you meant temp = temp->next; in the splitting loop.
If gdb is overwhelming, adding printf's is a perfectly fine way to go about debugging code like this. Actually you want to write a list printing function and print the sublists at each level of recursion plus the results of the merge step. It's fun to watch. Just be neat and delete all that when you're done.
Here's code that works for reference:
struct listnode *sort(struct listnode *lst) {
if (!lst || !lst->next) return lst;
struct listnode *q = lst, *p = lst->next->next;
while (p && p->next) {
q = q->next;
p = p->next->next;
}
struct listnode *mid = q->next;
q->next = NULL;
struct listnode *fst = sort(lst), *snd = sort(mid);
struct listnode rtn[1], *tail = rtn;
while (fst && snd) {
if (fst->key < snd->key) {
tail->next = fst;
tail = fst;
fst = fst->next;
} else {
tail->next = snd;
tail = snd;
snd = snd->next;
}
}
while (fst) {
tail->next = fst;
tail = fst;
fst = fst->next;
}
while (snd) {
tail->next = snd;
tail = snd;
snd = snd->next;
}
tail->next = NULL;
return rtn->next;
}
On my old MacBook this sorts 10 million random integers in a bit over 4 seconds, which doesn't seem too bad.
You can also put the append operation in a macro and make this quite concise:
struct listnode *sort(struct listnode *lst) {
if (!lst || !lst->next) return lst;
struct listnode *q = lst, *p = lst->next->next;
while (p && p->next) {
q = q->next;
p = p->next->next;
}
struct listnode *mid = q->next;
q->next = NULL;
struct listnode *fst = sort(lst), *snd = sort(mid);
struct listnode rtn[1], *tail = rtn;
#define APPEND(X) do { tail->next = X; tail = X; X = X->next; } while (0)
while (fst && snd) if (fst->key < snd->key) APPEND(fst); else APPEND(snd);
while (fst) APPEND(fst);
while (snd) APPEND(snd);
tail->next = NULL;
return rtn->next;
}
Does it have to be a top down merge sort? To get you started, here's a partial fix, didn't check for other stuff. The | if (first != NULL && second != NULL) | check isn't needed since the prior check for length <= 1 takes care of this, but it won't cause a problem.
while (first != NULL && second != NULL)
{
if (first->key < second->key)
{
tail->next = first;
tail = first;
first = first->next;
}
else
{
tail->next = second;
tail = second;
second = second->next;
}
}
if (first == NULL)
{
tail->next = second;
}
else
{
tail->next = first;
}
}
I'm busy with implementation of singly linked list and have 2 functions: insert_back and insert_after.
Here is the listing of them:
void insert_back(int data)
{
node *temp1;
temp1 = (node*)malloc(sizeof(node));
temp1 = head;
while (temp1->next != NULL) {
temp1 = temp1->next;
}
node *temp;
temp = (node*)malloc(sizeof(node));
temp->data = data;
temp->next = NULL;
temp1->next = temp;
}
void insert_after(int pos, int data)
{
node *temp1;
temp1 = (node*)malloc(sizeof(node));
temp1 = head;
for (int i = 1; i < pos; i++) {
temp1 = temp1->next;
if (temp1 == NULL) {
return;
}
}
node *temp;
temp = (node*)malloc(sizeof(node));
temp->data = data;
temp->next = temp1->next;
temp1->next = temp;
}
As you can see they are almost the same and for insert back I want to write insert_after(null, 10). I can solve it by adding if condition and choose one of the loops, but it's not my aim.
Is it possible somehow to use one while or for loops together for serial numbers and null?
Also I see that param int pos is int. Should I use 0 instead of null?
You unnecessarily allocate memory in the following lines.
temp1 = (node*)malloc(sizeof(node));
temp1 = head;
This allocated memory will leak as you overwrite the returned address in temp1. You just need temp1 to walk over the list, so there is also no need to allocate any node itself. temp1 can point to any node.
I've taken the liberty to kind of from scratch write a routine doing both things in one go. If pos < 0 it will add the element to the end of the list, otherwise it will add it after the pos-th element, where the first element corresponds with pos == 1. If pos == 0 the element is added at the start of the list.
Also a small main is added to test the routine. new_node has been added to test if memory is not exhausted.
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
struct node * next;
int data;
} node;
node * head = NULL;
node * new_node(void)
{
node * result = malloc(sizeof(*result));
if (result == NULL)
{
fprintf(stderr, "Out of memory.\n");
exit(10);
}
return result;
}
void insert_after(int pos, int data)
{
node *walk, * prev;
int i;
prev = NULL;
walk = head;
for (i = 0; walk != NULL && i != pos; i++)
{
prev = walk;
walk = walk->next;
}
if (i != pos && pos > 0)
{
fprintf(stderr, "Location not found.\n");
exit(9);
}
else
{
walk = new_node();
walk->data = data;
if (prev == NULL)
{
walk->next = head;
head = walk;
}
else
{
walk->next = prev->next;
prev->next = walk;
}
}
}
int main(void)
{
int i;
node * wlk;
for (i = 0; i < 10; i++)
{
insert_after(-1, i);
}
for (i = 0; i < 10; i++)
{
insert_after(3, i+10);
}
for (wlk = head; wlk != NULL; wlk = wlk->next)
{
printf("%d\n", wlk->data);
}
return 0;
}
Since you are testing for the end of the chain with insert_after(pos,...) anyway, you could go for:
void insert_after(int pos, int data)
{
node *temp1= head;
for (int i=1; i<pos; i++) {
if (temp1->next==NULL) {
if (pos==INT_MAX)
break; // pos of INT_MAX means insert at end
// so we continue with this last item and append
else
return; // pos higher than length of chain
}
temp1 = temp1->next;
}
...
}
Or slightly more compact:
void insert_after(int pos, int data)
{
node *temp1= head;
for (int i=1; i<pos && temp1->next!=NULL; i++) {
temp1 = temp1->next;
}
if (temp1->next==NULL && pos!=INT_MAX)
return; // pos higher than length of chain, except for
// INT_MAX (for that we just want to continue)
...
}
Then you could use
void insert_back(int data)
{
insert_after(INT_MAX, data);
}