nested linked list print issue - c

When I running this code and call " List() "function it prints only the last added by user . I want to print from beginning to the end.I hope you will help me about my list function.It prints only the last one.
#include<stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
struct seat {
int k_no;
int k_name;
struct seat *next_k, *previous_k;
} *first_k, *temp_k, *last_k;
struct sefer {
char name[20];
int no;
struct sefer *next, *previous;
struct seat *bus;
} *first, *last, *temp;
void list();
void seat_link(int val);
void sefer_search();
int main() {
int val;
printf ("how many names do you want to type ->");
scanf ("%d", &val);
int i;
int j;
for (i = 0; i < val; i++) {
if (first == NULL) {
first = (sefer *)malloc(sizeof(struct sefer));
fflush(stdin);
printf(" %d. name->", i + 1);
scanf("%s", &first->name);
printf(" %d. capacity ->", i + 1);
scanf("%d", &first->no);
first->next = NULL; //2 inci düğüm daha oluşmadığı için null
first->previous = NULL;
last = first; //şimdilik sadece ilk düğüm olduğu için aynı zamanda son oluo
last->bus = NULL;
for (j = 0; j < first->no; j++) {
//KOLTUKLAR OLUŞTURULCAK
if (last->bus == NULL) {
first_k = (seat *)malloc(sizeof(struct seat));
fflush(stdin);
first_k->k_no = j;
first_k->k_name = 1;
first_k->next_k = NULL;
first_k->previous_k = NULL;
last_k = first_k;
last->bus = first_k;
} else {
temp_k = (seat *)malloc(sizeof(struct seat ));
fflush(stdin);
temp_k->k_no = j;
temp_k->k_name = 0;
last_k->next_k = temp_k;
temp_k->previous_k = last_k;
last_k = temp_k;
last_k->last_k = NULL;
}
}
} else if (last == first) {
printf("\n");
last = (sefer *)malloc(sizeof(struct sefer));
fflush(stdin);
printf(" %d. name ->", i + 1);
scanf("%s", &last->name);
printf(" %d. capacitiy ->", i + 1);
scanf("%d", &last->no);
first->next = last;
last>next = NULL;
last->previous = first;
last->bus = NULL;
for (j = 0; j < last->no; j++) {
//KOLTUKLAR OLUŞTURULCAK
if (last->bus == NULL) {
first_k = (seat *)malloc(sizeof(struct seat ));
fflush(stdin);
first_k->k_no = j;
first_k->k_name = 2;
first_k->last_k = NULL;
first_k->previous_k = NULL;
last_k = first_k;
last->bus = first_k;
} else {
temp_k = (seat *)malloc(sizeof(struct seat));
fflush(stdin);
temp_k->k_no = j;
temp_k->k_name = 0;
last_k->next_k = temp_k;
temp_k->previous_k = last_k;
last_k = temp_k;
last_k->last_k = NULL;
}
}
} else { // kayıt eklenmişse diğer düğümler oluşturulcak
printf ("\n");
temp = (sefer *) malloc(sizeof(struct sefer));
fflush(stdin);
printf(" %d. name", i + 1);
scanf("%s", &temp->name);
printf(" %d. capacity->", i + 1);
scanf("%d", &temp->no);
last->next = temp;
temp->previous = last;
last = temp;
last->next = NULL;
last->bus = NULL;
for (j = 0; j < temp->no; j++) {
//KOLTUKLAR OLUŞTURULCAK
if (last->bus == NULL) {
first_k = (seat*)malloc(sizeof(struct seat));
fflush(stdin);
first_k->k_no = j;
first_k->k_name = 3;
first_k->last_k = NULL;
first_k->previous_k = NULL;
last_k = first_k;
last->bus = first_k;
} else {
temp_k = (seat *)malloc(sizeof(struct seat));
fflush(stdin);
temp_k->k_no = j;
temp_k->k_name = 0;
last_k->next_k = temp_k;
temp_k->previous_k = last_k;
last_k = temp_k;
last_k->next_k = NULL;
}
}
}
}
list();
system("PAUSE");
return 0;
}
void sefer_search() { //bağda arama yapar
int searching;
printf("\n\t\t Aranacak Sefer Numarasını Giriniz:");
scanf("%d", &searching);
temp = first;
while (1) {
if (temp->no == searching) {
break;
}
temp = temp->next;
}
}
void seat_link(int val) {
int j;
}
my problem is here actually :
void list() {
temp = first;
while (temp != NULL) {
printf("\t%s --%d \n", temp->name, temp->no);
temp = temp->next;
}
printf ("\n");
last->bus = first_k;
while (last->bus != NULL) {
printf("\t%d --%d \n", last->bus->k_name, last->otobus->k_no);
last->bus = last->bus->next_k;
}
}
Please help me

There are a bunch of problems with your code. Firstly, it won't compile for various reasons. For instance, you sometimes use a struct koltuk without ever defining it. "koltuk" means "seat" in Turkish, so I'm going to assume you meant struct seat in all those cases. Secondly, deg is undefined; I assume you meant val.
There were a few other problems like that which I was able to fix by making plausible guesses. But that leaves the following fundamental problems:
You are using global variables as local variables, for instance temp_k and temp. This makes it well-nigh impossible for a human to analyze your code and understand the control flow.
You have copied code all over the place. You have three separate code blocks to allocate and initialize a sefer depending upon whether it's first in the global linked list, second, or later. Use subroutines!
Your data model seems confused. You have global variables struct *first_k,*temp_k,*last_k; which makes it seem like you have one global linked list of seats for all sefer structs, but the struct seat does not refer back in an obvious way to the sefer that owns it, which implies that each sefer has a separate, private list of seats.
Taking all three problems together, I can't really see where, specifically, you are going wrong. I took a cut at rewriting your code to eliminate these problems. Give it a try to see if it solves your problems:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
typedef struct seat{
int k_no;
int k_name;
struct seat *next_k, *previous_k;
} seat;
typedef struct sefer {
char name[20];
int no;
struct sefer *next,*previous;
struct seat *bus;
} sefer;
void list();
sefer *sefer_search();
void link_sefer(sefer **pp_first, sefer **pp_last, sefer *p_added)
{
p_added->next = p_added->previous = NULL;
if (*pp_first == NULL)
{
*pp_first = *pp_last = p_added;
}
else
{
(*pp_last)->next = p_added;
p_added->previous = *pp_last;
*pp_last = p_added;
}
}
void link_seat(seat **pp_first, seat **pp_last, seat *p_added)
{
p_added->next_k = p_added->previous_k = NULL;
if (*pp_first == NULL)
{
*pp_first = *pp_last = p_added;
}
else
{
(*pp_last)->next_k = p_added;
p_added->previous_k = *pp_last;
*pp_last = p_added;
}
}
sefer *create_and_link_sefer(sefer **pp_first_sefer, sefer **pp_last_sefer, int i)
{
sefer *new_sefer;
seat *p_first_seat = NULL;
seat *p_last_seat = NULL;
int j;
// Allocate and initialize sefer
printf ("\n");
new_sefer = calloc(1, sizeof(struct sefer));
fflush(stdin);
printf (" %d. name->",i+1);
scanf ("%s",&new_sefer->name);
printf (" %d. capacity->",i+1);
scanf ("%d",&new_sefer->no);
new_sefer->bus = NULL;
// Link sefer
link_sefer(pp_first_sefer, pp_last_sefer, new_sefer);
// Allocate seats
for(j=0;j<new_sefer->no;j++){
//KOLTUKLAR OLUŞTURULCAK
seat *p_seat = calloc(1, sizeof(struct seat));
fflush(stdin);
p_seat->k_no=j;
p_seat->k_name = (j != 0 ? 0 : (i+1 > 3 ? 3 : i+1)); // I CAN'T FIGURE OUT WHAT THIS IS SUPPOSED TO BE
link_seat(&p_first_seat, &p_last_seat, p_seat);
}
new_sefer->bus = p_first_seat;
return new_sefer;
}
void sefer_list(sefer *first, sefer *last){
sefer *temp=first;
while (temp !=NULL)
{
seat *seat;
printf("\t%s --%d \n", temp->name,temp->no);
for (seat = temp->bus; seat != NULL; seat = seat->next_k)
{
printf("\t\t%d --%d \n",seat->k_name, seat->k_no);
}
printf ("\n");
temp=temp->next;
}
}
sefer *sefer_search(sefer *first, sefer *last){ //bağda arama yapar
int arama;
sefer *temp;
printf ("\n\t\t Aranacak Sefer Numarasını Giriniz:");
scanf ("%d",&arama);
temp=first;
while (temp != NULL){
if (temp->no==arama){
break;
}
temp=temp->next;
}
return temp;
}
sefer *first = NULL;
sefer *last = NULL;
int main( )
{
int val;
int i;
printf ("how many names do you want to type ->");
scanf ("%d",&val);
for(i=0;i<val;i++){
create_and_link_sefer(&first, &last, i);
}
sefer_list(first, last);
system("PAUSE");
return 0;
}
It seems to work, but since I don't know what you are trying to do, it might not be working as you want.

Judging by the logic, that means that temp really isn't going anywhere. My guess is that when you set those pointers *first, *last, *temp; in the first few lines of main, you don't really point first to NULL, causing it to skip the first if statement. Pointers don't point to NULL by default, they point to whatever was at that memory location beforehand. In this case, garbage. Try adding first=NULL; prior to your first if-statement.

Related

Sorting linked list with multiple parameters

I'm having a trouble with my school project. I was asked to use a linked list, I'm almost finish but then I got stuck in how do I sort my data by looking at the date
I want to display these data by sorting the date
I have searched everywhere and I still can't find how to sort a linked list multiple parameters
say these are the parameters:
struct Data {
int kode;
char variety[20];
int weight;
int date;
struct Data *next;
} *headIn, *tempIn;
with a main function like this:
int menu;
int pointIn = 0;
int amount = 0;
void insert(int kode, char *variety, int weight, int date);
void userInput();
void printList(struct Data *tempIn);
int main() {
headIn = NULL;
int menu = 0;
do {
system ("cls");
printf( " \n\nMAIN MENU :\n");
printf( " 1. Input Product\n\n");
printf( " 2. Print List\n\n");
printf( " enter your choice (1 - 2) : ");
scanf("%d", &menu);
if (menu < 1 || menu > 2) {
system("cls");
printf ("your input is not available\n");
getch();
}
switch (menu) {
case 1:
userInput();
break;
case 2:
printList(tempIn);
break;
}
}
while (menu != 3);
system("cls");
printf ("============ Thankyou ============");
return 0;
}
and then I apply this function so that the data is going to be a linked list:
void insert(int kode, char *variety, int weight, int date) {
struct Data *dataIn = (struct Data *)malloc(sizeof(struct Data));
dataIn->kode = kode;
strcpy(dataIn->variety, variety);
dataIn->weight = weight;
dataIn->date = date;
dataIn->next = NULL;
if (headIn == NULL) {
headIn = dataIn;
} else {
dataIn->next = headIn;
headIn = dataIn;
}
}
and then I have this 2 function for asking user's input and the other is for printing
void userInput() {
int code;
int weight;
int date;
amount = 0;
char variety[5][20] = { "Fish", "Crab", "Squid", "Clam", "Lobster" };
system ("cls");
printf("Number of data you want to enter : "); scanf("%d", &amount);
printf( "_________________________________________________________________\n");
printf("\n Kode 0 = Fish \n kode 1 = Crab \n kode 2 = Squid \n kode 3 = Clam \n kode 4 = Lobster\n\t\t\t ");
for (int i = 0; i < amount; i++) {
printf("\n\nProduct-%d", pointIn + 1);
printf("\n\tInput code\t : "); scanf(" %d", &code);
if (code < 0 || code > 4) {
printf ("this code product is not available\n");
i--;
} else {
printf("\tJenis\t\t : %s\n", variety[code]);
printf("\tINPUT weight\t : "); scanf(" %d", &weight );
printf("\tInput date (YYYYMMDD)\t : ");scanf(" %d", &date);
pointIn++;
insert(code, variety[code], weight, date);
}
}
getch();
}
void printList(struct Data *tempIn) {
system ("cls");
tempIn = headIn;
//sort function here
printf("***** DATA PRODUCT ***** \n" );
printf("| DATE | CODE | NAME | WEIGHT | \n");
while (tempIn != NULL) {
printf(" %d %d %s %d \n", tempIn->date, tempIn->kode, tempIn->variety, tempIn->weight);
tempIn = tempIn->next;
}
getch();
}
please help me I don't understand and I can't find any references, it's just this sorting part I'm stuck in.
In the Insert function, you must find the proper place to insert the node by iterating in the list past the nodes with a lesser date:
void insert(int kode, const char *variety, int weight, int date) {
struct Data *dataIn = (struct Data *)malloc(sizeof(struct Data));
if (dataIn == NULL) {
fprintf(stderr, "cannot allocate memory for Data struct\n");
return;
}
dataIn->kode = kode;
strcpy(dataIn->variety, variety);
dataIn->weight = weight;
dataIn->date = date;
if (headIn == NULL || headIn->date > date) {
// insert node at the head
dataIn->next = headIn;
headIn = dataIn;
} else {
// insert node in the list
struct Data *np = head;
while (np->next && np->next->date >= date) {
np = np->next;
}
dataIn->next = np->next;
np->next = dataIn;
}
}
I have solved my problem for sorting this program
first i add a new struct
struct node{
int kode;
char variety[20];
int weight;
int date;
struct node* left;
struct node* right;
};
struct node* newNode(int data){
struct node* node = (struct node*) malloc(sizeof(struct node));
node->date = data;
node->left = NULL;
node->right = NULL;
return(node);
}
and then i initiate an array
struct Data order[100];
int k=0;
and then make the sorting functions
struct node* insertSort(struct node* node, int data)
{
if (node == NULL)
return(newNode(data));
else
{
if (data <= node->date)
node->left = insertSort(node->left, data);
else
node->right = insertSort(node->right, data);
return node;
}
}
void sort(struct node* node) {
struct node* current = node;
if (node != NULL) {
sort (current->left);
order[k++].date =node->date ;
sort (current->right);
}
}
and then i update my printing process so that it can print the sorted products
void printList(struct Data *tempIn) {
system ("cls");
tempIn = headIn;
int angka =0;
struct node* root = NULL;
while(tempIn!=NULL){
if(root==NULL){
root = insertSort(root, tempIn->date);
}
else {
insertSort(root, tempIn->date);
}
tempIn = tempIn->next;
}
tempIn = headIn;
printf("***** DATA PRODUCT ***** \n" );
printf("| DATE | CODE | NAME | WEIGHT | \n");
k=0;
for (int i=0;i<100;i++){
order[i].date=0;
order[i].kode =0;
order[i].weight=0;
}
sort(root);
tempIn = headIn;
for(int i=0;i<100;i++){
tempIn = headIn;
while (tempIn != NULL) {
if(order[i].date==tempIn->date){
printf(" %d %d %-10s %d \n", tempIn->date, tempIn->kode, tempIn->variety, tempIn->weight);
}
tempIn = tempIn->next;
}
}
getch();
}

Problems regarding an multiple choice question program

I have created a program to generate the result of a multiple choice exam. The program was supposed to show the total number of mistakes, blank answers and the number of the question which were answered incorrectly. For the following input:
6
1..223
(Here . means blank answer)
123124
The output was supposed to be:
Your result:
Mistakes: 3
Blanks: 2
Your mistakes are following:
4 5 6
Your blanks are following:
2 3
But the code shows undefined behavior. It seems to go through infinite loop. Expecting solution to my problem shortly. Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char data;
struct node* next;
}node;
void printNode(node* head)
{
node* local = head;
int i = 0;
if(local -> data == 0)
{
printf("0");
return;
}
while(local != NULL)
{
if(i == 3)
{
i = 0;
printf("\n");
}
printf("%d\t", local -> data);
local = local -> next;
++i;
}
}
void freeNode(node** head)
{
node* temp = (*head);
while((*head) != NULL)
{
(*head) = (*head) -> next;
free(temp);
temp = (*head);
}
}
int main()
{
int n, i, flagB, flagM, blnk, mstk;
blnk = mstk = flagB = flagM = 0;
printf("Enter the number of questions: ");
scanf("%d", &n);
char ques[n], ans[n];
if(n == 0)
return 0;
node* headM = (node*)malloc(sizeof(node));
node* nodeM;
node* headB = (node*)malloc(sizeof(node));
node* nodeB;
printf("Enter your given answers: ");
fflush(stdin);
for(i = 0; i < n; ++i)
{
scanf("%c", &ques[i]);
}
fflush(stdin);
ques[n] = '\0';
printf("Enter the solution: ");
for(i = 0; i < n; ++i)
{
scanf("%c", &ans[i]);
}
ans[n] = '\0';
for(i = 0; i < n; ++i)
{
if(ques[i] == '.')
{
++blnk;
if(flagB == 0)
{
headB -> data = i + 1;
headB -> next = NULL;
nodeB = headB;
continue;
}
nodeB -> next = (node*)malloc(sizeof(node));
nodeB = nodeB -> next;
nodeB -> data = i + 1;
nodeB-> next = NULL;
flagB = 1;
}
else if(ques[i] != ans[i])
{
++mstk;
if(flagM == 0)
{
headM -> data = i + 1;
headM -> next = NULL;
nodeM = headM;
continue;
}
nodeM -> next = (node*)malloc(sizeof(node));
nodeM = nodeM -> next;
nodeM -> data = i;
nodeM-> next = NULL;
flagM = 1;
}
}
printf("Your result:\n\tMistakes: %d\n\tBlanks: %d\n", mstk, blnk);
printf("Your mistakes are follwing:\n");
printNode(headM);
printf("\nYour blanks are follwing:\n");
printNode(headB);
freeNode(&headM);
freeNode(&headM);
return 0;
}
Here are some additional thoughts. What makes your code very convoluted and hard to debug and keep the logic straight is you are mixing your linked-list Add function within the logic of your blanks and mistakes and using special conditions to handle adding the first node and subsequent nodes. This make things difficult to test and debug. If you need to add nodes to a linked-list, then write an add() function that you can thoroughly test and debug before putting it to use in your code.
Your VLAs ques and ans are too short to hold a string of n characters, at minimum they must be n + 1 characters long to provide storage for the nul-termining character that marks the end of the string. Ideally, you will make them at least 2-character longer to also hold the '\n' which will allow you to take input with fgets() rather than looping scanf() a character at a time -- which is just nuts.
You do not need to pass the address of the pointer to freeNode() simply pass a pointer. Sure freeNode() will receive a copy of the pointer -- but it will contain the original address -- and since you don't have to make any changes to that pointer available back to the caller, there is no need to pass the address of the pointer (there won't be any list left to worry about when you are done...)
So putting those pieces together, adding an add() function to add to your linked lists (See Linus on Understanding Pointers for why a pointer-to-pointer is used to iterate to the end), and adding a simple empty_stdin() function to remove the '\n' left in stdin from reading n with scanf() before making calls to fgets() later for ques and ans, you could do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* simple function to empty stdin to end-of-line */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
typedef struct node
{
int data;
struct node *next;
} node;
node *add(node **head, int v)
{
node **ppn = head, /* pointer to pointer to head */
*pn = *head, /* pointer to head */
*newn = malloc (sizeof *newn); /* allocate new node */
if (!newn) { /* validate allocation */
perror ("malloc-node");
return NULL;
}
newn->data = v; /* initialize members values */
newn->next = NULL;
while (pn) { /* iterate to end of list */
ppn = &pn->next;
pn = pn->next;
}
return *ppn = newn; /* add & return new node */
}
void printNode (node *head)
{
for (; head; head = head->next)
printf (" %d", head->data);
putchar ('\n');
}
void freeNode(node *head)
{
while (head != NULL)
{
node *victim = head;
head = head->next;
free(victim);
}
}
int main()
{
int n, i, blnk, mstk;
blnk = mstk = 0;
node *headM = NULL; /* declare pointers and initialize NULL */
node *headB = NULL;
printf ("Enter the number of questions: ");
/* you must VALIDATE every user-input */
if (scanf ("%d", &n) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
empty_stdin(); /* remove '\n' (and any other chars from user) */
/* before calling fgets() below */
if (n == 0) /* check 0 BEFORE VLA declaration */
return 0;
char ques[2*n], ans[2*n]; /* declare question/answer VLAs, don't skimp */
printf("Enter your given answers: ");
if (!fgets(ques, sizeof ques, stdin)) /* read ques from stdin */
return 1;
ques[strcspn(ques, "\r\n")] = 0; /* trim '\n' from end of ques */
printf("Enter the solution: ");
if (!fgets(ans, sizeof ans, stdin)) /* read ans from stdin */
return 1;
ans[strcspn(ans, "\r\n")] = 0; /* ditto for ans */
for(i = 0; i < n; ++i) /* loop n times */
{
if(ques[i] == '.') /* if blank */
{
add (&headB, i + 1); /* add to list headB */
++blnk; /* increment counter */
}
else if(ques[i] != ans[i]) /* if mistake */
{
add (&headM, i + 1); /* add to list headM */
++mstk; /* increment counter */
}
}
printf ("Your result:\n\tMistakes: %d\n\tBlanks: %d\n"
"Your mistakes are following:\n", mstk, blnk);
printNode(headM);
printf("\nYour blanks are following:\n");
printNode(headB);
freeNode(headM); /* no need to pass the address of the pointer to free */
freeNode(headB); /* there won't be a list left when freeNode is done */
return 0;
}
There is a lot there, so go through it slowly.
Example Use/Output
$ ./bin/llquestions
Enter the number of questions: 6
Enter your given answers: 1..223
Enter the solution: 123124
Your result:
Mistakes: 2
Blanks: 2
Your mistakes are following:
4 6
Your blanks are following:
2 3
(note: in 1..223 and 123124, 5 is not a mistake, the 2 is in the correct position at the end)
Look things over and let me know if you have further questions.
I made some changes to this code, check this out.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node node;
struct Node
{
int data;
struct Node * next;
};
void printNode(node *head)
{
node *local = head;
while (local != NULL)
{
printf("%d ", local->data);
local = local->next;
}
}
void freeNode(node **head)
{
node *temp = (*head);
while ((*head) != NULL)
{
(*head) = (*head)->next;
free(temp);
temp = (*head);
}
}
int main()
{
int n, i, flagB = 0, flagM = 0, blnk = 0, mstk = 0;
blnk = mstk = flagB = flagM = 0;
printf("Enter the number of questions: ");
scanf("%d", &n);
char ques[n], ans[n];
if (n == 0)
return 0;
node *headM = (node*) malloc(sizeof(node));
headM->data = 0;
node *nodeM = headM;
node *headB = (node*) malloc(sizeof(node));
headB->next = 0;
node *nodeB = headB;
printf("Enter your given answers: ");
for (i = 0; i < n; ++i)
{
scanf("%s", &ques[i]);
}
ques[n] = '\0';
fflush(stdin);
printf("Enter the solution: ");
for (i = 0; i < n; ++i)
{
scanf("%s", &ans[i]);
}
ans[n] = '\0';
fflush(stdin);
for (i = 0; i < n; ++i)
{
if (ques[i] == '.')
{ ++blnk;
if (flagB == 0)
{
nodeB->data = i + 1;
nodeB->next = NULL;
flagB = 1;
continue;
}
nodeB->next = (node*) malloc(sizeof(node));
nodeB = nodeB->next;
nodeB->data = i + 1;
nodeB->next = NULL;
}
else if (ques[i] != ans[i])
{ ++mstk;
if (flagM == 0)
{
nodeM->data = i + 1;
nodeM->next = NULL;
flagM = 1;
continue;
}
nodeM->next = (node*) malloc(sizeof(node));
nodeM = nodeM->next;
nodeM->data = i + 1;
nodeM->next = NULL;
//flagM = 1; //You made a mistake here
}
}
nodeM = headM;
nodeB = headB;
printf("Your result:\n\tMistakes: %d\n\tBlanks: %d\n", mstk, blnk);
printf("Your mistakes are following question numbers:\n");
if (mstk != 0)
printNode(headM);
else
printf("No Mistakes\n");
printf("\nYour blanks are following question numbers:\n");
if (blnk != 0)
printNode(headB);
else
printf("No Blanks\n");
freeNode(&headM);
freeNode(&headM);
return 0;
}

C code, compiler Xcode, detected source and destination buffer overlap

I'm doing a project for school in which I have to create a program that plays go fish. In which a deck of cards is in a doubly linked list. I read the cards from a file in the function Addcard. I have a function to print the cards and a function that is supposed to shuffle the cards. I have ot use the parameters of the struct to implement the cards. I sometimes see the error "detected source and destination buffer overlap" when I run the shuffle function, sometimes not. When the error comes up it says Thread 1: signal SIGABRT next to a string copy function. I believe it has something to do with the buffer size of some kind of allocated memory being too small, but I don't really know how to fix it. Any help would be more then appreciated. Here is an excerpt of the code I have written.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
typedef struct card_s{
char suit[7];
int value;
struct card_s *next, *previous;
}card;
int rand_gen(int count){
double frac;
frac = (double)rand()/((double)RAND_MAX+1);
return floor(count * frac); //random number in [0, count]
}
void addCard(card *p, card **hl, card **hr, FILE *inp){
card *temp; // pointer to a node_t
temp = (card *)malloc(sizeof (card)); // new node creation
fscanf(inp, "%d", &temp->value);
fscanf(inp, "%s", temp->suit);
if (*hl == NULL){ // if left head is null, i.e., list is empty
temp->previous = NULL;
temp->next = NULL;
*hl = temp;
*hr = temp;
}
else if (p->next == NULL){ // if adding at the end of list
temp->previous = p;
temp->next = NULL;
p->next = temp;
*hr = temp;
}
else{ // if adding to the middle of the list
temp->next = p-> next;
temp->previous = p;
p->next = temp;
temp->next->previous = temp;
}
}
void Print(card **headl) { //this function prints from left to right only
card *temp;
temp = (*headl);
while(temp != NULL) {
printf("|");
printf("%d", temp->value);
if(strcmp(temp->suit,"hea")==0) {
printf("♥");
}
if(strcmp(temp->suit,"clu")==0) {
printf("♣");
}
if(strcmp(temp->suit,"spa")==0) {
printf("♠");
}
if(strcmp(temp->suit,"dia")==0) {
printf("♦");
}
printf("|");
//printf("%s ", temp->suit);
temp = temp->next;
}
}
void Print1(card **headl) { //this function prints from left to right only
card *temp;
temp = (*headl);
while(temp != NULL) {
for(int i = 0; i < 13; i++) {
printf("|");
if(temp->value == 11){
printf("J");
}
else if(temp->value == 12) {
printf("Q");
}
else if(temp->value == 13) {
printf("K");
}
else if(temp->value == 14) {
printf("A");
}
else {
printf("%d", temp->value);
}
if(strcmp(temp->suit,"h")==0) {
printf("♥");
}
if(strcmp(temp->suit,"c")==0) {
printf("♣");
}
if(strcmp(temp->suit,"s")==0) {
printf("♠");
}
if(strcmp(temp->suit,"d")==0) {
printf("♦");
}
printf("|");
//printf("%s ", temp->suit);
temp = temp->next;
}
printf("\n");
}
}
void swap(card *pt, int i, int j) {
card *temp;
temp = (card *)malloc(sizeof(card));
card *temp1 = pt, *temp2 = pt; //creates temperaries that start from the head left
for(int x = 0; x < i; x++) { //counts the number of nodes until i
temp1 = temp1->next;
}
for(int x = 0; x < j; x++) { //counts the number of nodes until j
temp2 = temp2->next;
}
temp->value = temp1->value; //swaps the information not the nodes
strcpy(temp->suit,temp1->suit);
temp1->value = temp2->value;
strcpy(temp1->suit, temp2->suit);
temp2->value = temp->value;
strcpy(temp2->suit, temp->suit);
}
int main(void) {
FILE *inp = NULL;
inp = fopen("cards.txt", "r");
srand((int)time(NULL));
card *headl = NULL, *headr = NULL;
for(int i = 0; i < 52; i++) {
addCard(headr, &headl, &headr, inp);
}
if(inp == NULL) {
printf("No file found");
return -1;
}
printIntro();
printf("\n");
Print1(&headl);
printf("\n");
printf("\n");
for(int i = 0; i <= 45; i++) { //does the swap function swap number times
swap(headl, rand_gen(52), rand_gen(52));
}
Print1(&headl);
return(0);
}
You have an error message saying "detected source and destination buffer overlap", near a string copy function, which copies data from a source to a destination...
Are there any instances of strcpy where the source and dest might point to the same memory?
I see these two lines:
card *temp1 = pt, *temp2 = pt; //creates temperaries that start from the head left
//advance `temp1` `i` times, and `temp2` `j` times
...
strcpy(temp1->suit, temp2->suit);
What happens when i and j are the same value?

Sorting a linked list using merge sort

Given this problem:
Write a function that takes two date of birth structures as input and
returns -1, 0, 1 if the first parameter is less than, equal to or
greater than the second parameter respectively. Using your function,
write a recursive mergeSort program to sort the linked list of student
records in increasing order of their age (do not use arrays, use
linked list only).
here is what I wrote:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*Recursive Merge Sort to sort linked list of students in increasing order
of their age*/
/*A structure dateofbirth is created to store date of birth of each
student*/
struct dateofbirth {
int date;
int month;
int year;
};
/*Another structure student is created whihc contains information about a
student and it is also a nested structure that contains another structure
dateofbirth*/
struct student {
char firstname[64];
struct dateofbirth d;
int height;
float weight;
struct student *next;
};
/*Some pointers are made global as they will be used many a times in the
programs*/
struct student *temp = NULL, *start = NULL, *end = NULL;
/*comparedob will take two dateofbirth structures and compare them which one
is greater */
int comparison(struct dateofbirth d1,struct dateofbirth d2) {
if (d1.year > d2.year)
return 1;
else if (d1.year < d2.year)
return -1;
else if (d1.month > d2.month)
return 1;
else if (d1.month < d2.month)
return -1;
else if (d1.date > d2.date)
return 1;
else if (d1.date < d2.date)
return -1;
else return 0;
}
/*It displays the linked list starting from the first till the last*/
void display() {
temp = start;
while (temp != NULL) {
printf("%s, ", temp->firstname);
if (temp->d.month < 10)
printf("%d0%d%d, ", temp->d.date, temp->d.month, temp->d.year);
else
printf("%d%d%d, ", temp->d.date, temp->d.month, temp->d.year);
printf("%d, ", temp->height);
printf("%.2f\n", temp->weight);
temp = temp->next;
}
}
/*It reads from the file*/
void readdata() {
int a;
if (start == NULL) { /*This case will be implemented when the first record is read
from the file*/
temp = (struct student*) malloc(sizeof(struct student));
if (temp == NULL) {
printf("\nNot enough memory");
}
scanf("%s", (*temp).firstname);
scanf("%d", &a);
(*temp).d.date = a / 1000000;
(*temp).d.month = (a % 1000000) / 10000;
(*temp).d.year = a % 10000;
scanf("%d", &(*temp).height);
scanf("%lf", &(*temp).weight);
temp->next = NULL;
start = temp;
end = temp;
} else { /*For all subsequent records this case will be implemented*/
temp = (struct student*) malloc(sizeof(struct student));
if (temp == NULL) {
printf("\nNot enough memory");
}
scanf("%s", (*temp).firstname);
scanf("%d", &a);
(*temp).d.date = a / 1000000;
(*temp).d.month = (a % 1000000) / 10000;
(*temp).d.year = a % 10000;
scanf("%d", &(*temp).height);
scanf("%lf", &(*temp).weight);
temp->next = NULL;
end->next = temp;
end = temp;
}
}
/*This function will swap two student record with the help of pointers*/
void swap(struct student* s1,struct student* s2) {
struct student s;
strcpy(s.firstname, (*s1).firstname);
strcpy((*s1).firstname, (*s2).firstname);
strcpy((*s2).firstname, s.firstname);
s.d.date = (*s1).d.date;
(*s1).d.date = (*s2).d.date;
(*s2).d.date = s.d.date;
s.d.month = (*s1).d.month;
(*s1).d.month = (*s2).d.month;
(*s2).d.month = s.d.month;
s.d.year = (*s1).d.year;
(*s1).d.year = (*s2).d.year;
(*s2).d.year = s.d.year;
s.height= (*s1).height;
(*s1).height = (*s2).height;
(*s2).height = s.height;
s.weight = (*s1).weight;
(*s1).weight = (*s2).weight;
(*s2).weight = s.weight;
}
/*This function is used to find the middle record in a linked list by making
one pointer move at a double pace than the other*/
void middle(struct student* head, struct student** s1, struct student** s2) {
struct student* x = NULL, *y = NULL;
if (head == NULL || head->next == NULL) {
*s1=head;
*s2=NULL;
} else {
x = head;
y = head->next;
while (y != NULL) {
y=y->next;
if (y != NULL) {
x = x->next;
y = y->next;
}
}
*s1 = head;
*s2 = x->next;
x->next = NULL;
}
}
/*This function will combine both the independently sorted linked lists of
records of student*/
struct student* merge(struct student* a,struct student* b) {
struct student* final = NULL; // final will store the result of merging 'a' and 'b'
if (a == NULL)
return (b);
else if (b == NULL)
return (a);
if (comparison((*a).d, (*(b)).d) == 1) {
final = a;
final->next = merge(a->next, b);
} else {
final=b;
final->next = merge(a, b->next);
}
return (final);
}
/*Recursive merge sort*/
void mergesort(struct student** Ref) {
struct student* base = *Ref; /*Ref is a pointer to pointer which will point to
the starting record so that we do not lose the reference of the starting
record in the process of merging*/
struct student* a = NULL; //Variable pointer
struct student* b = NULL; //Variable pointer
if ((base == NULL) || (base->next == NULL))
return;
middle(base, &a, &b);
mergesort(&a);
mergesort(&b);
*Ref = merge(a,b);
}
void main() {
int m, i;
scanf("%d", &m);
printf("%d\n", m);
for (i = 0; i < m; i++)
readdata();
mergesort(&start);
display();
}
The program is sorting, but the weight properties reported in the output are changed to zero. Why is that happening?

Adding struct pointer to a pointer array

I have a problem and I really dont know what to do.
I'am trying to insert "new students" to an student-array. The array contains pointers to the created structs. Can somebody find the error? It adds the student-structs to the array but especially the printing doesnt work.
It would be really helpful, if somebody could help me. :) PS: You can just copy the code.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_HASH 10
typedef struct student
{
unsigned int matnr;
char *name;
struct student *next_student;
} Student;
Student **hash_tabelle[MAX_HASH];
void insert_student (unsigned int matnr, char *name)
{
Student *neuer_student = malloc(sizeof(Student));
neuer_student->name = malloc(sizeof(*name)+1);
neuer_student->matnr = matnr;
strcpy(neuer_student->name, name);
neuer_student->next_student = NULL;
// Index im Hash-Array ermitteln
int hash_index = matnr % 10;
if(hash_tabelle[hash_index] == NULL)
{
neuer_student->next_student = hash_tabelle[hash_index];
hash_tabelle[hash_index] = neuer_student;
}
else
{
while(*hash_tabelle[hash_index] != NULL && (((*hash_tabelle[hash_index])->matnr - neuer_student->matnr) <= 0))
hash_tabelle[hash_index] = &(*hash_tabelle[hash_index])->next_student;
neuer_student->next_student = *hash_tabelle[hash_index];
*hash_tabelle[hash_index] = neuer_student;
}
}
void print_hash_tabelle()
{
for(int i = 0; i != MAX_HASH - 1; i++){
printf("%d)\t", i);
hash_tabelle[i] = &(*hash_tabelle[i])->next_student;
for(; hash_tabelle[i] != NULL; hash_tabelle[i] = &(*hash_tabelle[i])->next_student){
printf("%s (%d)", (&(*hash_tabelle[i])->name), (&(*hash_tabelle[i])->matnr));
}
printf("\t");
}
}
int main()
{
unsigned int matnr;
char name[100];
do
{
printf("Matrikelnummer:\t");
scanf("%d", &matnr);
fflush(stdin);
getchar(); // um das \n aus dem Puffer zu kriegen und rauszuschmeißen
printf("Name:\t\t");
fgets(name, 30, stdin);
insert_student(matnr, name);
}
while (matnr != 0);
print_hash_tabelle();
return 0;
}
Using a hash table is so simple... No need to use dereferencing for a fixed-size array of linked-list pointers.
Step 1 - a hash table is a array of linked-list pointers.
As #BLUEPIXY suggests:
Student *hash_tabelle[MAX_HASH];
Step 2 - to allocate and free each linked-list, initialize each item to NULL.
Otherwise, if(hash_tabelle[hash_index] == NULL) is Undefined
behavior in the function insert_student().
void hash_init()
{
for(int i=0;i<MAX_HASH;i++) {
hash_tabelle[MAX_HASH]=NULL;
}
}
Step 3 - allocate enough char to store the char *name to insert_student().
As # WhozCraig suggests, use strlen().
void insert_student (unsigned int matnr, char *name)
{
Student *neuer_student = malloc(sizeof(Student));
neuer_student->name = malloc(strlen(name)+1);
neuer_student->matnr = matnr;
strcpy(neuer_student->name, name);
neuer_student->next_student = NULL;
Step 4 - add the neuer_student in the hash_tabelle[] (function insert_student())
Warning: the index shall be included in the size of the array
[0..MAX_HASH[. (using 10 instead of MAX_HASH could become a bug).
int hash_index = matnr % MAX_HASH;
When the hash_tabelle[hash_index] is NULL, simple store the
neuer_student. No need to modify neuer_student->next_student.
if(hash_tabelle[hash_index] == NULL)
{
hash_tabelle[hash_index] = neuer_student;
}
Else explore the linked-list of hash_tabelle[hash_index] to store
the neuer_student at the end.
else
{
Student *tmp;
tmp = hash_tabelle[hash_index];
while (tmp->next_student!=NULL) {
tmp = tmp->next_student;
}
tmp->next_student = neuer_student;
}
Step 5 - to print the all items of the hash table (function print_hash_tabelle())
Reuse the same method to explore each linked-list pointer.
Warning: explore all item from 0 to MAX_HASH-1
void print_hash_tabelle()
{
for(int i = 0; i < MAX_HASH; i++){ // ERR != MAX_HASH - 1; i++){
printf("%d)\t", i);
Student *tmp = hash_tabelle[i];
while (tmp!=NULL) {
printf("%s (%d)", tmp->name, tmp->matnr);
tmp = tmp->next_student;
}
printf("\n");
}
}
Step 6 - free the memory of each item of the hash_tabelle[].
Free the allocated string free(tmp->name);.
Remove the current student hash_tabelle[i] = tmp->next_student;
Free the allocated student free(tmp);
Repeat until the end of the linked-list
That's all (no change in the main() except adding a call to hash_free() at the end).
void hash_free()
{
for(int i=0;i<MAX_HASH;i++) {
Student *tmp = hash_tabelle[i];
while (tmp!=NULL) {
free(tmp->name);
hash_tabelle[i] = tmp->next_student;
free(tmp);
tmp = hash_tabelle[i];
}
}
}
like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_HASH 10
typedef struct student {
unsigned int matnr;
char *name;
struct student *next_student;
} Student;
Student *hash_tabelle[MAX_HASH];
void insert_student (unsigned int matnr, char *name){
Student *neuer_student = malloc(sizeof(Student));
neuer_student->name = malloc(strlen(name)+1);
strcpy(neuer_student->name, name);
neuer_student->matnr = matnr;
//neuer_student->next_student = NULL;
int hash_index = matnr % MAX_HASH;
Student head = { .next_student = hash_tabelle[hash_index] };
Student *prev = &head, *curr = head.next_student;
while(curr != NULL && curr->matnr <= neuer_student->matnr){
prev = curr;
curr = curr->next_student;
}
neuer_student->next_student = curr;
prev->next_student = neuer_student;
hash_tabelle[hash_index] = head.next_student;
}
void print_hash_tabelle(void){
for(int i = 0; i < MAX_HASH; i++){
printf("%d)\t", i);
for(Student *p = hash_tabelle[i]; p; p = p->next_student){
printf("%s (%d)\t", p->name, p->matnr);
}
printf("\n");
}
}
void free_hash_tabelle(void){
for(int i = 0; i < MAX_HASH; i++){
Student *p = hash_tabelle[i];
while(p){
Student *temp = p->next_student;
free(p->name);
free(p);
p = temp;
}
}
}
int main(void){
int matnr = -1;//for %d of scanf
char name[100];
while(1){
printf("Matrikelnummer(-1 for end input): ");fflush(stdout);
scanf("%d", &matnr);
if(matnr < 0)
break;
while(getchar() != '\n');
printf("Name: ");fflush(stdout);
fgets(name, sizeof name, stdin);
name[strcspn(name, "\n")] = 0;
insert_student(matnr, name);
}
print_hash_tabelle();
free_hash_tabelle();
return 0;
}

Resources