A flexible list with indefinite number of nodes - c

I am supposed to make a linked list that takes in strings and prints them out in the reverse order. Normally I'd ask the number of nodes that need to be created, and then ask for the data in a for loop until we're done.
typedef struct word_st {
string word; // string is meant to be a pointer to a struct
word_st *next;
}
But the problem is, the number of nodes isn't known until runtime. So I have to keep asking for data until the user is done. I'm not really sure where to start/how to do that and can't seem to find anything on the internet either. So a hint would be very helpful.
I have my insert function and the print function looks fairly simple too.
word_t *insert_2(word_t* head, string text) {
word_t * p = NULL;
word_t * temp = (word_t*) malloc(sizeof(word_t));
temp -> word = text;
temp -> next = NULL;
if(head == NULL) {
head = temp;
} else {
p = head;
} while(p -> next != NULL) {
p = p -> next;
}
p -> next = temp;
return head;
}

In reverse, replace next by prev:
typedef struct word_st {
string word; // string is meant to be a pointer to a struct
word_st * prev;
}
And the function:
word_t *insert_2(word_t* head, string text) {
word_t * nextHead = (word_t*) malloc(sizeof(word_t));
nextHead -> word = text;
nextHead -> prev = NULL;
// Check first element of LIFO
if( head == NULL ) {
return nextHead;
}
nextHead -> prev = head;
return nextHead;
}
I hope It compiles and work.
Note:
for(word_t * head = last ; head->prev != NULL ; head = head->prev )
{
// Do the job
;
}

Related

Sorting linked list by manipulating pointers

I'm trying to implement Shell sort on a linked list. I divide my original linked list into sub linked list, which contain nodes that have 'k' gap regarding the shell sort algorithm. I want to sort the sub linked list by manipulating the 'next' pointers instead of changing its data field. So I have a sortList function that traverses the linked list and swaps the nodes with swapNodes if it encounters any unordered nodes.
When I pass an unordered linked list with two elements to the sortList I keep loosing one of the nodes in my list. For example, I have 50 and -84 in my list, I pass it to sortList. After the sortList figures that they're unordered it calls swapNodes, but once swapNodes terminates, the resulting list only has 50.
I tried to gdb and found out that when I'm in swapNodes scope the list gets sorted successfully without losing a node, but when it terminates and turns back to sortList scope, both the head and curr points only to 50 and their 'next' field is NULL.
My functions:
void sortList(Node * head, long * n_comp) {
Node * curr;
int didSwap = 1;
while(didSwap) {
didSwap = 0;
for(curr = head; curr -> next != NULL; ) {
*n_comp += 1; //number of comparison
if(curr->value > curr->next->value) {
swapNodes(curr, curr->next, &head);
didSwap = 1;
}
curr = curr -> next;
if (!curr) break;
}
}
}
void swapNodes(Node * p1, Node * p2, Node ** start)
{
Node *p1pre = NULL;
Node *p1curr = *start;
while (p1curr && p1curr!=p1)
{
p1pre = p1curr;
p1curr = p1curr->next;
}
Node *p2pre = NULL;
Node *p2curr = *start;
while (p2curr && p2curr != p2)
{
p2pre = p2curr;
p2curr = p2curr->next;
}
if (p1pre != NULL)
{
p1pre->next = p2curr;
}
else
{
*start = p2curr;
}
if (p2pre != NULL)
{
p2pre->next = p1curr;
}
else
{
*start = p1curr;
}
Node *temp = p2curr->next;
p2curr->next = p1curr->next;
p1curr->next = temp;
return;
}
``
It's happening for the same reason why you gave start type Node** in the first place: your node [50] is being moved and head moves with it instead of staying at the start of the list. You need to change your sortList method so the parameter head also has type Node**:
void sortList(Node ** head, long * n_comp) {
Node * curr;
int didSwap = 1;
while(didSwap) {
didSwap = 0;
for(curr = *head; curr -> next != NULL; ) {
std::cout<< "It: " << *n_comp<< std::endl;
*n_comp += 1; //number of comparison
if(curr->value > curr->next->value) {
swapNodes(curr, curr->next, head);
didSwap = 1;
}
curr = curr -> next;
if (!curr) break;
}
}
}
Now your head will stay at the start of the list.
Note: this is one of the reasons why sentinel nodes are a thing.

strcpy() to copy string from struct member to char array is failing. Why?

I have a structure node which is used to create a binary search tree. Inside each node I am storing a integer KEY and a corresponding string value. I am performing some searches within the tree and wish to return arrays containing key value pairs of only specific nodes.
TO do so I am passing arrays by reference and saving the integer KEY to that array. This works fine, however when I try to the the same with the string I am getting poor results.
In the below code I am trying to copy the string inside root[count].value; to p_value_arr[*p_unique_count] which is a char array.
Struct definition:
typedef struct node {
int KEY;
char *value;
int node_count;
struct node *left, *right;
int unique_count;
} node;
Function to traverse graph and copy unique key value pairs. KEY is being copied correctly to an array while value is not.
void unique_key(node *root, int *p_unique_count, int p_unique_arr[], char *p_value_arr[]) {
int count = 0;
//unique *temp = (unique *)malloc(n * sizeof(unique));
if (root != NULL)
{
unique_key(root->left, p_unique_count, p_unique_arr, p_value_arr);
if (root->node_count == 1) {
root[count].unique_count = *p_unique_count;
p_unique_arr[*p_unique_count] = root[count].KEY;
printf("%s\n", root[count].value);
//"warning: assignment makes integer from pointer without a cast"
strcpy(p_value_arr[*p_unique_count],root[count].value);
printf("%d(%d) -> %s %d\n", root->KEY, root->node_count, root->value, root->unique_count);
(*p_unique_count)++;
count++;
}
unique_key(root->right, p_unique_count, p_unique_arr, p_value_arr);
}
}
A utility function to insert a new node with given key in BST
node* insert_node(node* node, int key, char *value)
{
/* If the tree is empty, return a new node */
if (node == NULL)
return newNode(key,value);
// If key already exists in BST, icnrement count and return
if (key == node->KEY)
{
(node->node_count)++;
// return node;
}
/* Otherwise, recur down the tree */
if (key < node->KEY)
node->left = insert_node(node->left, key, value);
else
node->right = insert_node(node->right, key, value);
/* return the (unchanged) node pointer */
return node;
}
node *newNode(int KEY, char *value)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->KEY = KEY;
strcpy(temp->value, value);
temp->left = temp->right = NULL;
temp->node_count = 1;
return temp;
}
Main driver code
int main() {
int unique_count = 0;
int in_count = 0;
int unique_arr[10]; /
char *value_arr[10]; // an array of pointers
/* Let us create following BST. Passing values along with key */
node *root = NULL;
//this is for storing commands
root = insert_node(root, 2, "Hello");
root = insert_node(root, 3, "Thanks");
printf("\nkeys of the given tree \n");
unique_key(root, &unique_count, unique_arr, *value_arr);
for(int i = 0; i < 10; i++) {
printf("%d %s\n", unique_arr[i], value_arr[i]); //Mismatching the argument type "char" and conversion specifier "s" and nothing prints here
}
}
Output:
Hello
keys of the given tree
Segmentation fault
Any suggestions on how I can effectively copy a string inside a struct member to an array of chars?
EDIT:
Full code: https://pastebin.com/CB4Gp0gY
Since char *value_arr[10]; is an array of pointers I followed chapter 5.6 of K&R The C programming language to pass the array of pointers to the function. I get no warnings now, but the seg fault persists.
I also have more warnings set on my NetBeans 8.2.
Output from debugger:
/cygdrive/C/Users/****/AppData/Roaming/NetBeans/8.2/bin/nativeexecution/dorun.sh: line 71: 16516 Segmentation fault (core dumped) sh "${SHFILE}"
Gonna follow up for Lundin here
node *newNode(int KEY, char *value)
{
// Allocate a new overall structure
struct node *temp = (struct node *)malloc(sizeof(struct node));
//Copy the integer key
temp->KEY = KEY;
// uh oh - copy the given string into a random location in memory and segfault.
// Hint - you need to allocate enough memory to hold the incoming string.
// Advanced hint - If you don't want to make a copy of the string, you can
// just store its pointer, but it would want to be marked constant at the least...
strcpy(temp->value, value);
// Set tree stuff and count, but we are already dead...
temp->left = temp->right = NULL;
temp->node_count = 1;
return temp;
}
Also,
printf("%d %s\n", unique_arr[i], value_arr[i]); //Mismatching the argument type "char" and conversion specifier "s" and nothing prints here
Will fail because value_arr[i] is not a string, it is a char *. For this to work, it would have to point at a valid C string, or would need to point to memory that has a properly '\0' terminated string.
Take a look at his given link as you need a deeper understanding of how C strings work.
char *value_arr[10]; // the problem is here
That initializes an array of pointers but does not assign memory to those pointers before using them for stuff like strcpy(). As per K&R chapter 5.6 one should allocate memory using alloc() for the pointer array inside the function.
If you want a pointer to point to some memory for storing a string, then you have to create such an area of memory and set the pointer to point to it.
char *p;
alloc(strlen(root[count].value) +1);
strcpy(p, root[count].value);
p_value_arr[*p_unique_count] = p;
struct node_t*curr = head;
struct node_t*node = (struct node_t*)malloc(sizeof(struct node_t));
strcpy(node -> str,str);
node -> prev = NULL;
node -> next = NULL;
if(curr == NULL)
{
head = node;
tail = node;
return
}
int value = strcmp(curr -> str,str);
if(value>0)
{
head = node;
node -> next = curr;
curr -> prev = node;
return;
}
struct node_t* prev = curr;
curr = prev -> next;
while(curr != NULL)
{
value=strcmp(prev -> str,str);
if(value < 0)
{
int value1 = strcmp(curr -> str,str)
if(value1>0)
{
node -> prev = prev;
node -> next = curr;
node -> next = node;
node -> prev = node;
}
else if(value1 == 0)
{
if(curr -> next == NULL)
tail=prev;
prev -> next = curr -> next;
curr -> prev = NULL
return;
}
}
prev = curr;
curr = prev -> next;
}
prev -> next = node;
node -> prev = prev;
tail = node;

Creating a sublist of the original list?

I'm trying to make a function that takes two parameters positions to take from list and original list and then copy indexed numbers to a list. Also i included the Struct for the list and the head. I get the EXC_BAD_ACCESS Error i commented the line.
code:
struct node_struct {
Item item;
link next;
};
struct list_struct {
link first;
int length;
};
list sublist(list A, list pos_list) {
int index = 0;
link tempForindex = malloc(sizeof *tempForindex);
link temp2 = malloc(sizeof *temp2);
list finale = malloc(sizeof *finale);
link temp3 = malloc(sizeof *temp3);
tempForindex = pos_list->first;
temp2 = A->first;
temp3 = finale->first;
int counter = 0;
while(tempForindex->next != NULL)
{
index = tempForindex->item;//EXC_BAD_ACCESS code1
counter = 0;
while(temp2->next != NULL)
{
if (counter == index)
{
temp3->item = temp2->item;
temp2 = A->first;
temp3 = temp3->next;
break;
}
temp2 = temp2->next;
counter++;
}
tempForindex = tempForindex->next;
}
return finale;
}
It all hopelessly flawed.
You need to get patterns going with linked lists. The structures are fine, but the fact that the code is crashing in the position indicated suggests to me that pos_list has not been set up correctly.
iterate through a list using this pattern
list mylist;
link ptr;
for(ptr = mylist->first; ptr != NULL; ptr = ptr->next)
{
/* loop body */
}
now write a test function to print out both arguments and ascertain that they are valid.

Reverse a linked list using recursion technique in C

I have the following C code which returns the reverse of a linked list.
Though it reverses the linked list, I never get the head of the reversed linked list because the restofElements node is getting overwritten.
S *reverseRecursive(S *headref) {
S *firstElement = NULL;
S *restOfElements = NULL;
if (headref==NULL) {
return ;
}
firstElement = headref;
restOfElements = headref->next;
if (restOfElements == NULL)
return headref;
reverseRecursive(restOfElements);
firstElement->next->next = firstElement;
firstElement->next = NULL;
headref = restOfElements;
return headref;
}
How can I get the head of the reversed linked list node returned to the calling program?
If you want to change the head pointer, you must pass it by reference (as a pointer). The prototype should be modified to receive the head as S **.
S *reverseRecursive(S **headref);
The head of the reversed list is equal to the head of the reversed List starting with restOfElements (because the original headref has to become tha last element of the reversed list). So storing the result of the recussive call should do (as Jim has already suggested in his comment):
...
headref = reverseRecursive(restOfElements);
firstElement->next->next = firstElement;
firstElement->next = NULL;
/* headref = restOfElements; that's wrong */
return headref;
Thanks everyone. I have modified it little bit and it works now. Let me know your comments.
new_head is a global variable.
S *reverseRecursive(S *headref)
{
S *firstElement = NULL;
S *restOfElements = NULL;
if (headref==NULL)
{
return ;
}
firstElement = headref;
if (headref->next == NULL)
return headref;
else
restOfElements = headref->next;
reverseRecursive(restOfElements);
firstElement->next->next = firstElement;
firstElement->next = NULL;
if(new_head == NULL ) //just dont take it ervery time
new_head = restOfElements;
return new_head;
}
Probably closer.
S *reverseRecursive(S *headref)
{
S *firstElement = NULL;
S *restOfElements = NULL;
S *new_head = NULL;
if (headref==NULL)
{
return ;
}
firstElement = headref;
restOfElements = headref->next;
if (restOfElements == NULL)
return headref;
new_head = reverseRecursive(restOfElements);
restOfElements->next = new_head;
return restOfElements;
}
$ gcc -std=c99 -Wall -Wextra reverse.c
#include <stdlib.h>
#include <stdio.h>
typedef struct list {
struct list* next;
int data;
} S;
void print_list(S* list) {
if (list == NULL) { printf("NULL\n"); return; }
printf("%d ", list->data);
print_list(list->next);
}
S* reverse_aux(S* list, S* tail) {
// invalid arg
if (list == NULL) { return NULL; }
// base case
if (list->next == NULL) {
list->next = tail;
return list;
}
// general case
S* tmp = list->next;
list->next = tail;
return reverse_aux(tmp, list);
}
S* reverse(S* list) { return reverse_aux(list, NULL); }
int main(int argc, char* argv[]) {
// build a list with which to test
S a[10];
for (unsigned i = 0; i < sizeof(a)/sizeof(S); ++i) {
a[i].data = i;
a[i].next = &a[i+1];
}
a[sizeof(a)/sizeof(S) - 1].next = NULL;
S* list = &a[0];
print_list(list);
list = reverse(list);
print_list(list);
return 0;
}
Actually, since reverse is destructive (it mutates its argument), a better interface design would probably be
void reverse(S** plist);
reverse(&list);
So there's two ways to reverse a list in place recursively.
First, some setup. Let's make it easy to load linked lists
of strings and print them, so we can make sure this stuff works:
// linked_list.c
#include <stdio.h>
#include <stdlib.h>
// a linked lis of strings
typedef struct S {
struct S * next;
char * val;
} S;
// print out the list
void showS(char * const name, S * head) {
printf("%s: (", name);
while (head){
printf(" ");
printf("%s",head->val);
head = head->next;
printf( "%c", head ? ',' : ' ' );
}
printf(")\n");
}
// convert an array of strings into a linked list of strings
S * mkS(int n, char ** args) {
S * head = NULL;
if (n > 0 && (head = calloc(n, sizeof(S)))){
S * curr = head - 1;
while (n-- > 0) {
curr++;
curr->val = *args++;
curr->next = curr + 1;
}
curr->next = NULL;
}
return head;
}
One way of reversing the list involves passing back the new head of the
list once we find it. We don't need it locally (since we're just moving
the current element to the new end), but we'll need it so that the caller
has a pointer to the head of the list once we're done.
// reverse a list one way
S * revS1( S * const head ){
if (head && head->next) {
S * const new_head = revS1( head->next );
head->next->next = head;
head->next = NULL;
return new_head;
} else {
return head;
}
}
Another way takes a pointer to a pointer. The only difference is that
we don't need to return anything, since we're directly modifying a variable
the caller has. I prefer this calling method since it's much clearer
that we're modifying the list, not returning a copy. It's also harder
for the caller to accidentally loose the pointer to the new head this way.
// reverse a list another way
void revS2( S ** phead ){
S * const head = *phead;
if (head && head->next) {
*phead = head->next;
revS2( phead );
head->next->next = head;
head->next = NULL;
}
}
But what's better than either of these is to reverse the list non-recursively.
Neither of those functions is tail-recursive, so the compiler has
to allocate new stack frames for each element in the list. Try to reverse a long
enough list, and you'll blow your stack. Much better to just reverse the list
using a while loop.
// reverse a list non-recursively
void revS3( S ** phead ){
S * head = *phead;
S * reversed = NULL;
while (head) {
S * curr = head;
head = curr->next;
curr->next = reversed;
reversed = curr;
}
*phead = reversed;
}
Now we can test our results just by building lists out of the command line:
// just use the command line arguments as our list
int main(int argc, char** argv){
S* list1 = mkS(argc - 1, argv + 1);
S* list2 = mkS(argc - 1, argv + 1);
S* list3 = mkS(argc - 1, argv + 1);
showS( "given", list1 );
showS( "revS1", revS1(list1) );
revS2( &list2 );
showS( "revS2", list2 );
revS2( &list3 );
showS( "revS3", list3 );
return 0;
}
So let's compile:
% gcc -Wall linked_list.c -o linked_list
And do some test runs
% ./linked_list
given: ()
revS1: ()
revS2: ()
revS3: ()
% ./linked_list first second third
given: ( first, second, third )
revS1: ( third, second, first )
revS2: ( third, second, first )
revS3: ( third, second, first )
% ./linked_list only
given: ( only )
revS1: ( only )
revS2: ( only )
revS3: ( only )

Deleting items from a structure

I have the following linked list:
struct scoreentry_node {
struct scoreentry_node *next;
int score;
char name[1];
}
;
typedef struct scoreentry_node *score_entry;
I'm trying to write a function that removes all nodes that contain a certain name. Here is what I have so far but I'm not sure I'm right:
score_entry disqualify(score_entry a, char* name)
{
score_entry tmp = a;
while (tmp != NULL){
if (strcmp(tmp->name, name) == 0)
{
score_entry trash = tmp;
tmp = tmp->next;
free(trash);
}
else { tmp = tmp->next; }
}
return a;
}
It gives me heap error's .. Any suggestions?
score_entry disqualify(score_entry a, char* name)
{
score_entry new_front = a, tmp;
// delete "wrong" entries from the front
while (new_front != NULL){
if (strcmp(new_front->name, name) == 0)
{
score_entry trash = new_front;
new_front = new_front->next;
free(trash);
}
else
{
// first list entry is valid
// delete "wrong" entries from inside the list
tmp = new_front;
while ( tmp->next != NULL )
{
if ( strcmp(tmp->next->name,name)==0 )
{
score_entry trash = tmp->next;
tmp->next = tmp->next->next;
free(trash);
} else
{
tmp = tmp->next;
}
}
}
}
return new_front;
}
You should also obtain some book related to common data structures - you seem to be interested in the stuff, and it could be a great help for you.
If you delete a member from the list you must fix the gap this creates by linking the 'next' pointer of the previous entry to the following entry. The code below does that. Note that I have changed score_entry so that the typedef no longer contains the pointer - I prefer not to disguise types. Notice that the function returns the head which might have changed if we deleted the first entry in the list.
typedef struct scoreentry_node score_entry;
static score_entry *
disqualify(score_entry *head, const char *name)
{
score_entry *se = head;
score_entry *prev = head;
while (se) {
if (!strcmp(se->name, name)) {
score_entry *next = se->next;
if (head == se) {
head = next;
} else {
prev->next = next;
}
free(se);
se = next;
} else {
prev = se;
se = se->next;
}
}
return head;
}
You're using strcmp on a non-null-terminated string (tmp->name). I'm assuming it's not null-terminated as it's only of length 1. Seems like you're really comparing a character, not a string, so a simple character equality operator would be the right thing to do.

Resources