Linked List - Stack Sorting in C - c

My code is following:
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<math.h>
struct stack {
int data;
struct stack* next;
};
struct Student
{
unsigned long int rollnumber;
char name[100];
struct Student *next;
}* head;
// Utility function to initialize stack
void initStack(struct stack** s) { *s = NULL; }
// Utility function to check if stack is empty
int isEmpty(struct stack* s)
{
if (s == NULL)
return 1;
return 0;
}
// Utility function to push an item to stack
void push(struct stack** s, int x, unsigned long int rollnumber, char *name)
{
struct stack* p = (struct stack*)malloc(sizeof(*p));
if (p == NULL) {
fprintf(stderr, "Memory allocation failed.\n");
return;
}
p->data = x;
p->next = *s;
*s = p;
}
// Utility function to remove an item from stack
int pop(struct stack** s)
{
int x;
struct stack* temp;
x = (*s)->data;
temp = *s;
(*s) = (*s)->next;
free(temp);
return x;
}
// Function to find top item
int top(struct stack* s) { return (s->data); }
// Recursive function to insert an item x in sorted way
void sortedInsert(struct stack** s, int x, unsigned long int rollnumber, char *name)
{
// Base case: Either stack is empty or newly inserted
// item is less than top (more than all existing)
if (isEmpty(*s) || x < top(*s)) {
push(s, x, rollnumber, name);
return;
}
else{
// If top is less, remove the top item and recur
int temp = pop(s);
sortedInsert(s, x, rollnumber, name);
// Put back the top item removed earlier
push(s, temp, rollnumber, name);}
}
// Function to sort stack
void sortStack(struct stack** s)
{
// If stack is not empty
char *name;
unsigned long int rollnumber;
if (!isEmpty(*s)) {
// Remove the top item
int x = pop(s);
// Sort remaining stack
sortStack(s);
// Push the top item back in sorted stack
sortedInsert(s, x, rollnumber, name);
}
}
// Utility function to print contents of stack
void printStack(struct stack* s, unsigned long int rollnumber, char* name)
{
struct Student* student = (struct Student *) malloc(sizeof(struct Student));
struct Student* temp = head;
while (s && temp!=NULL) {
printf("%lu %s\n", temp->rollnumber, temp->name);
s = s->next;
temp = temp->next;
}
printf("\n");
}
void insert(unsigned long int rollnumber, char* name)
{
struct Student * student = (struct Student *) malloc(sizeof(struct Student));
student->rollnumber = rollnumber;
strcpy(student->name, name);
student->next = NULL;
if(head==NULL){
// if head is NULL
// set student as the new head
head = student;
}
else{
// if list is not empty
// insert student in beginning of head
student->next = head;
head = student;
}
}
void Delete(unsigned long int rollnumber)
{
struct Student * temp1 = head;
struct Student * temp2 = head;
while(temp1!=NULL){
if(temp1->rollnumber==rollnumber){
printf("Record with roll number %lu Found\n", rollnumber);
if(temp1==temp2){
// this condition will run if
// the record that we need to delete is the first node
// of the linked list
head = head->next;
free(temp1);
}
else{
// temp1 is the node we need to delete
// temp2 is the node previous to temp1
temp2->next = temp1->next;
free(temp1);
}
printf("Record successfully deleted\n");
return;
}
temp2 = temp1;
temp1 = temp1->next;
}
printf("Student with roll number %lu is not found\n", rollnumber);
}
void display()
{
struct Student * temp = head;
while(temp!=NULL){
printf("Roll Number: %lu\n", temp->rollnumber);
printf("Name: %s\n", temp->name);
temp = temp->next;
}
}
int main(void)
{
head = NULL;
int choice;
int fc_,id_,year_, fc_year;
char name[100];
struct student* s;
unsigned long int rollnumber;
struct stack* faculty;
struct stack* year;
struct stack* id;
initStack(&faculty);
initStack(&year);
initStack(&id);
printf("1 - Enter school number\n2 - Display school numbers by ID\n3 - Display school numbers sorted by year\n4 - Display school numbers sorted by the faculty codes\n5 - Delete a record by school number\n6 - Exit");
do
{
printf("\nEnter Choice: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
printf("Enter roll number: ");
scanf("%lu", &rollnumber);
fc_ = rollnumber/pow(10, 6);
id_ = rollnumber%(10*10*10*10);
fc_year = rollnumber/pow(10,4);
year_ = fc_year%(100);
printf("Enter name: ");
scanf("%s", name);
insert(rollnumber, name);
push(&faculty, fc_, rollnumber, name);
push(&year, year_, rollnumber, name);
push(&id, id_, rollnumber, name);
break;
case 2:
printf("Sorted by ID: \n");
sortStack(&id);
printStack(id, rollnumber, name);
break;
case 3:
printf("Sorted by year: \n");
sortStack(&year);
printStack(year, rollnumber, name);
break;
case 4:
printf("Sorted by faculty code: \n");
sortStack(&faculty);
printStack(faculty, rollnumber, name);
break;
case 5:
printf("Enter roll number to delete: ");
scanf("%lu", &rollnumber);
Delete(rollnumber);
break;
case 6:
break;
}
} while (choice != 6);
}
When, for example, the choice is 2, I want to display the student name and whole rollnumber in ascending order. But when I run it that is what I get (C, B, A are the names given by me):
Enter Choice: 2
705102020 C
705102010 B
705102005 A
I am sure that I sorted it correctly, but probably my printStack function is not working properly. How can I reverse this?

It would be better to define a stack struct independantly of the rest of your code:
struct stack {
void *data;
struct stack *next;
};
void stack_init(struct stack **ss)
{
*ss = NULL;
}
bool stack_push(struct stack **ss, void *data)
{
struct stack *node = malloc(sizeof *node);
if (!node) return false;
node->data = data; // Copy address, not data
node->next = *ss;
*ss = node;
return true;
}
bool stack_pop(struct stack **ss, void **data)
{
if (!*ss) return false;
struct stack *rm = *ss;
*ss = (*ss)->next;
if (data) *data = rm->data; // If nothing is provided (i.e. NULL), data will leak if it was allocated dynamically.
free(rm);
return true;
}
bool stack_top(const struct stack *ss, void **data)
{
if (!ss) return false;
*data = ss->data;
return true;
}
void stack_print(const struct stack *ss, void print(const struct stack*))
{
for (const struct stack *sp = ss; sp; sp = sp->next)
print(sp);
}
You can implement your stack sorting function like that:
struct stack *stack_find_min(struct stack *ss, int (*cmp)(const void*, const void*))
{
struct stack *min = ss;
for (struct stack *sp = ss; sp; sp = sp->next)
if (cmp(sp->data, min->data) < 0)
min = sp;
return min;
}
void stack_sort(struct stack *ss, int (*cmp)(const void*, const void*))
{
if (!ss) return;
for (struct stack *sp = ss; sp; sp = sp->next) {
struct stack *min = stack_find_min(sp, cmp);
swap(&sp->data, &min->data);
}
}
swap() swaps two pointers:
void swap(void **p1, void **p2)
{
void *tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
After that, define your student data structure:
struct student {
unsigned long rollnumber;
char name[100];
struct student *next;
};
struct student *student_insert(struct student **head, unsigned long rollnumber, const char *name)
{
struct student *st = malloc(sizeof(*st));
if (!st) return NULL;
st->rollnumber = rollnumber;
strncpy(st->name, name, 99);
st->next = *head;
*head = st;
return st;
}
void student_print(const struct stack *ss)
{
struct student *st = ss->data;
printf("%ld\t%s\n", st->rollnumber, st->name);
}
int student_compare_id(const void *s1, const void *s2)
{
// MUST cast void* into (struct student*) first.
const struct student *student1 = s1;
const struct student *student2 = s2;
unsigned long rollnumber1 = student1->rollnumber;
unsigned long rollnumber2 = student2->rollnumber;
unsigned long id1 = rollnumber1 % 10000;
unsigned long id2 = rollnumber2 % 10000;
return id1 == id2 ? 0 : (id1 < id2 ? -1 : 1);
}
If you want to test the above:
int main(void)
{
struct stack *ss;
stack_init(&ss);
struct student *st = NULL;
student_insert(&st, 100181234, "James");
student_insert(&st, 200195678, "John");
student_insert(&st, 300200324, "Goku");
student_insert(&st, 400214321, "Taylor");
for (struct student *p = st; p; p = p->next)
stack_push(&ss, p);
puts("Unsorted stack:");
stack_print(ss, student_print);
stack_sort(ss, student_compare_id);
puts("\nSorted by ID:");
stack_print(ss, student_print);
// Don't forget to free the memory allocated for students
// and pop all nodes of the stack (ommited here).
}
Output:
Unsorted stack:
100181234 James
200195678 John
300200324 Goku
400214321 Taylor
Sorted by ID:
300200324 Goku
100181234 James
400214321 Taylor
200195678 John
Few more things:
Don't use scanf() to read user input. fgets() is safer.
You can replace pow(10, 4) directly by 10000. Why wasting CPU cycles to calculate constants?
In your insert() function, there is no need to test for *head == NULL. The code in the else statement handles this case.
EDIT: In student_compare_id(), the const void* pointers MUST BE CASTED to const struct student* first before dereferencing. The previous version seemed to work because the rollnumber happened to be the first field in the struct. That was an undefined behavior in all its glory. Fixed that now.
Here is the previous version that NO ONE SHOULD USE:
int student_compare_id(const void *s1, const void *s2)
{
unsigned long rollnumber1 = *(unsigned long*)s1; // WRONG!
unsigned long rollnumber2 = *(unsigned long*)s2; // WRONG!
unsigned long id1 = rollnumber1 % 10000;
unsigned long id2 = rollnumber2 % 10000;
return id1 == id2 ? 0 : (id1 < id2 ? -1 : 1);
}

The primary problem is that there is no connection between your stack(s) and your student list, but the code assumes that there is. You can reorder the stacks however you like, but that does not reorder the list. When you print, the students simply come out in the reverse of their insertion order (because you insert at the front of the list, and then traverse the list from front to back).
You have two main alternatives:
combine the list and all the stacks into one linked list. You can use this both list-style and stack-style if you like. OR
Give the stack nodes pointers to the corresponding list elements, and traverse those when you print a stack to get the students in the order implied by the stack.

Related

Pointer problem while using Linked list in C

I'm working on a c programming code and most of the code is working fine except the polynomial Multiplication part. It has a runtime error. please help me in removing this runtime error from Polynomial Multiplication, I couldn't find the error i think it's in the third for loop.
Thanks...
It will be great if you solve the error
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#define MAX 17
typedef struct node
{
int coeff;
struct node *next;
}node;
node * init();
void read(node *h1);
void print(node *h1);
node * add(node *h1,node *h2);
node * multiply(node *h1, node *h2);
void main()
{
node *h1=NULL,*h2=NULL,*h3=NULL;
int option;
do
{
printf("\n1 : create 1’st polynomial");
printf("\n2 : create 2’nd polynomial");
printf("\n3 : Add polynomials");
printf("\n4 : Multiply polynomials");
printf("\n5 : Quit");
printf("\nEnter your choice :");
scanf("%d",&option);
switch(option)
{
case 1:
h1=init();
read(h1);
break;
case 2:
h2=init();
read(h2);
break;
case 3:
h3=add(h1,h2);
printf("\n1’st polynomial -> ");
print(h1);
printf("\n2’nd polynomial -> ");
print(h2);
printf("\n Sum = ");
print(h3);
break;
case 4:
h3=multiply(h1,h2);
printf("\n1’st polynomial -> ");
print(h1);
printf("\n2’nd polynomial -> ");
print(h2);
printf("\n Product = ");
print(h3);
break;
}
}while(option!=5);
}
void read(node *h)
{
int n,i,j,power,coeff;
node *p;
p=init();
printf("\n Enter number of terms :");
scanf("%d",&n);
/* read n terms */
for (i=0;i<n;i++)
{
printf("\nenter a term(power coeff.)");
scanf("%d%d",&power,&coeff);
for(p=h,j=0;j<power;j++)
p=p->next;
p->coeff=coeff;
}
}
void print(node *p)
{
int i;
for(i=0;p!=NULL;i++,p=p->next)
if(p->coeff!=0)
printf("%dX^%d ",p->coeff,i);
}
node * add(node *h1, node *h2)
{
node *h3,*p;
h3=init();
p=h3;
while(h1!=NULL)
{
h3->coeff=h1->coeff+h2->coeff;
h1=h1->next;
h2=h2->next;
h3=h3->next;
}
return(p);
}
node * multiply(node *h1, node *h2)
{
node *h3,*p,*q,*r;
int i,j,k,coeff,power;
h3=init();
for(p=h1,i=0;p!=NULL;p=p->next,i++)
for(q=h2,j=0;q!=NULL;q=q->next,j++)
{
coeff=p->coeff * q->coeff;
power=i+j;
for(r=h3,k=0;k<power;k++)
r=r->next;
r->coeff=r->coeff+coeff;
}
return(h3);
}
node * init()
{
int i;
node *h=NULL,*p;
for(i=0;i<MAX;i++)
{
p=(node*)malloc(sizeof(node));
p->next=h;
p->coeff=0;
h=p;
}
return(h);
}
There is at least a probleme here in the multiply function:
...
for (r = h3, k = 0; k < power; k++)
r = r->next;
r->coeff = r->coeff + coeff;
...
At some point r becomes NULL and at the next step when you dereference r with r->coeff (r being NULLnow) your program will result un undefined behaviour (a segfault on most platforms).
There were several problems:
Memory was leaked: make sure you can point out a free for every malloc.
read was creating a new list, but leaking it and never updating the data in h1 or h2.
add didn't check for NULL h2.
The result of addition/multiplication was unnecessarily retained.
There was an arbitrary maximum of 17 nodes - the whole point of a linked list is so that there's no need to maintain such arbitrary limits.
Variables had scopes that were too large. This is 2011: one can declare variables near to point of use and not at the beginning of the block.
The use of scanf was non-idiomatic and inapplicable to interactive line-oriented input. For such input, read complete lines and parse them, not the stdin stream. In the stdin stream, a newline is a field separator and you don't want that, I think.
There weren't any asserts: program defensively, assert what you think should be true.
This works and should be correct and free of undefined behavior under all conditions.
// https://github.com/KubaO/stackoverflown/tree/master/questions/c-linked-debug-52867729
#include <assert.h>
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node {
int power; // primary key for sorting
int coeff;
struct Node *next;
} Node;
Node *new_node(Node *prev, Node *next, int power);
Node *get_node(Node **head, Node *hint, int power);
void delete_nodes(Node *head);
Node *read(void);
void print(const Node *head);
Node *add(const Node *head1, const Node *head2);
Node *multiply(const Node *head1, const Node *head2);
void print_nodes(const Node *n1, const Node *n2, const char *extra_label,
const Node *extra);
const char *arity_suffix(int n);
bool parse_line(int max_length, const char *fmt, int count, ...);
static void *guarded_malloc(size_t size) {
void *result = malloc(size);
if (!result) {
fprintf(stdout, "Memory allocation has failed: exiting.");
abort();
}
return result;
}
int main() {
Node *h1 = NULL, *h2 = NULL;
int option;
do {
printf("\n1 : Create 1'st polynomial");
printf("\n2 : Create 2'nd polynomial");
printf("\n3 : Print polynomials");
printf("\n4 : Add polynomials");
printf("\n5 : Multiply polynomials");
printf("\n6 : Quit");
printf("\nEnter your choice: ");
if (!parse_line(10, "%d", 1, &option)) continue;
switch (option) {
case 1:
delete_nodes(h1);
h1 = read();
break;
case 2:
delete_nodes(h2);
h2 = read();
break;
case 3:
print_nodes(h1, h2, NULL, NULL);
break;
case 4: {
Node *sum = add(h1, h2);
print_nodes(h1, h2, "Sum", sum);
delete_nodes(sum);
break;
}
case 5: {
Node *prod = multiply(h1, h2);
print_nodes(h1, h2, "Product", prod);
delete_nodes(prod);
break;
}
}
} while (option != 6);
delete_nodes(h1);
delete_nodes(h2);
}
Node *read() {
int n;
printf("\n Enter number of terms: ");
if (!parse_line(10, "%d", 1, &n)) return NULL;
/* read n terms */
Node *head = NULL;
for (int i = 0; i < n;) {
int power, coeff;
printf("\nEnter the %d%s term (power coeff): ", i + 1, arity_suffix(i + 1));
if (!parse_line(80, "%d%d", 2, &power, &coeff) || !coeff) continue;
Node *p = get_node(&head, NULL, power);
if (!p->coeff) i++; // count only new terms
p->coeff = coeff;
}
return head;
}
void print(const Node *p) {
for (; p; p = p->next) printf("%dX^%d ", p->coeff, p->power);
}
void add_to(Node **sum, const Node *h) {
Node *r = NULL;
for (; h; h = h->next) {
r = get_node(sum, r, h->power);
r->coeff += h->coeff;
}
}
Node *add(const Node *h1, const Node *h2) {
Node *sum = NULL;
add_to(&sum, h1);
add_to(&sum, h2);
return sum;
}
Node *multiply(const Node *h1, const Node *h2) {
Node *prod = NULL;
for (const Node *p = h1; p; p = p->next) {
Node *r = NULL;
for (const Node *q = h2; q; q = q->next) {
int power = p->power + q->power;
r = get_node(&prod, r, power);
r->coeff += p->coeff * q->coeff;
}
}
return prod;
}
Node *new_node(Node *prev, Node *next, int power) {
assert(!prev || prev->power < power);
assert(!next || next->power > power);
Node *node = guarded_malloc(sizeof(Node));
node->power = power;
node->coeff = 0;
node->next = next;
if (prev) prev->next = node;
return node;
}
void delete_nodes(Node *head) {
while (head) {
Node *p = head;
head = head->next;
free(p);
}
}
static bool list_contains(Node *head, Node *elt) {
for (; head; head = head->next)
if (head == elt) return true;
return false;
}
Node *get_node(Node **head, Node *hint, int power) {
Node *node = hint;
Node *next = hint ? hint->next : head ? *head : NULL;
assert(!hint || !*head || list_contains(*head, hint));
assert(!hint || hint->power <= power);
assert(!node || !next || node->power < next->power);
while (next && next->power <= power) {
node = next;
next = next->next;
}
if (!node || node->power != power) {
assert(!node || node->power < power);
Node *n = new_node(node, next, power);
if (!node) *head = n;
node = n;
}
return node;
}
void print_nodes(const Node *h1, const Node *h2, const char *extra_label,
const Node *extra) {
printf("\n1'st polynomial -> ");
print(h1);
printf("\n2'nd polynomial -> ");
print(h2);
if (extra_label) {
printf("\n %s = ", extra_label);
print(extra);
}
printf("\n");
}
const char *arity_suffix(int n) {
if (n == 0) return "st";
if (n == 1) return "nd";
return "rd";
}
bool parse_line(int max_length, const char *fmt, int count, ...) {
bool result = false;
int const buf_size = max_length + 2; // include \n and zero termination
char *const buf = guarded_malloc((size_t)buf_size);
char *const str = fgets(buf, buf_size, stdin);
if (str) {
size_t n = strlen(str);
if (str[n - 1] == '\n') { // we must have read a whole line
str[n - 1] = '\0'; // remove the newline
va_list ap;
va_start(ap, count);
int rc = vsscanf(buf, fmt, ap);
va_end(ap);
result = rc == count;
}
}
free(buf);
return result;
}
I think you should use memcopy in read method
void read(node *h)
{
int n,i,j,power,coeff;
node *p;
p=init();
printf("\n Enter number of terms :");
scanf("%d",&n);
/* read n terms */
for (i=0;i<n;i++)
{
printf("\nenter a term(power coeff.)");
scanf("%d%d",&power,&coeff);
for(p=h,j=0;j<power;j++)
p=p->next;
p->coeff=coeff;
}
memcpy (h, p, sizeof(node))
}

How to sort a linkedlist in C programming?

So I am trying to sort a linked list, from small to big based on the name. It sorts it but it is sorting it the reverse or wrong way.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
//declaring a struct
struct node {
char *name;
int num;
struct node *next;
};
struct node *list=NULL;
/*
* insert()
*/
struct node *insert(char word2[], int val){
struct node *tmp;
tmp = malloc(sizeof(struct node));
if(tmp ==NULL){
fprintf(stderr, "out of memory\n");
exit(1);
}
tmp->name = strdup(word2);
tmp->num = val;
tmp->next = list;
list = tmp;
return tmp;
}//read string
void print(){
struct node *ptr;
for(ptr= list; ptr!=NULL; ptr = ptr->next){
printf(" %s/%d\n", ptr->name, ptr->num);
}//for loop
}//print
void sort(){
struct node *ptr1, *ptr2;
char *tmp;
for(ptr1 = list; ptr1!=NULL; ptr1 = ptr1->next){
for(ptr2 = ptr1->next; ptr2!=NULL; ptr2 = ptr2->next){
if(strcmp(ptr1->name, ptr2->name)>0){
//ptr1->name is "greater than" ptr2->name - swap them
tmp = ptr1->name;
ptr1->name = ptr2->name;
ptr1->name = tmp;
}
}
}
}//sort
int main (){
char buff[81];
int status=0;
int len;
char word1[20];
char word2[20];
int val;
// char word3[20];
while(fgets(buff, 81, stdin)>0){
len = strlen(buff);
if(buff[len-1]!='\n'){
fprintf(stderr,"Error: string line length was too long\n");
exit(1);
}
sscanf(buff, "%s %s %d", word1, word2, &val);
if(strcmp(word1, "insert")==0){
insert(word2, val);
sort();
}else if(strcmp(word1, "print")==0){
print();
}else{
}
}//while loop
return status;
}
This is what my input looks like when I run it.
"insert a 1"
"insert b 2"
"insert c 3"
"print"
output
c/3
b/2
a/1
If have tried changing my sort method condition but it keeps sorting it the wrong way. I can't seem to find the bug. Any help will be greatly appreciated. But my output is supposed to look like this
Desired output
a/1
b/2
c/3
If you sort after every insert you do not need the full bubble-sort, just one round.
void sort()
{
struct node *ptr1 = list;
char *tmpname;
int tmpnum;
while (ptr1->next != NULL) {
if (strcmp(ptr1->name, ptr1->next->name) > 0) {
// swap content in this case, not the nodes
tmpname = ptr1->name;
tmpnum = ptr1->num;
ptr1->name = ptr1->next->name;
ptr1->num = ptr1->next->num;
ptr1->next->name = tmpname;
ptr1->next->num = tmpnum;
}
ptr1 = ptr1->next;
}
}

All Nodes in a linked list point to same object

The problem is somewhere in here....
char buffer[80];
char *name;
while (1) {
fgets(buffer, 80, inf); //reads in at most 80 char from a line
if (feof(inf)) //this checks to see if the special EOF was read
break; //if so, break out of while and continue with your main
name = (char *) malloc(sizeof(char)*20);
....
name = strtok(buffer, " ");//get first token up to space
stock = newStock(name,...)
....
}
I'm working in C with generic linked lists. I made a list implementation that I've tested and know works with chars. I'm trying to add stocks (I created a stock struct) to the linked list, with each node of the linked list holding a stock struct, but when I finish reading in the stocks all of the nodes point to the same struct and I can't figure out why. Here's some snippets of my code
list *list = malloc(sizeof(list));
newList(list, sizeof(stock_t));
while(1) {
...
(read from file)
...
stock_t *stock;
stock = newStock(name, closes, opens, numshares, getPriceF, getTotalDollarAmountF,getPercentChangeF,toStringF);
addToBack(list, stock);
}
Here's the newStock function:
stock_t *newStock(char *name, float closingSharePrice, float openingSharePrice, int numberOfShares, getPrice getP, getTotalDollarAmount getTotal, getPercentChange getPercent, toString toStr) {
stock_t *stock = malloc(sizeof(stock));
stock->stockSymbol = name;
stock->closingSharePrice = closingSharePrice;
stock->openingSharePrice = openingSharePrice;
stock->numberOfShares = numberOfShares;
stock->getP = getP;
stock->getTotal = getTotal;
stock->getPercent = getPercent;
stock->toStr = toStr;
return stock;
}
In a way I see what's wrong. newStock returns a new pointer every time, but it always gets stored in the variable 'stock' which is what every node points to, so it's going to be equal to whatever the last pointer newStock returned was...but I don't see the way around this. I tried having newStock return just a stock_t, and doing addToBack(list, &stock), but that didn't solve the problem either.
Any help would be appreciated!
Here is some code from the list:
typedef struct node {
void *data;
struct node *next;
}node_t;
typedef struct {
int length;
int elementSize;
node_t *head;
node_t *tail;
} list;
void newList(list *list, int elementSize) {
assert(elementSize > 0);
list->length = 0;
list->elementSize = elementSize;
list->head = list->tail = NULL;
}
void addToBack(list *list, void *element) {
node_t *node = malloc(sizeof(node_t));
node->data = malloc(list->elementSize);
node->next = NULL; //back node
memcpy(node->data, element, list->elementSize);
if (list->length == 0) { //if first node added
list->head = list->tail = node;
}
else {
list->tail->next = node;
list->tail = node;
}
list->length++;
}
Here's code from the stock struct:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef float (*getPrice)(void *S);
typedef float (*getTotalDollarAmount)(void *S);
typedef float (*getPercentChange)(void *S);
typedef char *(*toString)(void *S);
typedef struct stock{
char *stockSymbol;
float closingSharePrice;
float openingSharePrice;
int numberOfShares;
getPrice getP;
getTotalDollarAmount getTotal;
getPercentChange getPercent;
toString toStr;
}stock_t;
The generic functions probably seem like overkill but this is for homework (if you couldn't tell already) so we were asked to specifically use them. I don't think that has anything to do with the problem though.
Here are the definitions for those functions anyway
float getPriceF(void *S) {
stock_t *stock = (stock_t*)S;
return stock->closingSharePrice;
}
float getTotalDollarAmountF(void *S) {
stock_t *stock = (stock_t*)S;
return ((stock->closingSharePrice) * (stock->numberOfShares));
}
float getPercentChangeF(void *S) {
stock_t *stock = (stock_t*)S;
return ((stock->closingSharePrice - stock->openingSharePrice)/(stock->openingSharePrice));
}
char *toStringF(void *S) {
stock_t* stock = (stock_t*)S;
char *name = malloc(20*sizeof(char));
//sprintf(name, "Symbol is: %s. ", (stock->stockSymbol));
return stock->stockSymbol;
}
void printStock(void *S) {
char *str = toStringF(S);
printf("%s \n", str);
}
And this is how I'm traversing the list:
typedef void (*iterate)(void *); //this is in the list.h file, just putting it here to avoid confusion
void traverse(list *list, iterate iterator) {
assert(iterator != NULL);
node_t *current = list->head;
while (current != NULL) {
iterator(current->data);
current = current->next;
}
}
And then in my main I just called
traverse(list, printStock);
I can't find any problems with your code (that would cause your problem, anyway - there are places where you don't check the return from malloc() and stuff like that, but those are not relevant to this question). You don't supply the definition of stock_t, so I made a new data struct, and a new couple of functions, otherwise I just copied and pasted the code you provided:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* Your code starts here */
typedef struct node {
void *data;
struct node *next;
}node_t;
typedef struct {
int length;
int elementSize;
node_t *head;
node_t *tail;
} list;
void newList(list *list, int elementSize) {
assert(elementSize > 0);
list->length = 0;
list->elementSize = elementSize;
list->head = list->tail = NULL;
}
void addToBack(list *list, void *element) {
node_t *node = malloc(sizeof(node_t));
node->data = malloc(list->elementSize);
node->next = NULL; //back node
memcpy(node->data, element, list->elementSize);
if (list->length == 0) { //if first node added
list->head = list->tail = node;
}
else {
list->tail->next = node;
list->tail = node;
}
list->length++;
}
/* Your code ends here */
/* I made a new struct, rather than stock, since you didn't supply it */
struct mydata {
int num1;
int num2;
};
/* I use this instead of newStock(), but it works the same way */
struct mydata * newNode(const int a, const int b) {
struct mydata * newdata = malloc(sizeof *newdata);
if ( newdata == NULL ) {
fputs("Error allocating memory", stderr);
exit(EXIT_FAILURE);
}
newdata->num1 = a;
newdata->num2 = b;
return newdata;
}
/* I added this function to check the list is good */
void printList(list * list) {
struct node * node = list->head;
int n = 1;
while ( node ) {
struct mydata * data = node->data;
printf("%d: %d %d\n", n++, data->num1, data->num2);
node = node->next;
}
}
/* Main function */
int main(void) {
list *list = malloc(sizeof(list));
newList(list, sizeof(struct mydata));
struct mydata * data;
data = newNode(1, 2);
addToBack(list, data);
data = newNode(3, 4);
addToBack(list, data);
data = newNode(5, 6);
addToBack(list, data);
printList(list);
return 0;
}
which outputs this:
paul#MacBook:~/Documents/src$ ./list
1: 1 2
2: 3 4
3: 5 6
paul#MacBook:~/Documents/src$
demonstrating that you have a 3 node list, with all nodes different and where you'd expect them to be.
Either there is some other problem in code you're not showing, or for some reason you are thinking each node points to the same struct when it actually doesn't.
One possibility is that you have a char * data member in your stock struct. It's impossible to tell from the code you provided, but it's possible that you really are creating different nodes, but they all end up pointing to the same name, so they just look like they're the same. If you're assigning a pointer to name, you should make sure it's freshly allocated memory each time, and that you're not just, for instance, strcpy()ing into the same memory and assigning the same address to each stock struct.
EDIT: Looks like that was your problem. This:
name = (char *) malloc(sizeof(char)*20);
....
name = strtok(buffer, " ");
should be:
name = (char *) malloc(sizeof(char)*20);
....
strcpy(name, strtok(buffer, " "));
Right now, you malloc() new memory and store a reference to it in name, but then you lose that reference and your memory when you overwrite it with the address returned from strtok(). Instead, you need to copy that token into your newly allocated memory, as shown.

malloc and pointer in a struct

I have the following C code:
typedef struct DListNode_ {
void *data;
struct DListNode_ *prev;
struct DListNode_ *next;
} DListNode;
typedef struct DList_ {
int size;
DListNode *tail;
DListNode *head;
} DList;
void insert(DList * list, DListNode * element, int data) {
DListNode * new_element = (DListNode *)malloc(sizeof(DListNode));
new_element->data = &data;
if (list->head==NULL) {
list->head=list->tail=new_element;
list->size++;
return;
}
if(element == NULL) {
// handle size==0?
new_element->next=list->head;
list->head->prev=new_element;
list->head=new_element;
list->size++;
} else {
printf("Not yet implemented!\n");
}
}
void printNodes(DList *list) {
DListNode * pointer = list->head;
if (pointer!=NULL) {
int v= *((int*)pointer->data);
printf("Node has value: %d\n", v);
while (pointer->next != NULL) {
v = *((int*)pointer->data);
printf("Node has value: %d\n", v);
pointer=pointer->next;
}
}
}
int main(int argc, const char * argv[])
{
int e0 = 23;
int e1 = 7;
int e2 = 11;
DList *list = (DList *)malloc(sizeof(DList));
initList(list);
assert(count(list)==0);
insert(list, NULL, e0);
assert(count(list)==1);
insert(list,NULL, e1);
assert(count(list)==2);
insert(list,NULL, e2);
assert(count(list)==3);
printNodes(list);
return 0;
}
I have a few problems:
does DListNode * new_element = (DListNode *)malloc(sizeof(DListNode)); also allocate space for the, data, prev, next pointer or do I manually need to call malloc on each of those pointers?
When I print the content of the data pointer in each node they all have the value 3 even though I insert 23, 7 and 11 and set the data pointer to the address of the int: ** new_element->data = &data;**.
(Introductionary textbooks on C have been ordered)
EDIT:
insert now takes a void pointer to the data:
// Insert data as the new head
void insert(DList *list, DListNode *element, void *data) {
DListNode *new_element = malloc(sizeof(DListNode));
new_element->data = data;
if (list->head==NULL) {
list->head=list->tail=new_element;
list->size++;
return;
}
if(element == NULL) {
new_element->next=list->head;
list->head->prev=new_element;
list->head=new_element;
list->size++;
} else {
printf("Not yet implemented!\n");
}
}
In main I do:
int main(int argc, const char * argv[])
{
int i0=7;
int *ip0 = malloc(sizeof(int));
ip0 = &i0;
int i1=8;
int *ip1 = malloc(sizeof(int));
ip1 = &i1;
int *ip2 = malloc(sizeof(int));
int i2=44;
ip2 = &i2;
DList *list = malloc(sizeof(DList));
initList(list);
// create some nodes
assert(count(list)==0);
insert(list, NULL, ip0);
assert(count(list)==1);
insert(list,NULL, ip1);
assert(count(list)==2);
insert(list,NULL, ip2);
assert(count(list)==3);
printNodes(list);
return 0;
}
which outputs:
Node has value: 44
Node has value: 44
Node has value: 8
but it should be:
Node has value: 44
Node has value: 8
Node has value: 7
malloc(sizeof(DListNode)) allocates space for exactly one DListNode, which by definition consists of a void* and two DListNode pointers. It does not initialize those pointers, though.
You're assigning the address of the data argument to insert. That's a pointer to a temporary which is invalidated once insert returns. The behavior of the program is undefined. The easy solution is to just replace void *data by int data.
You need to manually set those pointers to where they point with malloc. Without it, they will point to a space that isn't of size DListNode.
Don't make the data a pointer. Just make the data an int (it gets auto allocated) and then just set data = data (the data that is passed into insert).

hash table - linked lists - segmentation fault

I am trying to implement a hash table with linked list chaining. The following code below works -
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TABSIZ 200
struct record {
struct record *next;
char name[BUFSIZ];
int data;
};
static struct record *htable[TABSIZ];
unsigned hash(char *s)
{
unsigned h;
for (h = 0; *s; s++)
h = *s;
//printf("%d", h%TABSIZ);
//I know its not a good hash function but i wanted to check chaining
return h % TABSIZ;
}
struct record *find(char *name)
{
struct record *item;
for (item = htable[hash(name)]; item; item = item->next)
{
if (strcmp(name, item->name) == 0)
return item;
}
return NULL;
}
struct record *insert(char *name,int value)
{
struct record *item;
unsigned h;
if ((item = find(name)) == NULL)
{
if ((item = malloc(sizeof (*item))) == NULL)
return NULL;
strcpy(item->name, name);
item->data=value;
h = hash(name);
item->next = htable[h];
htable[h] = item;
}
return item;
}
void printTable()
{
int i=0;
struct record *temp;
for(i=0;i<=TABSIZ;i++)
{
temp=htable[i];
while(temp!=NULL)
{
printf("\n%d - %s - %d\n", i,temp->name, temp->data);
temp=temp->next;
}
}
}
int main(void)
{
char buf[BUFSIZ];int value;
struct record *item;
do{
printf("Enter the name of the student:\n");
scanf("%s", buf);
if(strcmp(buf,"stop")==0) break;
printf("Enter the marks of the student:\n");
scanf("%d", &value);
if(insert(buf, value)==NULL)
{
break;
}
}while((strcmp(buf,"stop"))!=0);
printf("Enter a name to find: ");
scanf("%s", buf);
if((item=find(buf))!=NULL)
printf("The marks of the student is %d\n", item->data);
else printf("\n Not Found\n");
printTable();
return 0;
}
Now I am trying to remove the global variable and use local variable for the array of structures. I removed the global declaration of htable and declared it in main as
struct record *htable[TABSIZ];
and changed the functions to
struct record *find(struct record *htable, char *name);
struct record *insert(struct record *htable, char *name,int value);
and I'm calling the functions as
find(htable, name);
insert(htable,name,value);
but now my program is segfaulting. Am i passing the array of structures right? and have I declared it correctly. Any help would be greatly appreciated.
I was going down the wrong path with my earlier answer.
When it's a global, it's automatically initialized to 0.
When it's declared on the stack of main, it's not initialized.
Add a memset( htable, 0, sizeof(htable)) in main(), and that should return it to the previous behavior.
In printTable():
for(i=0;i<=TABSIZ;i++)
looks suspect. You prabably want:
void printTable()
{
unsigned int i;
struct record *temp;
for(i=0; i < TABSIZ;i++)
{
for (temp=htable[i]; temp!=NULL; temp=temp->next )
{
printf("\n%d - %s - %d\n", i,temp->name, temp->data);
}
}
}

Resources