A I have managed to get the linked list to function in the sense that it can create a list store variables in them, but now I have run into another issue that I've never been able find the solution to. Any time I run it through a list of variables I want stored it will run through the list and create the right number of nodes, but the string variable keeps getting changed after each append.
For example if I run:
"Dog" "cat" "house"
Instead of the desired output:
Dog
cat
house
It produces
house
house
house
I'm unsure why it keeps doing it and I can't seem to pin where the head node string is being altered except for the first instance in which the list is empty and thus needs to assign a new head.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#define EMPTY NULL;
typedef struct listnode{
struct listnode* next;
char* fileName;
} listnode;
struct listnode* head;
//This section of code will be dedicated to the creation and management
//of the listnode functions
listnode* createNode(char* str, listnode* next){
listnode* tempo;
tempo = (listnode*)malloc(sizeof(struct listnode));
if(tempo == NULL){
printf("Error creating space for new node.\n");
exit(0);
}
tempo->fileName = str;
tempo->next = next;
return tempo;
}
listnode* append(listnode* head, char* str){
listnode* temp;
listnode* curr;
temp = createNode(str, NULL);
if(head == NULL){
head = temp;
return head;
}
else{
curr = head;
while(curr->next != NULL){
curr = curr->next;
}
curr->next = temp;
return head;
}
}
void printNames(listnode* head){
listnode* curr= head;
while(curr !=NULL){
printf("%s \n", curr->fileName);
curr = curr->next;
}
}
void list_free(listnode* head){
listnode* current;
listnode* temp;
if(head != NULL){
current = head->next;
if(head !=NULL){
current = head -> next;
head ->next = NULL;
while(current != NULL){
temp = current -> next;
free(current);
current = temp;
}
}
}
free(head);
}
int main(int argc, char **argv){
char *current_dir = NULL;
DIR *direct_ptr = NULL;
struct dirent *dir_ptr = NULL;
unsigned int fileNum = 0;
int c;
listnode* head = NULL;
current_dir = getenv("PWD");
if(NULL == current_dir){
printf("\n Error: Couldn't grab current directory.\n");
return -1;
}
direct_ptr = opendir((const char*)current_dir);
if(NULL == direct_ptr){
printf("\n Error: couldn't open current directory\n");
return -1;
}
for(fileNum=0; NULL != (dir_ptr = readdir(direct_ptr)); fileNum++){
if(dir_ptr->d_name[0] != '.'){
head = append(head, dir_ptr->d_name);
}
}
printNames(head);
}
In C, arrays (such as strings) are not passed by value. They are instead passed by pointer. When you specify the a char array as a function parameter, the array decays to a pointer.
Therefore, you must either
ensure that the string that the listnode struct member filename points to remains valid and is not overwritten, or
store a copy of the string in the listnode struct.
In order to copy a string, you can use the function strcpy. However, you must then either allocate enough space for the char array in the listnode struct or you must use dynamic memory allocation (such as malloc) and store a pointer to the dynamically allocated memory.
Related
I'm trying to write and use linked list. When trying to print the list to the file the first string gets chained to the last node and it causes a segfault.
I've tried debugging and it led me nowhere.
It only happens using printListToFile(...) and readstl(...).
The code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lists_c.h"
#define test "ijm digidimdimadam jjsklva /s4t\t \nmjam \nla kookaracha la kookaracha\n"
/*a method that creates a "blank" node, declares a the next node and points it to NULL, the char array is already initialized.*/
struct Node *makeNode();
struct Node *makeFullNode(struct Node *Next, char *Ptr);
struct Node *readFile(char *path);
struct Node *readstl(char*);
void printList(struct Node *head);
void insertToList(struct Node *node, char *str);
void printListToFile(char *path, struct Node *head);
int main(int argc, char *argv[])
{
struct Node *head;
head = (struct Node *)malloc(sizeof(struct Node));
printf("this is mmn 23 Q3, a func that stores a file in a linked list and then prints it.\n");/*
printf("%s\n",argv[1]);
if (argc == 2) { */
head = readFile("tester1.txt");
printList(head);
printListToFile("test.tmp", head);
insertToList(head->next, test);
printf("head");
free(head);
/*}
else if (argc > 2) {
printf("Too many arguments supplied.\n");
} else {
printf("One argument expected.\n");
}*/
return 0;
}
struct Node *makeNode()
{
struct Node *node;
node = (struct Node *)malloc(sizeof(struct Node));
if (node == NULL) {
printf("memory allocation failed\n");
return NULL;
}
node->next = NULL;
return node;
}
/*a method that creates a node with all values, declares a the next node and points it to the next node recieved
and changes the char array to the one recieved.*/
struct Node *makeFullNode(struct Node *Next, char Ptr[])
{
struct Node *node;
node = (struct Node *)malloc(sizeof(struct Node));
node->next = (struct Node *)malloc(sizeof(struct Node));
node->ptr[NICE] = Ptr[NICE];
node->next = Next;
return node;
}
/*the method that reads the file into the list into the char array of each node and returns the head of the list */
struct Node *readFile(char *path)
{
FILE *fptr;
struct Node *curr, *head;
curr = (struct Node *)malloc(sizeof(struct Node));
head = (struct Node *)malloc(sizeof(struct Node));
if (curr == NULL || head == NULL) {
printf("memory allocation failed\n");
return NULL;
}
curr = head;
fptr = fopen(path,"r");
if (fptr == NULL) {
printf("error - failed to open file\n");
exit(0);
return NULL;
}
while (fgets(curr->ptr, NICE, fptr))/*if fgets returns NULL it means that we either reached EOF or error, both a reason to end the loop*/
{
curr->next = makeNode();
curr = curr->next;
}
if(ferror(fptr))/*checking if the loop ended for the right reason*/
{
printf("error - failed to read file\nthis is what we got so far\n");
}
printf("file succesfully read\n");
fclose(fptr);
free(curr);
return head;
}
/*the method that reads the file into the list into the char array of each node and returns the head of the list */
struct Node *readstl(char *path)/*!!!problem!!!*/
{
FILE *fptr;
int i, len;
struct Node *head;
head = (struct Node *)malloc(sizeof(struct Node));
fptr = fopen("readstrtofile.tmp", "w");
if (fptr == NULL) {
printf("error - failed to open file\n");
exit(0);
return NULL;
}
len = strlen(path);
for (i = 0; i < len && fputc(*(path + i), fptr) != EOF; i++);
if (ferror(fptr))/*checking if the loop ended for the right reason*/
{
printf("error - failed to read into file\nthis is what we got so far\n");
}
fclose(fptr);
head = readFile("readstrtofile.tmp");
remove("readstrtofile.tmp");
return head;
}
/*a method that prints the recieved list depending on the list to have the equal length rows.
as specified in mmn 12 tab creating uneven rows is acceptable therefor when ever there is tab in the file
the rows will appear uneven as to tab takes a place of one char but prints to 8 blank spaces in ubuntu */
void printList(struct Node *head)
{
struct Node *curr;
curr = (struct Node *)malloc(sizeof(struct Node));
if (head == NULL) {
printf("empty list\n");
return;
}
if (curr==NULL) {
printf("memory allocation failed\n");
return;
}
printf("this is the list printed nicely\n");
curr = head;
printf("%s\n", curr->ptr);
while (curr->next != NULL) {
curr = curr->next;
printf("%s\n", curr->ptr);
}
printf("\n/********************/\n");
}
/* a method that creates a new file named path and prints a list to it */
void printListToFile(char *path,struct Node *head)/*!!!problem!!!*/
{
struct Node *curr;
char c;
int i;
FILE *fptr;
curr = (struct Node *)malloc(sizeof(struct Node));
if (curr == NULL) {
printf("memory allocation failed\n");
exit(0);
}
curr = head;
fptr = fopen(path, "w+");
if (fptr == NULL) {
printf("error - failed to open file\n");
exit(0);
}
if (head == NULL) {
printf("empty list\n");
exit(0);
}
printf("this is the file %s printed nicely\n",path);
curr = head;
while (curr->next != NULL) {
printf("new node -> ptr -> %s\n",curr->ptr);
/*if(sizeof(curr->ptr)/sizeof(char)<=NICE)
{*/
for(i=0;i<NICE && (c = fputc(curr->ptr[i],fptr)) != EOF;i++);
printf("puting %s to file %s\n",curr->ptr,path);
curr = curr->next;
printf("bolili\n");
/*}
else
{
printf("lilibo\n");
break;
}*/
}
printf("\n/********************/\n");
}
/* a method that recievs a string turns it into a list and inserts it into another list */
void insertToList(struct Node *node, char *str)
{
struct Node *tail, *head;
tail = (struct Node *)malloc(sizeof(struct Node));
head = (struct Node *)malloc(sizeof(struct Node));
if (tail == NULL || head == NULL) {
printf("memory allocation failed\n");
return;
}
head = readstl(str);/*reading the string to a node*/
printList(head);
printf("\n/***********in insert*********/\n");
tail = head;
while (tail->next) {
tail = tail->next;
}/*getting tto the last node to connect it*/
strcpy(tail->ptr, node->next->ptr);/*connecting the lists*/
tail->next = node->next->next;
strcpy(node->ptr, head->ptr);
node->next = head->next;
printf("inserted string successfully\n");
}
/* a method that returns the size of the list*/
unsigned int sizeOfList(struct Node *head)
{
struct Node *tmp;
int size;
if (!(head))
return 0;
size = 1;
tmp = (struct Node *)malloc(sizeof(struct Node));
tmp = head;
while ((tmp = tmp->next))
size++;
return size;
}
header file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NICE 80
#define debug "\n/****************/\n"
/*the node structure of a the list which contains a string the size we choose is nice
to print by and a pointer to the next node in the list. */
struct Node {
char ptr[NICE];
struct Node *next;
};
/*makeNode - a method that returns a newely created node and sets all values to NULL values.*/
struct Node *makeNode();
/*makeFullNode - a method that return a newely created node with values set to params as listed below.
#param Next - tho ptr to the next node desired.
#param Ptr - the string that will go into the node ptr.*/
struct Node *makeFullNode(struct Node *Next, char *Ptr);
/*readFile - a method that reads a file into a linked list returning the head to that list.
it reads the file using fgets and a const to decide what size the node strings should be.
#param path - the name of the file to open.
#return the head of the list.*/
struct Node *readFile(char *path);
/*readstl - a method that reads a string into a linked list returning the head to that list.
it prints the list to a tmp file then reads the file using readFile.
#param path - the string to read.
#return the head of the list.*/
struct Node *readstl(char*);
/*printList - a method that prints the list to stdout.
it goes in loop on the nodes each time printing the node->ptr.
#param head - the head of the linked list.*/
void printList(struct Node *head);
/*insertToList - a method that inserts a string into list.
it creates a new list using readstl the connects the nodes using the basic method.
#param node - the node to override.
#param str - the string to insert.*/
void insertToList(struct Node *node, char *str);
/*a method that prints the list to stdout.
it goes in loop on the nodes each time printing the node->ptr.
#param head - the head of the linked list.*/
void printListToFile(char *path,struct Node *head);
/*sizeOfList - a method that returns how many node are in the list.
it goes in a while loop incresing counter by 1 each iteration.
#param head - the head of the list to measure.
#return the size of the list.*/
unsigned int sizeOfList(struct Node *head);
I think it is this line:
for(i=0;i<NICE && (c = fputc(curr->ptr[i],fptr)) != EOF;i++);
Why would fputc ever return EOF if everything goes right? It will try to write characters behind the ptr array. From the manpage of fputc:
fputc(), putc() and putchar() return the character written as an unsigned char cast to an int or EOF on error.
This means, your loop writes as long as fputc doesn't return an error code. But what you probably want, is writing either 80 (NICE is not a nice constant name) or strlen(curr->ptr) characters. Assuming based on your readFile function, you want both things as a limit. I would recommend rewriting this line as:
int len = strnlen(curr->ptr, 80);
if (fwrite(curr->ptr, 1, len, fptr) < 0) {
printf("error writing file");
}
or if the string is always null terminated:
if (fputs(curr->ptr, fptr) < 0) {
printf("error writing file");
}
Also ptr is not a good name for an array. It might confuse people or even you after some time, trying to understand the code. A better name would be value or text (even arr would be better, because it is not a pointer).
In readFile you have a loop in which you read a line and put it in curr->ptr and then create a new curr and link it to the previous curr.
This creates an extra empty curr at the end of the list which you don't need and so you free it later. Unfortunately, the next pointer of the previous node is still pointing at the empty node you just freed.
The easiest way to fix this without restructuring the loop a bit is to keep a record of the previous node, something like this:
struct Node* prev = NULL;
while (fgets(curr->ptr, NICE, fptr))/*if fgets returns NULL it means that we either reached EOF or error, both a reason to end the loop*/
{
curr->next = makeNode();
prev = curr;
curr = curr->next;
}
free(curr);
if (prev != NULL)
{
prev->next = NULL;
}
else
{
head = NULL; // For the empty file case. head == curr in this case
}
// The other clean up stuff
I am trying to read a PPM File and store the comments in a linked list so far I have created a structure of Node with value and struct pointer to next node. Also created an append function and also a print linked list function. But when I try to call the function in main it doesn't print anything.
struct Node{
char value;
struct Node *next;
};
void append(struct Node * headNode, int newElement){
struct Node *newNode = malloc(sizeof(struct Node)); //Dynamically Allocating Memory for New Node
struct Node *tailNode = headNode; //Creating A Tail Node to traverse the linked list
newNode->value = newElement; //Assigning the values of newNode to the given value
newNode->next = NULL; //Setting next value to be null since its the last node
if (headNode == NULL){ //Checking if headnode is empty
headNode = newNode; //Assigning headnode and tailnode to be newnode
tailNode = newNode;
}
while(tailNode->next != NULL){ //Traversing through the linked list
tailNode = tailNode->next;
}
tailNode->next = newNode; //Setting tailnode's next to be newnode
tailNode = newNode;
}
void printLinkedList(struct Node* headNode){
while(headNode != NULL){
printf("%d",headNode->value);
headNode = headNode->next;
}
}
struct Node* getComments(char *filename){
struct Node *headNode = malloc(sizeof(struct Node));
FILE *f = fopen(filename,"r");
int ch = getc(f);
while(ch == '#'){
while(ch != '\n'){
append(headNode,ch);
ch = getc(f);
}
}
return headNode;
}
Also My comments are a string but in printLinked List when I use "%s" it says argument is int even though i specified as char.
This is the main Function
void main(int argc, char * argv[]){
printLinkedList(getComments(argv[1]);
}
A PPM Files Starts Like This
P3
# 100 * 100 square
100 100
255
..
..
Here the line with # is a comment.
Any Comments welcome on code
The comment lines start with "#" but the first line of the sample file does not.
End of your loop while(ch == '#').
End of your getcomment().
End of your program.
I think your program has more issues. But for the described situation/input this is the explanation.
"I'm trying to implement a Linked List that will later make uses of a lexicographical sort function, but I keep getting an error concerning conflicting types in listnode.
I don't know what the cause of this issue is. Previously I had issues trying to malloc using sizeof and I found that the solution was declaring next as listnode* pointer. It solved that issue, but it still has conflicting types. When I try to compile I get this error message:
ls.c:18:3: error: conflicting types for 'listnode'
} listnode:
ls.c:12:14: note previous declaration of 'listnode' was here
typedef node listnode;
My code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
int strcmp(const char *str1, const char *str2);
//This chunk of code is dedicated to the formation and functions of Linked list
//which will be used to store and sort file names.
typedef struct node node;
typedef node listnode;
#define EMPTY NULL;
typedef struct listnode{
struct listnode* next;
char* string;
} listnode;
struct listnode* head;
//This function will print the entire list
void printlist(listnode* head){
struct listnode* current = head;
while(current != NULL){
printf("%s \n", current->string);
current = current->next;
}
}
//This function creates a new node
listnode* newNode(char* str, listnode* node){
listnode* new = (listnode*)malloc(sizeof(listnode*));
if(new == NULL){
printf("Error creating new listnode.\n");
exit(0);
}
new->string = str;
new->next = node;
return new;
}
//This function will append a new node onto the list
listnode* list_append(listnode* head, char* str){
if (head == NULL){
listnode* new = newNode(str, head);
head = new;
return head;
}
else{
listnode* current = head;
while(current-> next != NULL){
current = current->next;
}
listnode* new = newNode(str,NULL);
current -> next = new;
}
return head;
}
//This function earses the list freeing up space
void list_free(listnode* head){
listnode* current;
listnode* temp;
if(head != NULL){
current = head->next;
if(head !=NULL){
current = head -> next;
head ->next = NULL;
while(current != NULL){
temp = current -> next;
free(current);
current = temp;
}
}
}
free(head);
}
//This is the end of the linked list code
int main(int argc, char **argv){
char *current_dir = NULL;
DIR *direct_ptr = NULL;
struct dirent *dir_ptr = NULL;
unsigned int fileNum = 0;
int c;
listnode* head = NULL;
current_dir = getenv("PWD");
if(NULL == current_dir){
printf("\n Error: Couldn't grab current directory.\n");
return -1;
}
direct_ptr = opendir((const char*)current_dir);
if(NULL == direct_ptr){
printf("\n Error: couldn't open current directory\n");
return -1;
}
if(argc == 1){
for(fileNum=0; NULL != (dir_ptr = readdir(direct_ptr)); fileNum++){
if(dir_ptr->d_name[0] != '.'){
head = list_append(head, dir_ptr->d_name);
}
}
}
else{
if(strcmp(argv[1], "-a") || strcmp(argv[1], "[-a]")){
for(fileNum=0; NULL != (dir_ptr = readdir(direct_ptr)); fileNum++){
head = list_append(head, dir_ptr->d_name);
}
}
else{
printf("\n Unrecognized argument in command line.\n");
return -1;
}
}
return 0;
}
You do in fact have conflicting definitions for listnode. You first define the type here:
typedef struct node node;
typedef node listnode;
Then define it again here:
typedef struct listnode{
struct listnode* next;
char* string;
} listnode;
In one case it's an alias for struct node and in the other it's an alias for struct listnode.
Get rid of the first one as well as typedef struct node node;
You have two definitions of listnode:
typedef node listnode;
and
typedef struct listnode{
struct listnode* next;
char* string;
} listnode;
The first one is unnecessary, and won't work, because it uses node, which is defined as
typedef struct node node;
but you never defined struct node anywhere.
Using the delete_SLL function I want to delete the head of this singly linked list(head = 4). Although I get the correct output, the var struct Node* "temp" holding the value of the head isn't NULL. What is it about the variable "temp" that the free function not like? Is the node temp not Malloc-ed when setting it equal to the list head?
Source:Deleting a Node
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node{
int item;
struct Node* next;
};
struct List{
struct Node* head;
struct Node* tail;
};
int SLL_empty(struct List* lst){
return lst->head == NULL ;
}
//newLst work
struct List newLst(){
struct List lst;
lst.head = NULL;
lst.tail = NULL;
return lst;
}
//Inserts a node to the front of the list[WORKS]
void insert_SLL(struct List* lst, int x){
struct Node* nde = (struct Node*)malloc(sizeof(struct Node));
nde->next = lst->head;
nde->item = x;
if (SLL_empty(lst))
lst->tail=nde;
lst->head = nde;
}
//Deletes a given Node
void delete_SLL(struct List* lst, int x){
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));;
temp = lst->head;
struct Node* prev = NULL;`enter code here`
//If the head has the key
if (temp != NULL && temp->item == x){
lst->head = temp->next;
temp->next = NULL;
free(temp);
}
// stops once the key is found
while(temp != NULL && temp->item != x){
prev = temp;
temp= temp->next;
}
//If not in list
if (temp == NULL) return;
//If middle
if (temp != NULL && temp->item == x){
prev->next = temp->next;
temp->next = NULL;
}
//if at the end
if (temp != NULL && temp->item == lst->tail->item){
lst->tail= prev;
prev->next = NULL;
}
free(temp);
}
int SLL_pop(struct List *list){
struct Node* nde = list->head;
int item = nde->item;
list->head = nde->next;
free(nde);
if (SLL_empty(list))
list->tail = NULL;
return item;
}
int main(int argc, const char * argv[]) {
int i;
struct List list = newLst();
for (i = 0; i < 5; ++i)
insert_SLL(&list, i);
// printf("The length of the linkedLst is: %d\n",SLL_length(&list));
delete_SLL(&list, 4);
while ( list.head != NULL )
printf("Node: %d\n", SLL_pop(&list));
return 0;
}
The main purpose of free() is to ask the OS take the allocated memory back to the system. You might not be able to "see" that but if you try to access any element at the "temp" afterward, you should get an error.
While the "temp" in the program is only a variable. C doesn't require to, and can't change the given pointer to NULL due to pass-by-value sense. It's the programmer's work to remember that this pointer is no longer valid.
Or you can set it to NULL manually each time you free a pointer.
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
char word[20];
struct node * next;
}node;
int main(){
FILE *ifp;
char newword[20];
node * head;
ifp = fopen("para.txt","r");
head = (node * )malloc(sizeof(node));
while(fscanf(ifp,"%s",newword) != EOF){
head -> next = NULL;
head -> word = newword;
}
return 0;
}
I want to add the words which is read by the text file to a link list. I tried to do with this code but I couldn't. How can I fix this.
You only allocate one node (head) and then change its contents each iteration of the loop. To create a linked list, you need to allocate a new node for each word (each iteration of the loop). Something like this should do it:
int main(){
FILE *ifp;
char newword[20];
node * head = NULL;
node *last = NULL;
node *current;
ifp = fopen("para.txt","r");
if (ifp == NULL) {
fprintf(stderr, "Unable to open file para.txt\n");
return EXIT_FAILURE;
}
while(fscanf(ifp,"%19s",newword) != EOF){
current = malloc(sizeof(node));
strcpy(current -> word,newword);
if(last) {
last->next = current;
}
else {
head = current;
}
last = current;
}
return EXIT_SUCCESS;
}
Keep track of a head and tail, or just push at head. The following appends to end, efficiently.
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
struct node * next;
char word[1];
//or, char word[20];//fixed length word
}node;
node*
nodeNew(char* word) {
if(!word) return NULL;
//either dynamically allocate for strlen(word)
node* pnode = malloc( sizeof(node)+strlen(word) );
//or fixed len word
if( pnode ) {
pnode->next = NULL;
strcpy(pnode->word, word);
//or, strncpy(pnode->word, word, 20-1); //fixed length
}
return pnode;
}
int main()
{
FILE *ifp;
char newword[200]; //since using fscanf, need to avoid buffer overflow, should use fgets and strtok instead
node * head;
if( !(ifp = fopen("para.txt","r") ) { printf("error\n"); exit(0); }
head = NULL;
while(fscanf(ifp,"%s",newword) != EOF){
if( !head ) { tail = head = nodeNew(newword); }
else { tail->next = nodeNew(newword);
}
//head points to first element, head->next points to next element
//tail points to last element
return 0;
}