im having a problem, im trying to make a list of a list where inicioC refers to the first node of clients, and every node of clients will have a list of rentals, referred as inicioA. The thing is, i dont know how to save the first pointer of the rentals, like, the first node of clients will only be saved one time, but wont the first node of every rental be different?
this are the structs:
typedef struct _aluguer
{
int id, estado, diaI, mesI, anoI, diaE, mesE, anoE;
struct _aluguer *prox;
}aluguer, *pAluguer;
typedef struct _registo
{
int nif,nalu;
char nome[100];
struct _registo *prox;
pAluguer *inicioA;
}registo, *pRegisto;
and this is the code I use to extract the info from a file into the list of lists
pRegisto iniC(pRegisto inicioC, pAluguer inicioA)
{
FILE *c;
int j, nif, nalu, l=0;
char nome[100];
c = fopen("clientes.txt", "r"); // abrir ficheiro
if(c == NULL)
{
printf("Erro ao abrir ficheiro %s", "clientes.txt");
exit(0);
}
while(fscanf(c, "%d %d %s", &nif, &nalu, nome) == 3) //format of info
{
pRegisto novoC = malloc(sizeof(registo));
if(novoC == NULL)
{
printf("erro alocacao memoria\n");
return inicioC;
}
novoC -> prox = NULL;
pAluguer inicioA = NULL;
pRegisto aux = inicioC;
pRegisto p = NULL;
novoC->nif=nif;
novoC->nalu=nalu;
strcpy(novoC->nome, nome);
while(aux != NULL)
{
p = aux;
aux = aux->prox;
}
if( aux == inicioC)
{
inicioC=novoC;
}
else
{
p->prox = novoC;
}
for(j=0; j<novoC->nalu; j++) // repeat is equal to the number of rentals
{
l++;
pAluguer novoA = malloc(sizeof(aluguer));
if(novoA == NULL)
{
printf("erro alocacao memoria\n");
return inicioC;
}
novoA -> prox = NULL;
pAluguer aux = inicioA;
pAluguer p = NULL;
fscanf(c, "%d %d", &(novoA->id), &(novoA->estado));
if(novoA->estado == 0)
{
fscanf(c, " %d %d %d", &(novoA->diaI), &(novoA->mesI), &(novoA->anoI));
}
else
{
fscanf(c, " %d %d %d %d %d %d", &(novoA->diaI), &(novoA->mesI), &(novoA->anoI), &(novoA->diaE), &(novoA->mesE), &(novoA->anoE));
}
while(aux != NULL)
{
p = aux;
aux = aux->prox;
}
if( aux == inicioA)
{
inicioA=novoA;
}
else
{
p->prox = novoA;
}
}
}
fclose(c);
return inicioC;
}
Arraylist (Array of pointers in C) is good choice for implementing list of list but as you are forced to do in this way, I am showing a Simple method how you can develop list of list in C.
It is very simple,suppose you have a list of 3 numbers: 1,2,3 i.e list_1,list of 2 numbers: 5,6 i.e list_2.Now these list_1 and list_2 can be linked in a similar way as the numbers in list linked above.Look at this scenario
list_1:1->2->3->Null
list_2:5->6->Null
list_of_list : list_1->list_2->Null i.e. (1->2->3->Null) -> (5->6->Null) -> Null
Here is a Sample program to insert list of ints in Last:
#include <stdio.h>
#include <stdlib.h>
// for list of Intergers
struct node{
int Data;
struct node *next;
};
// this is for list of nodes i.e list of lists
struct list{
struct node *start;
struct list *listnext;
};
// insert integers in list
void insertNode(struct node **head ,int data){
struct node *temp,*current;
temp=malloc(sizeof(struct node));
temp->Data=data;
temp->next=NULL;
if((*head)==NULL){
(*head)=temp;
}
else{
current=(*head);
while(current->next!=NULL){
current=current->next;
}
current->next=temp;
}
}
// insert lists of integers in a list
void insertList(struct list **Listhead,struct node *head){
struct list *temp,*current;
temp=malloc(sizeof(struct list));
temp->start=head;
temp->listnext=NULL;
if((*Listhead)==NULL){
(*Listhead)=temp;
}
else{
current=(*Listhead);
while(current->listnext!=NULL){
current=current->listnext;
}
current->listnext=temp;
}
}
// Show all the list with their data
void show(struct list *Listhead){
int i=1;
struct list *current;
struct node *currentlist;
current=Listhead;
while(current!=NULL){
currentlist=current->start;
printf("List %d: ",i);
while(currentlist!=NULL){
printf("%d ",currentlist->Data);
currentlist=currentlist->next;
}
i++;
printf("\n");
current=current->listnext;
}
}
int main(){
struct node *head1=NULL,*head2=NULL,*head3=NULL; // 3 lists of integers
struct list *Listhead=NULL; // Listhead will be the head of lists of list
insertNode(&head1,20); // inserting in first list
insertNode(&head1,13);
insertNode(&head1,22);
insertNode(&head1,18);
insertNode(&head2,42); // inserting in second list
insertNode(&head2,15);
insertNode(&head3,12); // inserting in third list
insertNode(&head3,14);
insertNode(&head3,28);
insertList(&Listhead,head1); // inserting lists in list
insertList(&Listhead,head2);
insertList(&Listhead,head3);
show(Listhead);
}
Output for this Program:
List 1: 20 13 22 18
List 2: 42 15
List 3: 12 14 28
I hope you got the point.
Related
I am having trouble figuring out how to do this correctly. I have a linked list of nodes then those nodes have pointers put into an array contained in that node. These nodes make up a sort of one-way graph between the nodes. I must then traverse the nodes randomly until the node "Home" is reached.
The main issue I'm having is assigning the graph nodes into the list nodes. I want the function to take in the head of the list, the names of the nodes and the weight (cost to travel between nodes). I'm not sure how to do this correctly and I don't know what I did but I think there's an infinite loop somehow. Any help is greatly appreciated.
The input file is structured as such:
Applebees
GroundRound
BlueMoose
DrunkenNoodle
Home
STOP
Applebees BlueMoose 10
Applebees DrunkenNoodle 13
GroundRound Applebees 2
GroundRound DrunkenNoodle 7
GroundRound Home 52
STOP STOP 0
GroundRound
Ignore the print statements in graphInsert() those are me trying to debug the loops.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
struct graphNode {
char name[100]; // Establishment name
int arcCnt; // Number of outgoing arc from this node
int weights[10]; // Weights of each outgoing arc from this node
struct graphNode* arcs[10]; // Holds other graph nodes that are connected to this node (this node is source)
};
struct listNode {
char name[100]; // Establishment name
struct listNode* next;
struct graphNode* graph; // Pointer into graph
};
void listInsert(struct listNode **head, char name[100]) {
// setup new nodes
struct graphNode* newGraph = (struct graphNode*)malloc(sizeof(struct graphNode));
for (int i = 0; i < 100; i++) {
newGraph->name[i] = name[i];
}
for (int i = 0; i < 10; i++) {
newGraph->arcs[i] = NULL;
}
newGraph->arcCnt = 0;
struct listNode* newNode = (struct listNode*)malloc(sizeof(struct listNode));
for (int i = 0; i < 100; i++) {
newNode->name[i] = name[i];
}
newNode->next = NULL;
newNode->graph = newGraph;
// check if head is NULL
if (*head == NULL) {
*head = newNode;
return;
}
// if the list is populated then add the node to the end
struct listNode* current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
void graphInsert(struct listNode** head, char src[100], char dst[100], int weight) {
struct listNode* srcNode = *head;
printf("CALL:");
while (srcNode->next != NULL) { // loop through list to find src
printf("%s %s", srcNode->name, src);
if (strcmp(srcNode->name, src) == 0) { // when it finds the name, find the dst update the graph node data
printf("FOUND");
struct listNode* dstNode = *head;
while (dstNode->next != NULL) { // this loop is to find the pointer to the dst node
printf(" %s %s", dstNode->name, dst);
if (strcmp(dstNode->name, src) == 0) { // when it finds name finally update all the info
printf("FOUND");
// assign the new arc to the right spot based on arcCnt (how many arcs there are), then return to exit the loops
srcNode->graph->arcs[srcNode->graph->arcCnt] = dstNode->graph;
srcNode->graph->weights[srcNode->graph->arcCnt] = weight;
srcNode->graph->arcCnt++;
return;
}
dstNode = dstNode->next;
}
}
srcNode = srcNode->next;
}
}
int main(){
srand(2021);
// setup variables
struct listNode* head = NULL;
struct graphNode* sourceNode = NULL;
FILE* data = fopen("./hw10.data", "r");
int i = 0;
int section = 1; // flag to read the file correctly
// this loop reads the file
while (1) {
char name[100];
char name2[100];
int weight = 0;
if (section == 1) { // reads the first section
fscanf(data, "%100s", name);
if (strcmp(name, "STOP") == 0) { // if end of section then increment section counter
section++;
} else { // if its not the end of the section then add the name to the linked list
listInsert(&head, name);
}
} else if (section == 2) { // reads the first section and builds the graph
fscanf(data, "%100s %100s %d", name, name2, &weight);
if (strcmp(name, "STOP") == 0) { // if end of section then increment section counter
section++;
} else {
//graphInsert(&head, name, name2, weight);
}
} else if (section == 3) { // this section only reads one line and gets the
char tmp[100];
fscanf(data, "%100s", tmp);
struct listNode* current = head;
while (current->next != NULL) { // loop through to find the right node for the name
if (strcmp(current->name, tmp) == 0) { // if names are equal update the node
sourceNode = current->graph;
break;
}
current = current->next;
}
}
if (feof(data)) break;
i++;
}
// debug print data
printf("\n");
struct listNode* current = head;
while (current != NULL) {
printf("%s\n", current->name);
current = current->next;
}
printf("\n");
// starting node
printf("%s ", sourceNode->name);
// now walk through the graph from sourceNode until we reach the node "Home"
int totalWeight = 0;
i = 0;
while (i < 100) {
char* tmp = sourceNode->name;
if (strcmp(tmp, "Home") == 0) { // if were home then exit program
// ending node and cost
printf("%s %d", sourceNode->name, totalWeight);
return 0;
} else { // if were not home then keep looping
int index = (rand() % sourceNode->arcCnt); // Generates random number between 0 and sourceNode->arcCnt
sourceNode = sourceNode->arcs[index];
//printf("Going to: %s, Index: %d", sourceNode->name, totalWeight);
}
i++;
}
return 0;
}
My code has two separate (although likely connected) problems, one of which being that when I print out the linked list (regardless of if I push nodes to the front or to the back), it prints an additional 0 at the start of the linked list. I saw a similar post about this, but the implementation of the push method was different, as it didn't take head as an argument, so I've defined head in the main() method with:
struct node *head = NULL;
and my linked list instantiation looks like
struct node *temp, *ptr;
temp=(struct node*)malloc(sizeof(struct node));
if(temp==NULL) {
exit(0);
}
temp->next=NULL;
if(head==NULL) {
head=temp;
} else {
ptr=head;
while(ptr->next!=NULL) {
ptr=ptr->next;
}
ptr->next=temp;
ptr->data=NULL;
}
The issue I'm having is that I'm not sure whether or not the issue is in the print method, my push front method or my linked list instantiation.
The relevant code is:
case PUSH_FRONT: ; // push onto front of list
struct node *temp1;
temp1=(struct node*)malloc(sizeof(struct node));
if(temp1==NULL) {
break;
}
temp1->next=NULL;
temp1->data=val;
if(head==NULL) {
head=temp1;
} else {
temp1->next=head;
head=temp1;
}
break;
case PRINT_LIST: ; // print list
printf("Elements: ");
struct node *ptr4;
ptr4=(struct node*)malloc(sizeof(struct node));
if(head==NULL) {
break;
} else {
ptr4=head;
while(ptr4) {
printf("%d",ptr4->data);
printf(" ");
ptr4=ptr4->next;
}
printf("\n");
free(ptr4);
}
break;
My other issue (although I'm still convinced that this issue lies elsewhere) is that my pop front method does absolutely nothing, which I'm guessing has to do with the initial instantiation of the linked list. The relevant code is:
case POP_FRONT: ; // remove from front of list
// If list is empty, do nothing.
struct node *ptr2;
ptr2=(struct node *)malloc(sizeof(struct node));
if(ptr2==NULL) {
break;
}
if(head==NULL) {
break;
} else if(head->next==NULL) {
ptr2=head;
head=head->next;
free(ptr2);
}
break;
You should post code someone could download and compile. And when
needed a data file or a description of the problem. Code fragments are
not good.
I believe that the data component of your list is just an int by looking at the code at the label PRINT_LIST
here goes what I think
a list is a collection of nodes. In java a list is even called a collection. In C++ lists are called containers. When you write code for a linked list as if it is a node you will have more work and less results.
as a direct consequence of using a node as a list you have 3 pointers here just to manage the list, in the instantiation code: head, temp and ptr, It is too much. Imagine if there where 3 lists...
a list with pointers only to one direction is harder to program and much less useful than one with pointers to next and previous nodes. If it is your decision may be you should reconsider. If the space of the additional pointer is not a concern, it is hard to justify not to use 2 pointers. Imagine a list for a library, a path,, a playlist, all the classic examples: it is very handful to be able to navigate in both directions.
the use of a switch() is uncommon. Why not just use functions?
back to your code
struct node *temp, *ptr;
temp=(struct node*)malloc(sizeof(struct node));
if(temp==NULL) {
exit(0);
}
temp->next=NULL;
if(head==NULL) {
head=temp;
} else {
ptr=head;
while(ptr->next!=NULL) {
ptr=ptr->next;
}
ptr->next=temp;
ptr->data=NULL;
}
here you write ptr->data = NULL; and we may think that data is a pointer, but in the list label you wrote
ptr4=head;
while(ptr4) {
printf("%d",ptr4->data);
printf(" ");
ptr4=ptr4->next;
}
printf("\n");
free(ptr4);
and data is just an int as you are using %d in the printf(). Well, the NULL in instantiation is, well, a zero.
And that NULL is the 0 you are complaining about.
This code seems to be much more complex and hard to read than it may need to be.
Let me show an alternative
about the declaration
You may write the node struct like
typedef struct _nd
{
int data;
struct _nd* next;
} node;
So you can use node in the declaration and not have to repeat struct at all times. Also it is useful to have a convention for typedef, like using first letter uppercase to help in readability
As I said before a list is a collection of nodes, it is NOT just a node --- with a pointer inside --- and each node has a payload, some data, usually a pointer. As an example consider
an alternate example of list structs
typedef struct _nda
{
int data;
struct _nda* next;
} Node;
struct _the_list
{
char* name;
unsigned size;
unsigned limit;
Node* head;
Node* tail;
};
typedef struct _the_list List;
Here the list is, well, List. And each list has head, tail, size, limit and even a name. I kept data as an int but is is not good: you really want it as a pointer, maybe (void*).
Why? Because in this way you can reuse the code everywhere with no change.
How to use a List like this?
Using functions like these possible prototypes
List* _create(const char*);
int _define_max(List* l, const unsigned);
List* _delete(List*);
int _empty(List*);
int _get_max(List*);
List* _insert_begin(int, List*);
List* _insert_end(int, List*);
int _insert_your_way(List*, int(*)(int,int));
int _print(List*);
int _print_your_way(List*, int(*)(int,int));
List* _remove(int, List*);
int _size(List*);
I will post a running example below just to have something you can test or ask about case you need. But it is the usual. Only these two functions are less usual, but more useful:
int _insert_your_way(List*, int(*F)(int,int));
int _print_your_way(List*, int(*F)(int,int));
Here you can pass a function like in the qsort() function, and the node is inserted at the position, using the function F() to compare the nodes. The effect is that you can have the nodes inserted (or listed) in any order, with no change in the list code, just by providing different functions to the print or insert function. C does that, C++ does that, everybody does that, so we can too :)
code for instantiating such a list
List* _create(const char* name)
{
List* one = (List*)malloc(sizeof(List));
one->name = (char*)malloc(1 + strlen(name));
strcpy(one->name, name);
one->size = 0;
one->limit = 0;
one->head = NULL;
one->tail = NULL;
return one;
}; // criar()
You may find that writing this way makes easier to maintain or read the code. And the List as a container is much more expressive: metadata about the list in included in the list. No need for ptr, head, temp, size or other controls hanging loose in main()
To create a list you can just write, like in the example
List* first = _create("The First List");
inserting nodes at the beggining
List* _insert_begin(int value, List* l)
{
if (l == NULL) return l; //no list
if ((l->limit > 0) && (l->size == l->limit)) return l; // full
// ok: create a node and stuff data in
Node* nd = (Node*)malloc(sizeof(Node));
nd->data = value; // data comes in
nd->next = l->head; // depois vem o que estava na frente
l->head = nd; // nd fim
l->size = l->size + 1;
// if it is the first node
if (l->size == 1)l->tail = nd;
return l;
};
As I told you this is just a toy, an example. In practice you will use a void* in order to have a generic code. I am using an int as data here, as you did. To insert a few nodes in the list created above you just write
// insert 6,7,8,9,10 at the end
for(int i = 6; i<11; i+=1 ) _insert_end(i, first);
And you can have even an array of lists and all goes well. No external variables to look after. And each list has size updated, head, tail...
printing nodes
print is also easy and can be more expressive, since we have metadata with limits, size, head, tail and even the name for each list.
sample program
int main(void)
{
List* first = _create("The First List");
_print(first);
_define_max(first,300);
_print(first);
// insert 5,4,3,2,1 at the beggining
for(int i = 5; i>0; i-=1 ) _insert_begin(i, first);
// list again
_print(first);
// insert 6,7,8,9,10 at the end
for(int i = 6; i<11; i+=1 ) _insert_end(i, first);
// list again
_print(first);
printf("empty(): %d size()= %d\n",
_empty(first),
_size(first) );
first = _delete(first);
_print(first);
return 0;
}
This code just
create a list and prints the nodes
set the optional limit to 300 nodes
list the nodes
insert 5,4,3,2,1 at the beginning
list the nodes
insert 6,7,8,9,10 at the tail
list the nodes
call a few functions on the list
deletes all data
output
List 'The First List' with 0 elements [MAX not defined yet]
List 'The First List' with 0 of 300 MAX elements
List 'The First List' with 5 of 300 MAX elements
First: 1
Last: 5
Elements
1
2
3
4
5
End of list
List 'The First List' with 10 of 300 MAX elements
First: 1
Last: 10
Elements
1
2
3
4
5
6
7
8
9
10
End of list
empty(): 0 size()= 10
Deleting 'The First List'
List not created!
the code (with almost no testing)
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct _nda
{
int data;
struct _nda* next;
} Node;
struct _the_list
{
char* name;
unsigned size;
unsigned limit;
Node* head;
Node* tail;
};
typedef struct _the_list List;
List* _create(const char*);
int _define_max(List* l, const unsigned);
List* _delete(List*);
int _empty(List*);
int _get_max(List*);
List* _insert_begin(int, List*);
List* _insert_end(int, List*);
int _insert_your_way(List*, int(*)(void*));
int _print(List*);
int _print_your_way(List*, int(*)(void*));
List* _remove(int, List*);
int _size(List*);
int main(void)
{
List* first = _create("The First List");
_print(first);
_define_max(first,300);
_print(first);
// insert 5,4,3,2,1 at the beggining
for(int i = 5; i>0; i-=1 ) _insert_begin(i, first);
// list again
_print(first);
// insert 6,7,8,9,10 at the end
for(int i = 6; i<11; i+=1 ) _insert_end(i, first);
// list again
_print(first);
printf("empty(): %d size()= %d\n",
_empty(first),
_size(first) );
first = _delete(first);
_print(first);
return 0;
}
List* _create(const char* name)
{
List* one = (List*)malloc(sizeof(List));
one->name = (char*)malloc(1 + strlen(name));
strcpy(one->name, name);
one->size = 0;
one->limit = 0;
one->head = NULL;
one->tail = NULL;
return one;
}; // criar()
int _define_max(List* l, const unsigned m)
{
if (l == NULL) return -1;
// new value can not be less than present size
if (l->size > m) return -2;
l->limit = m;
return m;
};
List* _delete(List* l)
{
if (l == NULL) return NULL;
printf("Deleting '%s'\n", l->name);
free(l->name);
if (l->size == 0)
{
free(l);
return NULL; // empty
}; // if()
Node* node = l->head;
do
{
Node* p = node->next;
free(node);
node = p;
} while (node != NULL);
return NULL;
};
int _empty(List* L)
{
if (L == NULL) return -1;
return (L->size == 0);
};
int _get_max(List* L)
{
if (L == NULL) return -1;
return (int)L->limit;
};
List* _insert_begin(int value, List* l)
{
if (l == NULL) return l; //no list
if ((l->limit > 0) && (l->size == l->limit)) return l; // full
// ok: create a node and stuff data in
Node* nd = (Node*)malloc(sizeof(Node));
nd->data = value; // data comes in
nd->next = l->head; // depois vem o que estava na frente
l->head = nd; // nd fim
l->size = l->size + 1;
// if it is the first node
if (l->size == 1)l->tail = nd;
return l;
};
List* _insert_end(int value, List* l)
{
if (l == NULL) return l;
if ((l->limit > 0) && (l->size == l->limit)) return l; // full
// ok: create a node and insert at the end
Node* nd = (Node*)malloc(sizeof(Node));
nd->data = value;
// first one?
if (l->size == 0)
{
l->head = nd;
nd->next = NULL;
}
else
{
nd->next = NULL; // no one after this
(l->tail)->next = nd;
}; // if()
l->tail = nd; // nd is tail now
l->size = l->size + 1;
// of this is the first node
if (l->size == 1)l->head = nd;
return l;
};
int _insert_your_way(List* L, int(*F)(void*))
{
return 0;
};
int _print(List* l)
{
if (l == NULL)
{
printf("List not created!\n");
return -1;
};
if (l->limit > 0)
{
printf("\nList '%s' with %d of %d MAX elements\n",
l->name,
l->size,
l->limit
);
}
else
{
printf("\nList '%s' with %d elements [MAX not defined yet]\n",
l->name,
l->size
);
}
if (l->size < 1) return 0;
// assume data as just an int
Node* p = l->head;
printf("\n First:%10d\n", l->head->data);
printf(" Last:%10d\n", l->tail->data);
printf("\nElements\n\n");
do
{
printf("%10d \n", p->data);
p = p->next;
} while (p != NULL);
printf("\nEnd of list\n\n");
return 0;
}; // _print()
int _print_your_way(List* L, int(*F)(void*))
{
return 0;
};
List* _remove(int value, List* L)
{
return NULL;
};
int _size(List* L)
{
if (L == NULL) return -1;
return (int)L->size;
};
It was extracted for a larger example, for WIndows. Compiled just under gcc 9.3 on Ubuntu on Windows WSL
I am trying to print out the results of the linked list in the reverse order that they were entered in. The program takes 3 inputs, Song name, song length (in seconds) and copyright. The program should take the list of songs and print the in the reverse order that they were entered in.
I am not too familiar with linked list. This is my first time using it as sort of a database.
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)
//defining struct
typedef struct node
{
char songName[20];
int songLength;
int copyright;
struct node * next;
}node;
//defining prototypes
node *create(int n);
void display(node *head);
int main()
{
int n = 0;
node *head = NULL;
printf("How many entries?\n");
scanf("%d", &n);
//call to create list
head = create(n);
printf("\nThe linked list in order is:\n");
display(head);
return 0;
}
node *create(int n)
{
node *head = NULL;
node *temp = NULL;
node *p = NULL;
for (int i = 0; i < n; i++)
{
temp = (node*)malloc(sizeof(node));
printf("What is the name of song %d\n", i + 1);
//fgets(temp->songName, 20, stdin);
scanf("%s", &temp->songName);
printf("What is the length of song %d (in seconds)?\n", i + 1);
scanf("%d", &temp->songLength);
printf("Is song %d copyrighted?(1 = YES, 0 = NO)\n", i + 1);
scanf("%d", &temp->copyright);
temp->next = NULL;
if (head == NULL)
{
head = temp;
}
else
{
// if not empty, attach new node at the end
p = head;
while (p->next != NULL)
{
p = p->next;
}
p->next = temp;
}
}
return head;
}
void display(node *head)
{
node *p = NULL;
if (head == NULL)
{
printf("List is empty\n");
}
else
{
p = head;
while (p != NULL)
{
printf("Song: %s, ", p->songName);
printf("%d minutes, ", p->songLength);
if (p->copyright == 1)
{
printf("Copyrighted\n");
}
else if (p->copyright == 0)
{
printf("No copyright\n");
}
p = p->next;
}
}
}
So if Input the following:
Song 1 - All Star (song name), 237 (seconds), 0 (no copyrights)
song 2 - Crab Rave, 193, 0
song 3 - 7 rings, 185, 1(copyrights)
The output should be:
7 rings, 185, 1
Crab Rave, 193, 0
All Star, 237, 0
If you have a single (forward) linked list, the probably easiest way to print it in reverse order is using recursion:
void display_recursive(node *n) {
if (!n) {
return;
}
display_recursive(n->next);
printf("Song: %s, ", n->songName);
...
}
Recursion means that a function is calling itself (until some end-condition, the anchor, is reached).
By that way, program flow will build up a "stack" of display_recursive- function calls, with the first node, then the second node, ..., until it reaches the last node; by then, recursion stops, and the print part of display_recursive is handled, starting with the last node backwards.
Hope this explanation helps; Try it out in the debugger to see what happens.
This program basically creates a list of flights with all their infos (read by the fread() function from a ListaVoli.bin).
The list is made up mainly by nodes and each node contains a flight.
#include <stdio.h>
#include <stdlib.h>
#define FILE_NAME "/Users/Matt/Downloads/ListaVoli.bin"
struct flight {
int flightCode;
char destination[3];
int scheduledDepHour;
int scheduledDepMinute;
int realDepHour;
int realDepMinute;
int passengers;
};
struct node {
struct flight volo;
struct node *next;
};
struct node *addToList(struct node *list, struct flight voloIn) {
struct node *newNode;
newNode = malloc(sizeof(struct node));
if (newNode == NULL) {
printf("Error: malloc failed\n");
exit(EXIT_FAILURE);
}
newNode -> volo = voloIn;
newNode -> next = list;
return newNode;
}
void printList(struct node *list) {
for (; list != NULL; list = list -> next) {
printf("Code:%d\nDestination:%s\nDeparture:%d-%d\nReal:%d-%d\nPassengers:%d\n\n\n",
list -> volo.flightCode,
list -> volo.destination,
list -> volo.scheduledDepHour,
list -> volo.scheduledDepMinute,
list -> volo.realDepHour,
list -> volo.realDepMinute,
list -> volo.passengers
);
}
}
void decolla(struct node *list, int flightCode, int realDepHour, int realDepMinute) {
for (; list != NULL; list = list -> next) {
if (flightCode == (list -> volo.flightCode)) { /*
printf("Inserisci ora di partenza per il volo %d: ", flightCode);
scanf("%d", &(list -> volo.realDepHour));
printf("Inserisci minuto di partenza: ");
scanf("%d", &(list -> volo.realDepMinute)); */
list -> volo.realDepHour = realDepHour;
list -> volo.realDepMinute = realDepMinute;
}
}
}
void delay(struct node *list) {
for (; list != NULL; list = list -> next) {
if ((list -> volo.realDepHour) - (list -> volo.scheduledDepHour) == 0) {
if ((list -> volo.realDepMinute) - (list -> volo.scheduledDepMinute) > 5 && (list -> volo.realDepMinute) - (list -> volo.scheduledDepMinute) < 30) {
printf("Il volo %d ha più di 5 minuti di ritardo\n", list -> volo.flightCode);
continue;
}
if ((list -> volo.realDepMinute) - (list -> volo.scheduledDepMinute) > 30) {
printf("Il volo %d ha più di 30 minuti di ritardo\n", list -> volo.flightCode);
continue;
}
} else
printf("Il volo %d ha più di 30 minuti di ritardo\n", list -> volo.flightCode);
}
}
void passengersCount(struct node *list) {
for (; list != NULL; list = list -> next) {
if (list -> volo.passengers > 200) {
printf("Il volo %d ha più di 200 passeggeri\n", list -> volo.flightCode);
continue;
}
}
}
int main() {
FILE *fp;
struct node *first = NULL;
struct flight volo;
/* Apro il file e controllo che sia stato aperto correttamente */
if ((fp = fopen(FILE_NAME, "rb")) == NULL) {
printf("Can't open %s\n", FILE_NAME);
exit(EXIT_FAILURE);
}
for (int i = 0; i < 4; i++) {
fread(&volo, sizeof(int), 7, fp);
first = addToList(first, volo);
}
decolla(first, 3497, 11, 30);
decolla(first, 2193, 11, 53);
decolla(first, 4284, 11, 07);
decolla(first, 5536, 12, 26);
printList(first);
delay(first);
passengersCount(first);
/* Controllo che il file sia chiuso correttamente */
if (fclose(fp) == EOF) {
printf("File not closed properly!");
exit(EXIT_FAILURE);
}
return 0;
}
The code compiles correctly so don't worry about the entire code, focus on the main() functions and the two structs.
I have two questions regarding the fread() function in the main() function:
Why, if I put sizeof(int) as the second parameter, the flight.destination value is assigned correctly? Shouldn't a char[3] variable be larger than sizeof(int)?
Why, if I put sizeof(struct flight) as second parameter (which would be the best choice), I get segmentation fault:11?
An array of three characters is three bytes. An int is usually (at least on modern 32 and 64 bit platforms) 4 bytes. It works to read sizeof(int) because the compiler adds padding.
But the "correct" (or at least usual) way to read the structure would be to read the whole structure as one single unit, i.e. using sizeof(volo) in your case:
fread(&volo, sizeof(volo), 1, fp);
If you get other errors because of it, you are doing something else wrong.
I'm trying to implement a linked list abstraction, however I am running into problems. Once I create the linked list and add elements to it. When I print the list it only prints the first element in it in an infinite loop fashion, meaning that either the first element is linked to itself or the print function is incorrect. However, I can't find the problem, could someone help?
The following is the list abstraction:
typedef struct _friend {
char *firstname;
char *lastname;
char birthdate[9];
} friend;
typedef struct _node {
friend *value;
struct _node *next;
} node;
typedef struct _linkedlist {
node *head;
} linkedlist;
The program must follow this abstraction, as it is part of something bigger.
The following are the functions that should print the list and add a node to the beginning of the list:
/* addHead
*
* This function takes two parameters - a linked list and a friend.
* This creates a node for the linked list and connects the friend to the
* node. Then it adds the node to the head of the linked list.
*/
void addHead(linkedlist *llist, friend *f)
{
// create a node and put the friend in it
node *n = (node *)malloc(sizeof(node));
n->value = f;
n->next = NULL;
// if the list is empty
if (llist == NULL)
{
// this link is the entire list
llist->head = n;
printf("adding friend to null list\n");
}
// if the list is not empty
else
{
// make the new link's next pointer point to
// the first link in the list
n->next = llist->head;
printf("adding %s to head\n", n->value->firstname);
// make the head pointer point to the new link
llist->head = n;
}
}
/*
* printList
*
* This steps down through each of the nodes in a linked list and
* prints out the information stored in the friend to which the node points.
* Instead of automatically printing to the screen, it prints to the
* file pointer passed in. If the programmer wants to print to the screen,
* he/she will pass in stdout.
*/
void printList(linkedlist *llist,FILE *fp)
{
node *n;
friend *f;
// for each node, print out the friend attached to it
for(n = llist->head; n != NULL ; n = llist->head->next)
{
// assign f to the friend of the right node
f = n->value;
// print the friend out
fprintf(fp,"%s %s: %s\n",
f->firstname, f->lastname, f->birthdate);
}
}
Thank You
The for loop in printList isn't quite right:
for(n = llist->head; n != NULL ; n = llist->head->next)
This should read:
for(n = llist->head; n != NULL ; n = n->next)
Otherwise from the second iteration onwards, n gets set to the same value every single time.
The following isn't related to the problem you're having, but I thought I'd mention it anyway. In the following code:
if (llist == NULL)
{
// this link is the entire list
llist->head = n;
printf("adding friend to null list\n");
}
if llist == NULL, the llist->head = n will segfault.
With the current signature of addHead(), there's not a lot you can do if llist is NULL (other than printing an error message and bailing out).
If instead you meant to check whether llist->head is NULL, you don't need to do that since the else block already handles that correctly.
Try:
void printList(linkedlist *llist,FILE *fp)
{
node *n;
friend *f;
// for each node, print out the friend attached to it
for(n = llist->head; n != NULL ; n = n->next)
{
// assign f to the friend of the right node
f = n->value;
// print the friend out
fprintf(fp,"%s %s: %s\n",
f->firstname, f->lastname, f->birthdate);
}
}
I have done the following to your program:
slightly modified the friend structure. Declared firstname and lastname as arrays for convenience.
Wrote a main() which calls other functions
error checking in addHead()
added create_friend() function which creates friend struct
added freeList() to release the memory which was malloc()'ed
corrected looping error in your print function
So here it goes..
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _friend {
char firstname[10];
char lastname[10];
char birthdate[9];
} friend;
typedef struct _node {
friend *value;
struct _node *next;
} node;
typedef struct _linkedlist {
node *head;
} linkedlist;
void addHead(linkedlist *llist, friend *f)
{
node *n = NULL;
if (( n = (node *)malloc(sizeof(node))) == NULL) {
printf("unable to allocate memory \n");
exit(1);
}
n->value = f;
n->next = NULL;
if (llist == NULL) {
llist->head = n;
printf("adding friend to null list\n");
} else {
n->next = llist->head;
printf("adding %s to head\n", n->value->firstname);
llist->head = n;
}
return;
}
void printList(linkedlist *llist)
{
node *n;
friend *f;
if (llist->head == NULL) {
printf("Empty list \n");
return;
}
for(n = llist->head; n != NULL ; n = n->next) {
f = n->value;
printf("%s %s %d \n", f->firstname, f->lastname, f->birthdate);
}
return;
}
friend * create_friend(char *fn, char *ln, char *dob)
{
friend *fp = NULL;
if ((fp = malloc(sizeof(friend))) == NULL) {
printf("unable to allocate memory \n");
exit(1);
}
strcpy(fp->firstname, fn);
strcpy(fp->lastname, ln);
strcpy(fp->birthdate, dob);
return fp;
}
void freeList(linkedlist *llist)
{
node *cur = llist->head;
node *prev = cur;
friend *f;
while (cur != NULL) {
prev = cur;
cur = cur->next;
f = prev->value;
printf("freeing .. %s %s %d \n", f->firstname, f->lastname, f->birthdate);
free(prev->value);
free(prev);
}
return;
}
int main(void)
{
linkedlist ll;
friend *f;
ll.head = NULL;
f = create_friend("firstname1", "lastname1", "12345678");
addHead(&ll, f);
f = create_friend("firstname2", "lastname2", "12345678");
addHead(&ll, f);
f = create_friend("firstname3", "lastname3", "12345678");
addHead(&ll, f);
printList(&ll);
freeList(&ll);
ll.head = NULL;
printList(&ll);
return 0;
}
Hope this helps!
Should be n = n ->next otherwise you're just getting the next of the head every time.