Storing Comments Of PPM File In Linked List - c

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.

Related

C linked list problem, segfault when printing the list to a file

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

Segmentation Fault In Linked List Append

I have been using linked list and I have used the following code for append function which i wrote in a new file and it works perfectly but when I copy it my main code it gives segmentation fault at while(current->next != null) . It does not give any warning while compiling so I don't know whats the issue here.
// Linked List Node for Reading Comments
struct Node{
char value;
struct Node *next;
};
void append(struct Node * headNode, char newElement){
struct Node *newNode = malloc(sizeof(struct Node)); //Dynamically Allocating Memory for New Node
struct Node *current = headNode; //Creating A 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
}
else {
while(current->next != NULL){ //Traversing through the linked list
current = current->next;
}
current->next = newNode; //Setting tailnode's next to be newnode
}
}
void printLinkedList(struct Node* headNode){
while(headNode != NULL){
fprintf(stderr,"%c",headNode->value);
headNode = headNode->next;
}
}
If anyone can comment on this please do.
Your code does not allow to add a node to an empty list. If you try and did not initialise your head pointer on the calling side, you may get such behavior.
For instance, in main you could have:
struct Node* head; // not initialised
append(head, 'a');
printLinkedList(head);
These are then the issues:
If head happens to be not NULL, then the else block will kick in and the current pointer will reference some unintended memory address.
append will not change the head variable of main. It will only modify a local variable that happens to have a similar name (headNode).
To correct, pass the address of head to the append function, and let append deal with this accordingly:
void append(struct Node ** headNode, char newElement) {
struct Node *newNode = malloc(sizeof(struct Node));
struct Node *current = *headNode;
newNode->value = newElement;
newNode->next = NULL;
if (*headNode == NULL) {
*headNode = newNode;
} else {
while(current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
}
Note the additional * wherever headNode occurs. In main:
struct Node* head;
append(&head, 'a');
printLinkedList(head);

Unnecessary Changes being made when appending to linked list

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.

Printing struct data from a singly-linked list

I'm trying to build a singly-linked list using a struct with 2 data types: char* and int, as well as next to point to other nodes of course.
I have two functions: addToList, and printList as well as the main method to run everything.
What my code is supposed to do is add a node after the head, and check to see if another node with the same data has already been added. If so, it does not add the new node, while incrementing the count data of the already-linked node.
Then, printList() prints the count data and the char* data of each node.
The first issue is that my char comparison doesn't seem to be working, since duplicate nodes are still added. Then, my printList function does not print the char* data correctly. Here's my code (I made sure to comment it so it's easy to follow along):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Struct for node. Has an extra data variable to keep track of which node is next
// in a singly-linked list.
typedef struct node {
char *str;
unsigned int count;
struct node *next;
} node;
// Creates a HEAD node with NULL data.
node *head = NULL;
// Adds a new node and populates the data.
struct node* addToList(struct node* Listptr, char* word){
struct node* new = malloc(sizeof(struct node));
new->str = malloc(sizeof(char) * 34);
strcpy(new->str, word);
new->count = 1;
new->next = Listptr;
// If the head is NULL, sets the new node as the head.
if(head == NULL){
head = new;
return new;
}
// Sets a node iterator "cur" to the first position.
node *cur = head;
// Sets a node iterator to be one place behind cur.
node *prev;
// Loops through the linked list, in order to count the previous words and determine
// if it is necessary to add another node.
// Otherwise, it sets cur to the next node, and prev to the node cur was just at.
while(cur != NULL){
if(cur->str == new->str){
cur->count++;
new = NULL;
return new;
} else{
prev = cur;
cur = cur->next;
}
}
// Checks to see if cur is NULL, if so, sets the previous node.next to the one we're adding.
if(cur == NULL){
prev->next = new;
return new;
}
}
// Prints out the count and word values of each node.
void printList(){
node* cur = head;
while(cur != NULL){
printf("%d %c\n", cur->count, cur->str);
cur = cur->next;
}
}
int main() {
node* Z = NULL;
char *a = "hello";
char *b = "world.";
char *c = "hello";
addToList(Z, a);
addToList(Z, b);
addToList(Z, c);
printList(Z);
return 0;
}
I expect to get:
2 hello
1 world
But in the console, I get:
1 l
1 (weird symbol)
1
Don't use == to compare strings rather use strcmp().
Change if (cur->str == new->str) to this:
if (strcmp(cur->str, new->str) == 0)
Read this to know more on string compare: How do I properly compare strings?

head updates on each insertion while converting text file to singly linked list in C

As the question specifies I want to convert a text file into linked list. When I read the string elements from an array it works fine but while doing the same from file creates the issue of updated head. The following is what I've tried...
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
//creating structure
typedef struct node {
char *word;
struct node *next;
}node;
//function for creating a node
node *createnode(char *wrd){
node *temp1;
temp1 = (node*)malloc(sizeof(node));
temp1->word = wrd;
temp1->next = NULL;
return temp1;
}
//function for creating and adding new node to linked list
node *creat(node *head, char *wrd){
node *temp, *p;
temp = createnode(wrd);
if(head == NULL){
head = temp;
}else{
p = head;
while(p->next != NULL){
p = p->next;
}
p->next = temp;
printf("p->word from creat method: %s ADDR: %p HEAD: %s \n", p->word,
p->next,head->word);
}
return head;
}
//traverse the list and display each node
node *show(node *head){
node *p;
p=head;
while(p != NULL){
printf("from show method: %s", p->word);
p = p->next;
printf("\n");
}
printf("\n");
}
int main()
{
node *head = NULL;
/* Character array to read the content of file */
char sWord[20];
/* Pointer to the file */
FILE *fp;
/* Opening a file in r mode*/
fp= fopen ("hw10data.txt", "r");
while( fscanf(fp, "%s", sWord) != EOF )
{
head = creat(head, sWord); //create list
}
fclose(fp);
show(head);
return 0;
}
I don't know why the head is updating on each insert. Any help will be appreciated.
It's not the head of the list which is changing; it's just that you read in the values into a local array sWord, which you then pass to the creat and createnode-functions. Therein, you simply assign a pointer, but you do not copy the content of sWord; Hence, all node contents will point to the same memory address, i.e. to sWord; and when you read in new values, all node contents will point to that new value. So it just seems as if the "head" has changed. Actually all nodes will show the same content...
To overcome this, write the following in createnode:
// temp1->word = wrd;
temp1->word = strdup(wrd);
Or, if strdup is not available:
temp1->word = malloc(strlen(wrd)+1);
strcpy(temp1->word,wrd);

Resources