I've implemented a Singly Linked List, and I'm noticing really strange behavior but can't pinpoint the exact reason why it's happening. I've tried using gdb to figure out what the problem is, and it looks like whenever I compute the size of a list, that's when things start to go wrong. This is the program I'm using to test out my implementation, and following is the actual implementation.
#include <stdio.h>
#include "singlylinked.h"
slist initialize(void); /* initializes test singly linked list */
slist initialize(){
int i, a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
slist l = sl_alloc();
int a_size = sizeof(a)/sizeof(a[0]);
for(i=0;i<a_size;i++){
sl_add(l, (void *)&a[i]);
}
return l;
}
int main(){
slist l = initialize();
int i, size = sl_size(l);
for(i = 0; i < size; i++){
printf("%d ", *(int *)sl_get(l,i));
}
fputc('\n',stdout);
return 0;
}
And now the actual implementation, I'm only going to post the methods used in the testing:
/* allocates an empty slist */
slist sl_alloc(){
return (slist) calloc(1, sizeof(struct node));
}
/* adds val to linked list */
void sl_add(slist l, void *val){
node *current, *new;
new = calloc(1, sizeof(struct node));
new->content = val;
new->next = NULL;
if((current = *l)){
while(current->next){
current = current->next;
}
current->next = new;
} else {
*l = new;
}
}
/* returns ith value in singly linked list l */
void *sl_get(slist l, int i){
node *current;
int j; /* counter */
void *result = NULL;
if((current = *l)){
int size = sl_size(l);
if(i < size){
for(j = i; j > 0; j--){
current = current->next;
}
result = current->content;
}
}
return result;
}
/* returns the size of the singly linked list */
int sl_size(slist l){
int size = 0;
node *current;
if((current = *l)){
do {
size++;
current = current->next;
} while (current);
}
return size;
}
And now this is how I define slist and struct node:
typedef struct node **slist;
typedef struct node {
void *content;
struct node *next;
} node;
EDIT: The strange behavior is this: When I try to print things out, it prints out the wrong values in the list. When I ran the program using gdb, this starts to happen after the first call to sl_size.
The problem is your initialisation of the list.
You add the 10 elements of the array a[] to the list that you are creating in initialize(). The only problem is that you store in your list nodes pointers to the data in the array a[]. Unfortunately this array is local to the function ! As soon as you return from initialize(), this array is no longer valid, and the pointer point to no valid place anymore. In consequence, the numbers that you expect to point to will be replaced by "garbage" value.
Related
So I wanted to write a function to reverse a linked list using an array of pointers but I'm getting warnings: assignment from incompatible pointer type [-Wincompatible-pointer-types]. I wanted to store the pointers to nodes of the list in an array of pointers int **s = (int **)calloc(10, sizeof(int)); and thought that s[*top] = *l will assign the pointer to which **l is pointing to *topth element of array *s[]. So am I wrong thinking that elements of array *s[] are pointers? If someone could explain it to me I'd be very glad. Here's the whole code (except the part where I create the list which is fine):
typedef struct list {
int v;
struct list *next;
} list;
void reverseListS(list **l, int **s, int *top) {
while ((*l)->next != NULL) {
s[*top] = *l;
*top++;
*l = (*l)->next;
}
list *temp = *l;
while (!(*top == 0)) {
temp->next = s[*top];
*top--;
temp = temp->next;
}
temp->next = NULL;
}
int main() {
int **s = (int **)calloc(10, sizeof(int));
int *top = 0;
reverseListS(&l, s, top);
}
Many issues. Just in main: Should be sizeof(int *) (or sizeof *s). Although, I think you want s to be an array of ints, so it should be an int *. And top does not point anywhere - why is it even a pointer?. l is not initialized.
In reverseListS at s[*top] = *l; you are trying to assign a struct list * to an int *.
I have re-written your code to work. I'm not saying this is the best way to reverse a list, but it makes the fewest modifications to your code - as I understand it.
typedef struct list {
int v;
struct list *next;
} list;
void reverseListS(list **l)
{
// Count number of items
// *this step could be skipped by dynamically resizing the array with realloc
int count = 0;
list *temp = *l;
while (temp) {
count += 1;
temp = temp->next;
}
// Allocate memory - an array of list *
list **s = malloc(count * (sizeof *s));
if (!s) return;
// Copy list item addresses to array
temp = *l;
int index = 0;
while (temp) {
s[index++] = temp;
temp = temp->next;
}
// Rebuild the list in reverse order
// *if you already have an "append_to_list" function, that should be used here
temp = NULL;
for (int i = index - 1; i >= 0; i--) {
if (!temp) {
// This is the new first item in list.
// Make the original list point to it
*l = temp = s[i];
}
else {
// Append to end of new list
temp->next = s[i];
temp = s[i];
}
s[i]->next = NULL;
}
free(s);
}
int main() {
list *l;
// TODO: Fill the list with values.
reverseListS(&l);
}
Kindly explain push function. I could not get why loop is used . For char and int (new_node->data=new_data) works fine . But for string , it doesn't . For string , error is produced. If char(%c) is printed for new_data in push() method then only first character is printed , while if char(%c) is printed for new_node->data then last characater is printed.
// C program for generic linked list
#include<stdio.h>
#include<stdlib.h>
/* A linked list node */
struct node
{
// Any data type can be stored in this node
void *data;
struct node *next;
};
/* Function to add a node at the beginning of Linked List.
This function expects a pointer to the data to be added
and size of the data type */
void push(struct node** head_ref, void *new_data, size_t data_size)
{
// Allocate memory for node
struct node* new_node = (struct node*)malloc(sizeof(struct node));
new_node->data = malloc(data_size);
new_node->next = (*head_ref);
// Copy contents of new_data to newly allocated memory.
// Assumption: char takes 1 byte.
int i;
//Why loop is used for copying data from new_data to new_node data.
for (i=0; i<data_size; i++)
*(char *)(new_node->data + i) = *(char *)(new_data + i);
// Change head pointer as new node is added at the beginning
(*head_ref) = new_node;
}
/* Function to print nodes in a given linked list. fpitr is used
to access the function to be used for printing current node data.
Note that different data types need different specifier in printf() */
void printList(struct node *node, void (*fptr)(void *))
{
while (node != NULL)
{
(*fptr)(node->data);
node = node->next;
}
}
// Function to print an integer
void printInt(void *n)
{
printf(" %d", *(int *)n);
}
// Function to print a float
void printFloat(void *f)
{
printf(" %f", *(float *)f);
}
/* Driver program to test above function */
int main()
{
struct node *start = NULL;
// Create and print an int linked list
unsigned int_size = sizeof(int);
int arr[] = {10, 20, 30, 40, 50}, i;
for (i=4; i>=0; i--)
push(&start, &arr[i], int_size);
printf("Created integer linked list is \n");
printList(start, printInt);
// Create and print a float linked list
unsigned float_size = sizeof(float);
start = NULL;
float arr2[] = {10.1, 20.2, 30.3, 40.4, 50.5};
for (i=4; i>=0; i--)
push(&start, &arr2[i], float_size);
printf("\n\nCreated float linked list is \n");
printList(start, printFloat);
return 0;
}
yes , we can also do new_node->data=new_data instead of using this loop
for (i=0; i<data_size; i++)
*(char *)(new_node->data + i) = *(char *)(new_data + i);
but there is difference between them. when we simply using new_node->data=new_data we are shallow copying.therefore two pointers pointing to the same location i.e if you change the values of arr[] then automatically the values in the struct changes.
when you using loop you are deep copying i.e if you change the values of the arr[] then the values of the struct will not get changed.
run the below code to understand the differnce.
// C program for showing shallow copy in generic linked list
#include<stdio.h>
#include<stdlib.h>
/* A linked list node */
struct Node
{
// Any data type can be stored in this node
void *data;
struct Node *next;
};
/* Function to add a node at the beginning of Linked List.
This function expects a pointer to the data to be added
and size of the data type */
void push(struct Node** head_ref, void *new_data, size_t data_size)
{
// Allocate memory for node
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
new_node->data = malloc(data_size);
new_node->next = (*head_ref);
// Copy contents of new_data to newly allocated memory.
// Assumption: char takes 1 byte.
int i;
// no loop just normal assignment of new_data
new_node->data=new_data;
printf("\n");
// Change head pointer as new node is added at the beginning
(*head_ref) = new_node;
}
/* Function to print nodes in a given linked list. fpitr is used
to access the function to be used for printing current node data.
Note that different data types need different specifier in printf() */
void printList(struct Node *node, void (*fptr)(void *))
{
while (node != NULL)
{
(*fptr)(node->data);
node = node->next;
}
}
// Function to print an integer
void printInt(void *n)
{
printf(" %d", *(int *)n);
}
// Function to print a float
void printFloat(void *f)
{
printf(" %f", *(float *)f);
}
/* Driver program to test above function */
int main()
{
struct Node *start = NULL;
// Create and print an int linked list
unsigned int_size = sizeof(int);
int arr[] = {1,2,3,4,5}, i;
for (i=4; i>=0; i--)
push(&start, &arr[i], int_size);
printf("Created integer linked list is \n");
printList(start, printInt);
printf("\n");
// changing the values in arr[]
arr[1]=45;
arr[3]=1000;
//printing the struct
printf("printing the struct after changing the values in the array \n");
printList(start, printInt);
/*
// Create and print a float linked list
unsigned float_size = sizeof(float);
start = NULL;
float arr2[] = {10.1, 20.2, 30.3, 40.4, 50.5};
for (i=4; i>=0; i--)
push(&start, &arr2[i], float_size);
printf("\n\nCreated float linked list is \n");
printList(start, printFloat);*/
return 0;
}
I want to create a linked list.
The user adds numbers and the idea is that the numbers are inserted to the list in descending order.
Here goes what I did, but when rearranging, it just orders the first number...
int addInputNumber(numberList **node){
numberList *temp;
int userInput;
temp = (numberList*)malloc(sizeof(numberList));
//Memory Check
if ( temp == 0 )//out of memory, return 0
return 0;
//Get the users input
printf("Give me a Number!\n");
scanf("%d",&userInput);
//Add it to the list.
temp->numbero = userInput;
///Link to the list.
temp->next = *node;
*node = temp;
//Lets cycle through the list.
numberList *temp2;
int helpNumber;
temp2 = *node;
//Rearrange the list.
while(temp2 != 0){
if(temp->numbero < temp2->numbero){
//Switch position..
helpNumber= temp2->numbero;
temp2->numbero = temp->numbero;
temp->numbero = helpNumber;
temp2 = *node;// If we change number, we must cycle from the beginning AGAIN.
}//eof if
temp2 = temp2->next;
}//eof while
return 0;
}//eof addNUmber function.
Here's the structure just in case:
typedef struct dynamicNumberList {
int numbero;
struct dynamicNumberList *next;
}numberList;
I've got 2 quick questions.
Why would it only arrange the first number?
This list adds a space towards the left (visually), how could I make it so I can add a space to the right?
You need to get into the habit of creating one function per task, instead of cramming everything into a single one. It makes the code easier to read and reuse and reduces the chance of errors.
A correct implementation could look like this:
#include <stdio.h>
#include <stdlib.h>
typedef struct s_List
{
int n;
struct s_List *next;
} List;
void print_list (List *head)
{
List *ptr;
for (ptr = head; ptr; ptr = ptr->next) {
printf ("%d\t", ptr->n);
}
putchar ('\n');
}
List * make_node (int n, List *next)
{
List * node = malloc (sizeof(List));
node->n = n;
node->next = next;
return node;
}
void insert_number_front (List **head, int n)
{
*head = make_node (n, *head);
}
void insert_number_after (List *prev, int n)
{
prev->next = make_node (n, prev->next);
}
// If HEAD is sorted, it will stay sorted after insertion
void insert_number_sorted (List **head, int n)
{
List *ptr;
List *ptr2;
// search for the rightmost node whose number is smaller than n.
ptr2 = NULL;
for (ptr = *head; ptr; ptr = ptr->next) {
if (ptr->n >= n)
break;
ptr2 = ptr;
}
// If such a node exists we insert the new node after it,
// otherwise we insert it at the front of the list.
if (ptr2) {
insert_number_after (ptr2, n);
}
else {
insert_number_front (head, n);
}
}
int input_number ()
{
int n;
printf ("enter a number: ");
scanf ("%d", &n);
return n;
}
int main ()
{
List *head = NULL;
int i;
// By adding elements exclusively with insert_number_sorted()
// we ensure the list is always sorted
for (i = 0; i < 5; i++) {
int n;
n = input_number ();
insert_number_sorted (&head, n);
}
print_list (head);
return 0;
}
To answer your second question, what you have here is a singly linked list, which can be described by a pointer to the first node. If you want to be able to insert nodes at the back you need to maintain an additional pointer to the last node. However this is not necessary in this case.
I'm trying to implement sequence_insert_at using the add_to_front function here
Everything before
typedef struct sequence *Sequence;
is pasted from another c file.
void sequence_insert_at(Sequence s, int pos, int item)
{
struct node* temp = s->lst;
for(; pos > 0; --pos)
{
temp = temp->rest;
}
add_to_front(&temp, item);
++s->length;
if(!temp->rest)
{
s->end = temp;
}
//s->lst = temp;
}
I don't know why I keep getting a runtime error. if I clone s->lst and traverse the clone, I'm not modifying the pointer to the node in s, but if I change temp, s->lst should have the reflected changes since the nodes are all linked still. Any ideas as to how to fix this? I tried creating another node that is one before the temp after traversal, and then setting it->rest = temp, but that failed as well.
following mistakes a could spot but only so far to get the main function run
new_sequence does not initialize anything in Sequence it creates. lst is not initialized when you access it in sequence_insert_at
struct node* temp = s->lst;
here how it should look like
Sequence new_sequence()
{
Sequence s = malloc(sizeof(struct sequence));
if(!s)
{
printf("Out of memory. Can't allocate s\n");
exit(EXIT_FAILURE);
}
s->lst = malloc(sizeof(struct node));
if(! s->lst) {
printf("Out of memory. Can't allocate lst\n");
}
s->lst->rest = NULL;
s->length = 0;
return s;
}
also s->lst->rest has to be set to NULL, this is what tells that the list has no more elements an not end witch turns obsolete.
struct sequence
{
struct node* lst;
int length;
};
You should be passing the sequence itself to your functions not a pointer to some internal data in the sequence.
add_to_front(&temp, item);
Your sequence_insert_at function should be the one that can handle any position not add_to_front() so it is easier to call with the position 0 from add_to_front() and your having the the hole work done in one function, not a half here and a half there.
void sequence_insert_at(Sequence s, int pos, int item)
{
if(s && pos <= s->length) {
print_sequence(s);
struct node *newnode = malloc(sizeof(struct node));
if (newnode == NULL) {
printf("ERROR! add_to_front ran out of memory!\n");
exit(EXIT_FAILURE);
}
newnode->first = item;
struct node* temp = s->lst;
struct node* prv = NULL;
for(int i = 0; i < pos; i++) {
printf("skip %d\n", temp->first);
prv = temp;
temp = temp->rest;
}
newnode->rest = temp;
if(pos == 0) {
printf("insert as first\n");
s->lst = newnode;
} else {
printf("insert before %d\n", temp->first);
prv->rest = newnode;
}
++s->length;
}
}
and in add_to_front only one statement is needed
void add_to_front(Sequence s, int item) {
sequence_insert_at(s, 0, item);
}
as for inserting at the back of the list
void add_to_back(Sequence s, int item) {
sequence_insert_at(s, s->length, item);
}
A small test with the main function
void print_sequence(Sequence s)
{
struct node* temp = s->lst;
for(int i = 0; i < s->length; temp = temp->rest) {
printf("%d ", temp->first);
i++;
}
printf("\n");
}
int main()
{
Sequence derp = new_sequence();
sequence_insert_at(derp, 0, 14);
add_to_front(derp, 16);
sequence_insert_at(derp, 0, 17);
sequence_insert_at(derp, 2, 15);
add_to_back(derp, 13);
print_sequence(derp);
delete_sequence(derp);
return 0;
}
output is:
17 16 15 14 13
You'll have to go trough the other functions and fix them.
Finally i should note that variable names you have choosen are little bit confusing if not misleading, i would name them this way
typedef struct node {
int data; /* the data that a node holds */
struct node* next; /* the pointer to the next node */
} Node_t;
typedef struct sequence {
struct node* head; /* head or first element of the sequence/list */
int length; /* length is ok but size is better */
} Sequence_t;
I am goofing around with pointers and structures. I want to achieve the following:
(1) define a linked list with a structure (numberRecord)
(2) write a function that fills a linked list with some sample records by going thourgh a loop (fillList)
(3) count the number of elements in the linked list
(4) print the number of elements
I am now so far that the fillList function works well, but I do not succeed in handing over the filled linked list to a pointer in the main(). In the code below, the printList function only displays the single record that was added in main() instead of displaying the list that was created in the function fillList.
#include <stdio.h>
#include <stdlib.h>
typedef struct numberRecord numberRecord;
//linked list
struct numberRecord {
int number;
struct numberRecord *next;
};
//count #records in linked list
int countList(struct numberRecord *record) {
struct numberRecord *index = record;
int i = 0;
if (record == NULL)
return i;
while (index->next != NULL) {
++i;
index = index->next;
}
return i + 1;
}
//print linked list
void printList (struct numberRecord *record) {
struct numberRecord *index = record;
if (index == NULL)
printf("List is empty \n");
while (index != NULL) {
printf("%i \n", index->number);
index = index->next;
}
}
//fill the linked list with some sample records
void fillList(numberRecord *record) {
numberRecord *first, *prev, *new, *buffer;
//as soon as you add more records you get an memory error, static construction
new = (numberRecord *)malloc(100 * sizeof(numberRecord));
new->number = 0;
new->next = NULL;
first = new;
prev = new;
buffer = new;
int i;
for (i = 1; i < 11; i++) {
new++;
new->number = i;
new->next = NULL;
prev->next = new;
prev = prev->next;
}
record = first;
}
int main(void) {
numberRecord *list;
list = malloc(sizeof(numberRecord));
list->number = 1;
list->next = NULL;
fillList(list);
printf("ListCount: %i \n", countList(list));
printList(list);
return 0;
}
SOLUTION
Do read the posts below, they indicated this solution and contain some very insightful remarks about pointers. Below the adapted code that works:
#include <stdio.h>
#include <stdlib.h>
typedef struct numberRecord numberRecord;
//linked list
struct numberRecord {
int number;
struct numberRecord *next;
};
//count #records in linked list
int countList(struct numberRecord *record) {
struct numberRecord *index = record;
int i = 0;
if (record == NULL)
return i;
while (index->next != NULL) {
++i;
index = index->next;
}
return i + 1;
}
//print linked list
void printList (struct numberRecord *record) {
struct numberRecord *index = record;
if (index == NULL)
printf("List is empty \n");
while (index != NULL) {
printf("%i \n", index->number);
index = index->next;
}
}
//fill the linked list with some sample records
numberRecord *fillList() {
numberRecord *firstRec, *prevRec, *newRec;
int i;
for (i = 1; i < 11; i++) {
newRec = malloc(sizeof(numberRecord));
newRec->number = i;
newRec->next = NULL;
//initialize firstRec and prevRec with newRec, firstRec remains head
if (i == 1) {
firstRec = newRec;
prevRec = newRec;
}
prevRec->next = newRec;
prevRec = prevRec->next;
}
return firstRec;
}
int main(void) {
numberRecord *list;
list = fillList();
printf("ListCount: %i \n", countList(list));
printList(list);
return 0;
}
This statement in fillList
record = first;
has no effect on the list variable in main. Pointers are passed by value (like everything else) in C. If you want to update the list variable in main, you'll either have to pass a pointer to it (&list) and modify fillList accordingly, or return a numberRecord* from fillList. (I'd actually go with that second option.)
Here's a (bad) illustration:
When main calls fillList, at the starting point of that function, the pointers are like this:
main memory fillList
list ----> 0x01234 <---- record
A bit later in fillList, you allocate some storage for new (that's actually a bad name, it conflicts with an operator in C++, will get people confused)
main memory fillList
list ----> 0x01234 <---- record
0x03123 <---- new
At the last line of fillList you're left with:
main memory fillList
list ----> 0x01234 ,-- record
0x03123 <---- new
record and list are not the same variable. They start out with the same value, but changing record will not change list. The fact that they are both pointers doesn't make them any different from say ints in this respect.
You can change the thing pointed to by list in fillList, but you can't change what list points to (with your version of the code).
The easiest way for you to get around that is to change fillList like this:
numberRecord *fillList() {
....
return new;
}
And in main, don't allocate list directly, just call fillList() to initialize it.