Linked List printing only last element in C - c

I'm suppose to implement QuickSort on a linked list, but I'm having trouble reading from text file into the list and printing all the nodes. I only get the last element printed as Output. What am I doing wrong?
My text file looks like this (password and its usage frequency):
asdfgh 31554
snoopy1 15637
qwertyuiop 24372
soccer 21208
.
.
Here's my structs
struct list_element {
char *password;
int count;
list_element* next;
};
struct list {
list_element* first;
list_element* last;
};
ReadfromData()
void read_data(char* filename, list* mylist)
{
FILE *fp;
char password[128];
int freq;
fp = fopen(filename, "r");
if(fp == NULL)
{
perror("Error opening file");
return;
}
while(fgets(password, sizeof(password), fp))
{
list_element *node = malloc(sizeof(list_element));
char *token;
token = strtok(password, " ");
node->password = strdup(token);
if( token != NULL ){
token = strtok(NULL, " ");
}
freq = atoi(token);
node->count = freq;
node->next = NULL;
insert_list(node, mylist);
}
fclose(fp);
}
Insert infront in List
void insert_list(list_element* le, list* mylist)
if((mylist->first = NULL)){
mylist->first = le;
}else{
le->next = mylist->first;
mylist->first = le;
}
Print list
void print_list(list* mylist)
list_element *temp;
temp = mylist->first;
while(temp != NULL)
{
printf("pass %s and count %d \n", temp->password, temp->count);
temp = temp->next;
}
I've also wrote a small function, which I call in the beginning of the program to intailize the list:
void init_list(list* mylist){
mylist = (list*)malloc(sizeof(list));
mylist->first = mylist->last = NULL;
}
but I don't think it makes sense to do a malloc here too, since I already create node one by one, right? Confused abit.
Any advice would be great!

Lets take a closer look at the init_list function:
void init_list(list* mylist){
mylist = (list*)malloc(sizeof(list));
mylist->first = mylist->last = NULL;
}
The argument mylist is a local variable. And as such it will go out of scope when the function ends and all changes to it will be lost. Because of this the pointer you will be using after the call to init_list will not actually be initialized and you will have undefined behavior when you use it.
There are two solutions: Either have init_list take no argument and instead return the new list. Or you emulate pass by value by passing a pointer to the list variable from the calling function, meaning the init_list function takes a pointer to a pointer to the structure.
The second alternative could look like this
void init_list(list **mylist)
{
*mylist = malloc(sizeof **mylist);
(*mylist)->first = (*mylist)->last = NULL;
}
Then you call it using the address-of operator:
list *mylist;
init_list(&mylist);

Related

print from users input linked list of struct

I am required to have a list of structs of sentence nodes that point to a struct of word nodes. I am trying to print the user's input.
I have a program that runs properly when I manually give it the input (see test section of the code). It does not, however, work when I use my input1() function.
I've tried debugging it, but I can't seem to find the problem.
I removed all printf lines that I used to debug. I also removed all the irrelevant code.
I am looking to know how to fix it and what is wrong so I can run it with no problems.
What I learned from debugging it is that (only when using input1() and not in the test) the head is overwritten every time and all the nodes as well.
I also tried using a double pointer instead of returning para but that didn't help.
any help will be appreciated,
thanks in advance
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct word
{
char * ch;//poiter to char
}
W;
typedef struct sentence
{
W * currentWord;//pointer to a word
int lineNumber;// holds the line number
int numbersOfWords;//holds the number of words
struct sentence* link;
}
sent;
typedef struct list
{
sent* head;
int count;
}
LISTS;
LISTS* createList()
{
LISTS* list;
list= (LISTS*) malloc (sizeof (LISTS));
if (list)
{
list-> head = NULL;
list-> count = 0;
}
return list;
} // createList
void printList(LISTS* list)
{
sent *temp = list -> head;
//iterate the entire linked list and print the data
while(temp != NULL)
{
printf("%s\n", temp->currentWord->ch);
temp = temp->link;
}
// printf("NULL\n");
}
void insertSentList (LISTS* list, W* itemPtr)
{
sent* newPtr; //new node
if (!(newPtr = (sent * ) malloc(sizeof(sent)))){
printf(" Memory can not be allocated.");
return;
}
newPtr->currentWord = itemPtr;
newPtr->link = NULL;
if(list->head == NULL)
{
list->head = newPtr;
}else{
sent* current = list->head;
while(current->link != NULL){
current = current->link;
}
current -> link = newPtr;
}
(list->count)++;
return;
} // insertList
LISTS * input1(LISTS *para)
{
char * line;
line = (char * ) malloc(1000 * sizeof(char));
line[0] = '\0';
while (line[0] != '\n')
{
W word;
word.ch = (char * ) malloc(100);
printf(" Please input a line : ");
fgets(line, 1000, stdin);
if(line[0] != '\n'){
strcpy(word.ch, line);
insertSentList(para,&word);
}
}
free(line);
return para;
}
int main()
{
///////////////////test////////////////
LISTS* list = createList();
W word;
word.ch= "word0 ";
W word1;
word1.ch= "word1 ";
W word2;
word2.ch= "word2";
insertSentList(list,&word);
insertSentList(list,&word1);
insertSentList(list,&word2);
insertSentList(list,&word);
insertSentList(list,&word1);
insertSentList(list,&word2);
printList(list);
///////////////////test////////////////
LISTS *para = createList();
para= input1(para);
printList(para);
return 0;
}
Main problem with the posted code is that "ownership" of the sent and W objects in a list is not well defined. For example word.ch= "word0 "; in main sets the ch pointer pointing to a string literal (which it does not own), but word.ch = malloc(100); in input1 points it to dynamically allocated memory (which it should own, and remember to free later). Because of this, memory allocations cannot be tracked reliably and, even in the cases where things appear to "work", there are multiple memory leaks. It also breaks when the inserted objects are local variables that do not live for the entire lifetime of the list object.
The simplest (if not necessarily the best or most efficient) solution would be to dynamically allocate all objects that go into the list, make the list own them all, and add a function to cleanup once done. To that end insertSentList could be modified as follows.
void insertSentList (LISTS* list, W* itemPtr)
{
sent* newPtr; //new node
if (!(newPtr = malloc(sizeof(sent)))){
printf(" Memory can not be allocated.\n");
return;
}
W *newItem = malloc(sizeof(W)); // <-- make a deep copy of the `itemPtr` argument
newItem->ch = strdup(itemPtr->ch); // including a copy of the string itself
newPtr->currentWord = newItem; // <-- save the copy in the list, not the argument
newPtr->link = NULL;
if(list->head == NULL)
{
list->head = newPtr;
}else{
sent* current = list->head;
while(current->link != NULL){
current = current->link;
}
current->link = newPtr;
}
list->count++;
} // insertList
For proper cleanup and to avoid memory leaks, the following freeList should be called for each list pointer returned by createList and filled by insertSentList.
void freeList(LISTS *list)
{
sent *temp = list->head;
while(temp != NULL)
{
sent *next = temp->link;
free(temp->currentWord->ch);
free(temp->currentWord);
free(temp);
temp = next;
}
free(list);
}

Address of nodes keep overwriting each other when being added to linked list

I'm trying to use tasklist and pipe the output to my code and parse each line to then create nodes of every process. I will later be filtering through them but that is not in the code yet. I'm having problems with the LIST. I have implemented 3 structs for this program: LIST (head for first node, rear for last node and count for number of nodes in list), NODE (pointer to PROCESS_INFO and pointer to next NODE), PROCESS_INFO (4 char pointers for process name, PID, memory usage and cputime). I've used printf to track my code and everything seems to work properly until I get to adding them to the linked list. The address of each nodes are different but it always seems to overwrite the last one in the list instead of adding the new address of the node to the next* of the previous node.
I'm mostly positive my algorithm is correct, it's the same one I've used multiple times just with different data. My malloc functions have dynamic checks incase they fault and I've checked and played with my pointers incase I was missing a dereference of some sort but I get errors if I change anything so I don't think those are the problem funny enough.
The only thing I can think of that would be the problem is the fact that all this doing resides in a loop in a function (I read somewhere that pointers on a stack can't remember their address?). What would I have to change though to fix this? I've moved everything to main but nothing changed.
Struct Definitions:
typedef struct processInfo{
char *pName;
char *processId;
char *memUsage;
char *cpuTime;
}PROCESS_INFO;
typedef struct node{
PROCESS_INFO* data;
struct node* next;
}NODE;
typedef struct li{
int num;
NODE* head;
NODE* rear;
}LIST;
Main function:
int main()
{
LIST* list;
list = buildList();
printList(list);
}
List functions:
//function that creates a new list and returns it as null
LIST* createList()
{
LIST* newListPtr;
newListPtr = (LIST*)malloc(sizeof(LIST));
if (newListPtr)
{
newListPtr->num = 0;
newListPtr->head = NULL;
newListPtr->rear = NULL;
}
return newListPtr;
}
//function that creates the struct for the information of the process
PROCESS_INFO* createPinfo(char* name, char* pid, char* kb, char* cTime)
{
PROCESS_INFO* pInfoPtr;
pInfoPtr = (PROCESS_INFO*)malloc(sizeof(PROCESS_INFO));
if (pInfoPtr)
{
pInfoPtr->pName = name;
pInfoPtr->processId = pid;
pInfoPtr->memUsage = kb;
pInfoPtr->cpuTime = cTime;
}
return pInfoPtr;
}
//function to create new node and set its data
NODE* createNode(PROCESS_INFO* dataPtr)
{
NODE* nodePtr;
nodePtr = (NODE*)malloc(sizeof(NODE));
if (nodePtr)
{
nodePtr->data = dataPtr;
nodePtr->next = NULL;
}
return nodePtr;
}
//Get process information node via the path
PROCESS_INFO* parseInfoFromPath (char str[])
{
char *pName;
char *processId;
char *memUsage;
char *time;
char *parse;
parse = strtok(str, " ");
pName = parse;
parse = strtok(NULL, " ");
processId = parse;
parse = strtok(NULL, " "); //Console
parse = strtok(NULL, " "); //session
parse = strtok(NULL, " "); //memory
memUsage = parse;
parse = strtok(NULL, " ");
parse = strtok(NULL, " ");
parse = strtok(NULL, " ");
parse = strtok(NULL, " "); //CPUTIME
time = parse;
PROCESS_INFO* pInfoPtr;
pInfoPtr = createPinfo(pName, processId, memUsage, time);
return pInfoPtr;
}
BuildList() function where I seem to be getting the semantic error:
LIST* buildList()
{
FILE *fp;
char path[PATH_MAX];
fp = popen("tasklist /v /fi \"STATUS eq running\" /nh ", "r");
if (fp == NULL)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
LIST* list_;
PROCESS_INFO* p;
NODE* n;
list_ = createList();
while (fgets(path, PATH_MAX, fp) != NULL)
{
if (path != NULL)
{
//create the process info struct
p = parseInfoFromPath(path);
//create the node
n = createNode(p);
//add node to list
//if empty list set as head
if (list_->head == NULL){
list_->head = n;
}
//otherwise set last->next to point to the new node
else {
list_->rear->next = n;
}
//rear points to last node
list_->rear = n;
(list_->num)++;
}
}
//They always print out the same data!!!!
printf("\nIn Loop: Head Node name: %s", list_->head->data->pName);
printf("\t\tIn Loop: Read Node name: %s", list_->rear->data->pName);
return list_;
}
You are not copying the strings for each input field you find. Instead you are holding pointers into your path buffer, which gets overwritten every time you do fgets. Try using strdup in createPinfo:
PROCESS_INFO* createPinfo(char* name, char* pid, char* kb, char* cTime)
{
PROCESS_INFO* pInfoPtr;
pInfoPtr = (PROCESS_INFO*)malloc(sizeof(PROCESS_INFO));
if (pInfoPtr)
{
pInfoPtr->pName = strdup(name);
pInfoPtr->processId = strdup(pid);
pInfoPtr->memUsage = strdup(kb);
pInfoPtr->cpuTime = strdup(cTime);
}
return pInfoPtr;
}
Also, since strdup allocates heap memory, don't forget to add a function to free the memory and call it every time you remove something from the list. Eg:
void destroyPinfo(PROCESS_INFO* pInfoPtr)
{
if (pInfoPtr)
{
free(pInfoPtr->pName);
pInfoPtr->pName = NULL;
free(pInfoPtr->processId);
pInfoPtr->processId = NULL;
free(pInfoPtr->memUsage);
pInfoPtr->memUsage = NULL;
free(pInfoPtr->cpuTime);
pInfoPtr->cpuTime = NULL;
}
}
You will probably want to NULL check the results of strdup like you do malloc (I'm too lazy to add this in to the answer though, as long as you get the basic idea).

C Quicksort (linked list) segmentation fault

I have to create a quicksort on a linked list (in C).
I have my first and last pointer an the pivot (in this code it's the first element of the list).
The structs I have to use:
typedef struct list_element list_element;
struct list_element {
char *password;
int count;
list_element* next;
};
typedef struct list list;
struct list {
list_element* first;
list_element* last;
};
I have a file with 100 passwords and counts.
Like this:
password1 123 (next line) password2 435 (next line) password3 133 ...
The passwords have to be sorted (according to their count) in the end of this programm.
There isn't needed any extra memory allociation for the left and right lists because I only have to use the next pointers. (That's what the hint in the exercise says.)
The given main-function:
int main(int argc, char** args)
{
if (argc != 2)
{
printf("Nutzung: %s <Dateiname>\n",args[0]);
return 1;
}
list mylist;
init_list(&mylist);
read_data(args[1],&mylist);
qsort_list(&mylist);
printf("Sortierte Liste:\n");
print_list(&mylist);
free_list(&mylist);
return 0;
}
I have initialized my list:
void init_list(list* mylist)
{
mylist->first = NULL;
mylist->last = NULL;
}
And insert a new element at end (passwort = passwords in file, hauefigkeit = counts in file):
void insert_list(list_element* le, list* mylist)
{
if (mylist->first != NULL) {
le->next = mylist->last;
mylist->last = le;
le->next= NULL;
}
else {
mylist->last->next = le;
mylist->last = le;
mylist->last->next = NULL;
}
}
Read data from file:
void read_data(char* filename, list* mylist)
{
FILE *file_in = fopen(filename, "r");
if (file_in == NULL) {
perror("Could not open input file!");
exit(1);
}
char buffer[999] = "0";
char *passwort = (char*) calloc(1,sizeof(passwort));
int haeufigkeit = 0;
while (fgets(buffer, sizeof(buffer), file_in) != NULL) {
sscanf(buffer, "%s %d", passwort, &haeufigkeit);
list_element* le = (list_element*)calloc(1,sizeof(list_element));
for(int i = 0; i <=100; i++) {
le->password[i] = passwort[i];
}
le->count = haeufigkeit;
le->next = NULL;
insert_list(le, mylist);
}
fclose(file_in);
}
Partition of the list:
list_element* partition( list* input, list* left, list* right )
{
list_element* pivot = NULL;
if (input->first != NULL) {
list_element* temp;
pivot = input->first;
input->first = input->first->next;
pivot->next = NULL;
left->first = NULL;
right->first = NULL;
while (input->first != NULL) {
if((pivot->count)>(input->first->count)){
temp=input->first->next;
insert_list(input->first, left);
input->first=temp;
}
else {
temp = input->first->next;
insert_list(input->first, right);
input->first = temp;
}
}
}
return pivot;
}
The actual quicksort:
void qsort_list(list* mylist)
{
if(mylist->first == mylist->last){
}
else{
list* left = calloc(1,sizeof(list));
list* right= calloc(1,sizeof(list));
list_element* pivot = partition(mylist, left, right);
qsort_list(left);
qsort_list(right);
if(left->first == NULL){
mylist->first = pivot;
}
else{
mylist->first = left->first;
left->last->next = pivot;
}
if(right->first == NULL){
pivot->next = NULL;
mylist->last = pivot;
}
else{
pivot->next = right->first;
mylist->last = right->last;
}
free(right);
free(left);
}
}
In the end print list:
void print_list(list* mylist)
{
list_element *elem = mylist->first;
while (elem != NULL) {
printf("%s %d\n", elem->password, elem->count);
elem = elem->next;
}
}
And free list:
void free_list(list* mylist)
{
list_element *current;
list_element *second;
current = mylist->first;
while (current != NULL) {
second = current->next;
free(current);
current = second;
}
}
Syntax should be ok. GCC (c99, Wall) compiles without any problems.
But there is an segmentation fault. I have been searching for hours now and I have no idea where the problem could be. Maybe you can help me with this problem.
After the first two answers there isn't any segmentation fault. But still have a problem with read_data function.
The program can't read the passworts correctly. Maybe i misunderstood you answers in relation to the read function.
That's the current function:
void read_data(char* filename, list* mylist)
{
FILE *file_in = fopen(filename, "r");
if (file_in == NULL) {
perror("Could not open input file!");
exit(1);
}
char buffer[999] = "0";
int haeufigkeit = 0;
while (fgets(buffer, sizeof(buffer), file_in) != NULL) {
char passwort[100];
sscanf(buffer, "%s %d", passwort, &haeufigkeit);
list_element* le = (list_element*)
calloc(1,sizeof(list_element));
le->password = passwort;
le->count = haeufigkeit;
le->next = NULL;
insert_list(le, mylist);
}
fclose(file_in);
}
As Leonardo Alves Machado pointed out, the first reflex when having trouble with a C/C++ program is to run it with a debugger like gdb. Here is the basics:
gcc -g main.c -o main
gdb main
(gdb) run
Note the -g compilation flag: this will add debug information to the executable.
In read_data, the lines
for(int i = 0; i <=100; i++) {
le->password[i] = passwort[i];
}
really bug me. You allocate space for passwort (which you never free by the way) and try to copy it to le->password, which is a simple pointer (no allocated space). What you actually need is to make le->password point to passwort, i.e.
le->password = passwort;
In free_list, don't forget to deallocate the passwort space before deallocating the list_element space with:
while (current != NULL) {
second = current->next;
free(current->password);
free(current);
current = second;
}
One of the first issues your program encounters is that read_data() does not allocate enough space for passwort. It's unclear, actually, why you are dynamically allocating this at all, but given that you are doing so, sizeof(passwort) is the size of one pointer to char (since that's what passwort is) -- probably either 4 or 8 bytes. Later, you seem to assume that the allocated space is 100 bytes long when you (attempt to) copy its contents into a list element. Why not simply declare it as a 100-char array?
char passwort[100];
Indeed, if you also declare list_element.passwort the same way then your password-copying code inside the loop will be correct, albeit a bit non-idiomatic.
As it is, that code is problematic, as #Derlin observes. His proposed solution is incorrect, however; you must not make the list elements point to the local passwort as long as that is allocated only once for the whole routine. Then all list elements will have the same password string, which is not what you want. If you want your list elements to contain pointers to the passwords, as they do now, then you'll want to move the declaration and allocation of passwort inside the loop, so that you get separate password space allocated for each list element. Then the suggestion to assign le->password = passwort would be correct.
Another early issue is that your insert_list() function is badly broken.
Consider first what happens when you try to insert an element into an empty list, as initialized by init_list(). The list's next and last members will both be null, and insert_list() will therefore attempt to execute this code:
mylist->last->next = le;
mylist->last = le;
mylist->last->next = NULL;
Observe that mylist->last is null, therefore the first line invokes undefined behavior by attempting to dereference a null pointer. A segmentation fault is an eminently plausible observed result. You might fix that by changing the first of those lines to
mylist->next = le;
Now consider what happens when you try to insert into a non-empty list. In that case, you execute these lines:
le->next = mylist->last;
mylist->last = le;
le->next= NULL;
Since your intention is to insert the new element at the end (i.e. to append it), it is odd that you set the new element's next pointer to the list's last element. It is especially odd that you later overwrite that value with NULL. You seem to have it backward: you want to set the initial last element to point to the new element as its next element, not the other way around:
mylist->last->next = le;
Indeed, that's exactly the code that was wrong for the empty-list case, but it's fine when the list is non-empty.
Overall, your function also suffers from an odd lack of parallelism and some hidden code duplication. I'd probably write the overall function something more like this:
void append_to_list(list_element* le, list* mylist)
{
le->next= NULL;
if (mylist->first != NULL) {
mylist->last->next = le;
mylist->last = le;
}
else {
mylist->first = le;
mylist->last = le;
}
}

error with pointers and linked list node creation

I'm trying to read line input from a file, correctly parse the line, and add the three fields of information from the line onto a node in a linked list.
Here's my read from file function:
int readFile(char* file)
{
FILE *fp = fopen(file,"r");
char ch;
char line[50];
char string1[100];
char string2[100];
char string3[100];
char endLine[2];
int i = 0;
while(fscanf(fp, "%[^\t]\t%[^\t]\t%[^\n]", string1, string2, string3) == 3)
{
printf( "%s\t%s\t%s\n", string1, string2, string3);
addNode(string1, string2, string3, head, tail);
}
printNodes();
fclose(fp);
return 0;
}
And here is my addNode function:
// create stuff
Entry *entry = malloc(sizeof(Entry));
entry->name = string1;
entry->address = string2;
entry->number = string3;
Node* node = malloc(sizeof(Node));
node->entry = entry;
node->next = NULL;
// Empty list
if(head->next == NULL)
{
head->next = node;
}
// Else, add to the end of the list
else
{
Node* temp = head->next;
while(temp->next!= NULL)
{
temp = temp->next;
}
temp->next = node;
}
I get problems when I call printNodes, and only the last read node's information is printed X times, where X is the number of unique nodes I'm supposed to have. I think I'm having a problem where I'm overwriting an old node each time I create a new node, but I'm not entirely sure, as this is my first time with raw C code.
Thanks again!
EDIT:
here's the printNodes() function:
int printNodes(Node* head)
{
Node *temp = head->next;
while(temp->next != NULL)
{
printf("\n%s\t%s\t%s\n", temp->entry->name, temp->entry->address, temp->entry->number);
temp = temp->next;
}
return 0;
}
Your problem is here:
entry->name = string1;
entry->address = string2;
entry->number = string3;
You are providing the same memory location to every node. Those strings contain the last value you read in when you call printNodes().

Linked list in C, is the list being constructed correctly?

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.

Resources