Adding a char array to a linked list - c

#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;
}

Related

I need to create a single linked list by taking the input from a file i.e., .txt file and print the linked list

The .txt file consists of id, name, gender, occupation, age. Now I need to read from the file and create a linked list and print the list. The code should be in C language.
below is the code which I am trying, but only a string/ word is printing.
Do I need to use fscanf function in while loop instead of fgets function? I need to print all the contents of text file, which has both integer and character type in it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list {
char *string;
struct list *next;
};
typedef struct list LIST;
int main(void) {
FILE *fp;
char line[128];
LIST *current, *head;
head = current = NULL;
fp = fopen("hello.txt", "r");
while(fgets(line, sizeof(line), fp)){
LIST *node = malloc(sizeof(LIST));
node->string = strdup(line);
node->next =NULL;
if(head == NULL){
current = head = node;
} else {
printf("%s", current->string);
current = current->next = node;
}
}
fclose(fp);
for(current = head; current ; current=current->next){
// printf("%s", current->string);
}
return 0;
}
This is wrong since it will never print the last line you read:
if(head == NULL){
current = head = node;
} else {
printf("%s", current->string); // prints the previous line
current = current->next = node;
}
If you want all lines to be printed, do the printing after you've assigned current:
if(head == NULL){
current = head = node;
} else {
current = current->next = node;
}
printf("%s", current->string);
Or before assigning current, using node:
printf("%s", node->string);
if(head == NULL){
current = head = node;
} else {
current = current->next = node;
}
I would also suggest organizing the code and make use of functions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list LIST;
struct list {
char *string;
LIST *next; // I moved the typedef above the struct list definition
};
// A function to read and populate a list from a stream:
LIST *list_read(FILE *fp) {
char line[128];
LIST *head, **tail = &head;
while (fgets(line, sizeof line, fp)) {
LIST *node = malloc(sizeof *node);
node->string = strdup(line);
// simplification of your `if(head == NULL)` code. No `if`s needed:
*tail = node;
tail = &node->next;
}
*tail = NULL;
return head;
}
// A function to free the resources allocated by a list
void list_free(LIST *head) {
for (LIST *current = head, *next; current; current = next) {
next = current->next;
free(current->string);
free(current);
}
}
// A function to print a list
void list_print(LIST *head) {
for (LIST *current = head; current; current = current->next) {
printf("%s", current->string);
}
}
int main(void) {
FILE *fp = fopen("hello.txt", "r");
if (fp == NULL) return 1;
LIST *head = list_read(fp);
fclose(fp);
list_print(head);
list_free(head);
}
If you want the list to be sorted in alphabetical order, you could add a function that inserts a node in the correct position in the list:
void list_insert(LIST **lp, char *str) {
LIST *node = malloc(sizeof *node);
node->string = strdup(str);
// find insertion point for the list to be in alphabetical order
while(*lp && strcmp(str, (*lp)->string) > 0) {
lp = &(*lp)->next;
}
// link the new node:
node->next = *lp;
*lp = node;
}
and change list_read accordingly:
LIST *list_read(FILE *fp) {
char line[128];
LIST *head = NULL;
while (fgets(line, sizeof line, fp)) {
list_insert(&head, line);
}
return head;
}

Printing elements in a linked list based on a user inputted prefix in C

I am currently writing an auto-complete program in C and am in need of some help (yes this is a hw assignment). Basically what the program does is asks the user to input a folder name and then adds all of the directories in that folder into a linked list. The user is then asked to input a prefix and the program will print all of the directories that begin with said prefix.
My question is how do I implement a function to print out all directories with the prefix?
(i have already created the linked list I just need to print out the directories based on the prefix)
sample output:
Enter a folder name: /usr/bin
> zi
Files starting with zi in /usr/bin:
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit
> zipc
Files starting with zipc in /usr/bin:
zipcloak
code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <ctype.h>
const int MAX = 125;
//node struct
typedef struct Node{
//fn length
char fn[256];
struct Node *next;
}Node;
//list struct
typedef struct List {
struct Node *head;
} List;
//constants and functions
char *getNext(DIR *dp);
List *create();
void addElement(List *list, char *v);
void printList(List *list);
void printFIles(List *fn, char prefix);
int main(void) {
// insert code here...
//variables
char dirName[MAX];
char prefix[MAX];
int i = 0;
List *fileNames[26];
DIR *dp;
char *fn;
struct dirent *ep;
char dir[MAX];
//enter a directory
printf("Enter a folder name: ");
scanf("%s", dirName);
dp = opendir(dirName);
for (i =0; i<26; i++) {
fileNames[i] = create();
}
if (dp != NULL)
{
while ((ep = readdir (dp)) != NULL) {
strcpy(dir, ep->d_name); /* adds to list */
addElement(fileNames, dir);
}
(void) closedir (dp); /*close the directory */
}
else{
perror ("Couldn't open the directory");
}
printf(">");
while (scanf("%s", prefix)) {
printf("Files starting with %s in %s \n", prefix, dirName);
}
return 0;
}
void addElement(List *list, char *v){
//adds a node to the top of list
Node *head = list->head;
//if the head isnt null push it to the front of the list
if (head != NULL) {
Node *newnode = malloc(sizeof(Node));
strcpy(newnode->fn, v);
//set the next node equal to the head of the list
newnode->next = list->head;
list->head = newnode;
return;
}
Node *current = head;
Node *next = current->next;
if (next == NULL) {
current = next;
next = next->next;
}
if(next !=NULL){
//push to end
Node *current = list->head;
Node *node = malloc(sizeof(Node));
strcpy(node->fn, v);
node ->next = NULL;
while (current->next == NULL) {
current = current->next;
}
if (current) {
current->next =node;
} else{
list->head = node;
}
return;
}
Node *node = malloc(sizeof(Node));
strcpy(node->fn, v);
current ->next = node;
node -> next = next;
}
void printList(List *list) {
Node *current = list->head;
printf("[");
//iterate
while (current != NULL) {
printf("%s", current->fn);
if (current->next) {
printf(",");
}
current = current->next;
}
printf("]");
}
void printFIles(List *fn, char prefix){
// Node *node = list->head;
//
// while (node && ) {
// <#statements#>
}
List *create(){
//allocate memory for the lsit
List *list = malloc(sizeof(List));
list->head = NULL; /*head of list is now null*/
return list;
}

linked list insertion at end when header node is not null

I'm having a problem with inserting a node at the end of a linked list. It's not being executed when the start node is not null and I don't understand the problem. Please help me out here. The function is called second time but is not going to the else block.
typedef struct token_Info
{
int linenumber;
char* token;
char value[200];
struct token_Info* next;
} token_Info;
token_Info *tokenlist;
token_Info* insert_at_end( token_Info *list,char *name)
{
printf("token identified \t");
token_Info *new_node;
token_Info *temp,*start;
start = list ;
char *tempname ;
tempname = name;
new_node= malloc(sizeof(token_Info));
new_node->token = malloc(sizeof(strlen(tempname)+1));
strcpy(new_node->token,tempname);
new_node->next= NULL;
// printf("%d",strlen(tempname));
if(new_node == NULL){
printf("nFailed to Allocate Memory");
}
if(start==NULL)
{
start=new_node;
return start;
}
else
{
printf("anvesh");
temp = start;
while(temp->next != NULL)
{
temp = temp ->next;
}
temp->next = new_node;
return temp;
}
}
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
tokenlist = insert_at_end(tokenlist,"TK_BEGIN1");
UPDATE
I found two bugs, the first was the head of the list was not being returned when appending the list. The other in the memory allocation for the token string which incorrectly used sizeof.
I repositioned the test of the malloc() return value, and added a second one. I removed several unnecessary temporary variables that were cluttering the code. I added two functions, show_list() and free_list(). Finally, remember that the value string field is still uninitialised.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct token_Info
{
int linenumber;
char* token;
char value[200];
struct token_Info* next;
} token_Info;
token_Info* insert_at_end( token_Info *list, char *name)
{
token_Info *new_node, *temp;
new_node= malloc(sizeof(token_Info));
if(new_node == NULL){ // repositioned
printf("\nFailed to allocate node memory\n");
exit(1); // added
}
new_node->token = malloc(strlen(name)+1); // removed sizeof
if(new_node->token == NULL){ // added
printf("\nFailed to allocate token memory\n");
exit(1);
}
strcpy(new_node->token, name);
new_node->next= NULL;
if(list==NULL)
return new_node;
// append
temp = list;
while(temp->next != NULL)
temp = temp->next;
temp->next = new_node;
return list; // original head
}
void free_list( token_Info *list)
{
token_Info *temp;
while (list) {
temp = list->next;
free(list->token);
free(list);
list = temp;
}
}
void show_list( token_Info *list)
{
printf ("\nCurrent list:\n");
while (list) {
printf ("%s\n", list->token);
list = list->next;
}
}
int main(int argc, char **argv)
{
token_Info *tokenlist = NULL;
tokenlist = insert_at_end(tokenlist, "TK_BEGIN");
show_list(tokenlist);
tokenlist = insert_at_end(tokenlist, "TK_SECOND");
show_list(tokenlist);
tokenlist = insert_at_end(tokenlist, "TK_FINAL");
show_list(tokenlist);
free_list(tokenlist);
return 0;
}
Program output:
Current list:
TK_BEGIN
Current list:
TK_BEGIN
TK_SECOND
Current list:
TK_BEGIN
TK_SECOND
TK_FINAL
The question could also be whether you want tokenlist to be a running end of the list, or remain at the start.
As of right now, your first call:
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
has tokenlist being the only node in the list.
The second call tokenlist = insert_at_end(tokenlist,"TK_BEGIN1"); returns 'temp' which happens to also be the 'TK_BEGIN' node, ( ie, the first node )
If you want the return value to be the last element, you would return new_node instead of temp. If you want to retain the start, you would return start;
All that said:
The calls to it are not part of any function,
I just ran it with the calls in main and got this output:
int main(void){
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
tokenlist = insert_at_end(tokenlist,"TK_BEGIN1");
return 0;
}
$> ./a.out
token identified token identified anvesh

Creating a Linked List from File Input

Basically what I'm trying to do is take in a txt file and create a linked list off of it. The txt file contains either a "i" or "d" followed by a space and then a number.
Example of txt file:
i 10
i 12
d 10
i 5
I am trying to take in the input file and based off the input create a linked list. If the letter is an "i", I am trying to add it to the linked list. If it is a "d", I am trying to delete it from the list.
This is what I have so far. I have taken in the file and read it line by line, separating the letters from the number and stores them in char pointers. I tried earlier to create a linked list but it did not work out properly. Could someone please point me in the right direction on where and how I should implement the linked list.
#include<stdio.h>
#include<stdlib.h>
#include <ctype.h>
#include <string.h>
struct node { // creation of node structure
int data; // data inside node
struct node *next; // address to the next node int the list
};
void Insert (struct node *root, int x){ // this method will insert a node into the linked list
struct node *newnode;
newnode = (struct node*)malloc(sizeof(struct node));
newnode->data=x;
newnode->next = NULL; // this creates the node and stores the input into the data variable
if (root == NULL){ // if the root node is empty, point the root node to this pointer.
root = newnode;
}
else {
newnode->next=root; // if the link list is not empty, set whatever head point was pointing to previously equal to newnode-> next
root=newnode; // now make the head node point to the newnode
}
}
void printlist(struct node *root)
{
struct node *temp;
temp=root;
while(temp!=NULL)
{
printf("%d",temp->data);
temp=temp->next;
}
printf("\n");
}
int main (int argc, char *argv[]){
// Need to create a Root Node
struct node *root;
if (argc != 2) { // if the input is more than one, error
return EXIT_FAILURE;
}
// argv[1] will contain the file name input.
FILE *file = fopen(argv[1], "r");
// we need to make sure the file is not empty, error case.
if (file == NULL){
printf("error\n");
exit(0);
}
// if the file is empty, print an empty line. ******** MAKE SURE TO COME BACK TO THIS ************
char linestring[BUFSIZ]; // this will hold our file input after we read/scan it.
// now we need to read the file
while (fgets(linestring, sizeof(linestring), file)) // reads the entire file until it hits Null
{
// need to split up the lines so that we separate letters from integars.
// look for \t or " " and use strtok.
char* letter = strtok(linestring, " \t\n"); // stores the letter from the line
char* number = strtok(NULL, " \t\n"); // stores the numbers from the line
// now we need to now check the letter and see whether it is an "i" or a "d"
// use sting compare (it returns a 0 if the letter is equal to what we are checking)
if (strcmp(letter, "i") == 0){ // This checks the letter and if it is "i", we are going to be inserting a node
// need to create the new node to be inserted and assign the number value to it.
int x;
x = atoi(number); // converts the string input into a integar
Insert(root, x); // method which inserts the input onto the linked list.
}
if (strcmp(letter, "d") == 0){ // This checks the letter and if it is "d", we are going to be deleting a node
}
}
printlist(root);
fclose(file);
}
I assume that values does not repeated.
struct node
{ // creation of node structure
int data; // data inside node
struct node *next; // address to the next node int the list
};
//insertion in last
int insertNode(node **root, node *data)
{
if(!data) return 0;
//check if root available. if not data will be the root
if(!*root)
{
*root = data;
data->next = NULL;
return 1;
}
node *temp = *root;
while(temp->next)
{
temp = temp->next;
}
temp->next = data;
return 1;
}
//deletion. if multiple ocures first will delete
int deleteNode(node **root, int num)
{
if(!root) return 0;
node *temp = *root;
if(temp->data == num)
{
if(temp->next)
{
*root = temp->next;
}
free(temp);
return 1;
}
while(temp->next)
{
node* deleteThis = temp->next;
if((temp->next->next) && temp->next->data == num)
{
//delete next
temp->next = temp->next->next;
free(deleteThis);
return 1;
}
else if(temp->next->data == num)
{
//the last node
temp->next = NULL;
free(deleteThis);
return 1;
}
temp = temp->next;
}
return 0;
}
int main(int argc, char *argv[]){
//make root node
node* root = NULL;
// if the input is more than one, error
if (argc != 2) return EXIT_FAILURE;
// argv[1] will contain the file name input.
FILE *file = fopen(argv[1], "r");
// we need to make sure the file is not empty, error case.
if (file == NULL)
{
printf("error\n");
exit(0);
}
// if the file is empty, print an empty line.
/*int size = ftell(file);
if (size == 0){
printf("\n");
}
printf("%d",size);*/
char linestring[BUFSIZ]; // this will hold our file input after we read/scan it.
// now we need to read the file
while (fgets(linestring, sizeof(linestring), file)) // reads the entire file until it hits Null
{
// printf("%s", linestring); // stores each line into linestring.
// need to split up the lines so that we separate letters from integars.
// look for \t or " " and use strtok.
char* letter = strtok(linestring, " \t\n"); // stores the letter from the line
char* number = strtok(NULL, " \t\n"); // stores the numbers from the line
//changed from here
int n =atoi(number);//convert string to int
if(*letter == 'i')
{
//creates node to be inserted
node *data = NULL;
data = (struct node*)malloc(sizeof(node));
data->data = n;
data->next = NULL;
if(!insertNode(&root,data)) //if insertion gose wrong 0 will return
printf("insert %s was faild\n", number);
}
else
{
if(!deleteNode(&root,n))
printf("Couldnt Delete (%s not in the list)\n )", number);
}
}
}
**FULL WORKING CODE IN C++ FOR REFERENCE**
#include<bits/stdc++.h>
#include<fstream>
using namespace std;
struct node{
int data;
struct node* next;
};
typedef struct node node;
typedef struct node* nodeptr;
nodeptr Create(nodeptr head,nodeptr &current,int x){
nodeptr temp = (nodeptr)malloc(sizeof(node));
temp->next=NULL;
temp->data=x;
if(current==NULL){
current=temp;
head=temp;
}
else{
current->next=temp;
current=temp;
}
return head;
}
nodeptr Delete(nodeptr head, int x){
nodeptr temp = head;
nodeptr temp1;
while(temp->data!=x){
temp1=temp;
temp=temp->next;
}
temp1->next=temp->next;
free(temp);
temp=NULL;
return head;
}
void PrintC(nodeptr head){
nodeptr temp = head;
while(temp!=NULL){
cout<<temp->data<<" ";
temp=temp->next;
}
}
int main(){
nodeptr current = NULL;
nodeptr head = current;
string str;
ofstream myfile;
myfile.open("file.txt",ios::out);
myfile << "i 1 i 2 i 3 i 4 i 5 d 2 d 3";
myfile.close();
ifstream myfile1("file.txt");
getline(myfile1,str);
myfile1.close();
int i=0;
while(str[i]!='\0'){
if(str[i]!=' '){
if(str[i]=='i'){
int n = str[i+2]-48;
head=Create(head,current,n);
i=i+2;
}
else if(str[i]=='d'){
int n = str[i+2]-48;
head = Delete(head,n);
i=i+2;
}
}
i++;
}
cout<<endl;
PrintC(head);
return 0;
}

anagram detecting using linked lists in c

I'm trying to write a code that'll check 2 words if they are anagrams,using linked lists.To do that,I guess it should receive 2 words from the user and pass every letter they contain to linked list's nodes,and compare the nodes if they have the same letter,if so,remove the same letter from the second word.When the process is done,if the second list is empty,then they are anagrams.Even if 1 letter is not matching,it should return 0,but I don't know how to determine the length of these words,here is what I wrote so far
#include <stdio.h>
#include <stdlib.h>
struct node
{
struct node *prev;
struct node *next;
char data;
};
typedef struct node *NODE,NOD;
NODE last(NODE list)
{
if(list!=NULL)
while(list->next!=NULL)
list=list->next;
NODE lst;
lst=list;
return lst;
}
void insert( char letter, NODE list)
{
NODE nod;
nod=(NODE)malloc(sizeof(NOD));
nod->next=NULL;
nod->prev=NULL;
nod->data=letter;
if(list==NULL)
{
list=nod;
}
else
{
nod->prev=last(list);
last(list)->next=nod;
}
}
Just check that each word has the same number of each letter in it.
int anagrams(const char *a, const char *b) {
int counts[256] = {0};
while (*a) counts[*a++]++;
while (*b) counts[*b++]--;
for (int i = 0; i < 256; i++) {
if (counts[i]) return 0;
}
return 1;
}
Why use linked lists for such an easy problem?
O(N) solution:
Calculate frequencies of every letter for each word and then compare these 2 histograms. If they're equal, then one word can be obtained from another.
If you want to use your linked-list-based solution, then, the length of the word is, indeed:
Length of each input word (they must have the same length) - it can be calculated with a single traversal from the linked list head to the tail.
Amount of removed symbols
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node {
char data;
struct node *prev;
struct node *next;
} NODE;
NODE *newNode(char ch){
NODE *p = malloc(sizeof(NODE));
if(p){
p->data = ch;
p->prev = p->next = NULL;
}
return p;
}
void insert(NODE **list, NODE *node){
if(*list == NULL){
*list = node;
return ;
}
NODE *curr = *list;
while(curr){
if(curr->data >= node->data){//insert sort
if(curr->prev == NULL)
*list = node;
else
curr->prev->next = node;
node->prev = curr->prev;
curr->prev = node;
node->next = curr;
break;
}
if(curr->next == NULL){
curr->next = node;
node->prev = curr;
break;
} else
curr = curr->next;
}
}
NODE *input_word(){
NODE *word=NULL;
int ch;
while(EOF!=(ch=getchar()) && ch != '\n'){
insert(&word, newNode(ch));
}
return word;
}
bool isAnagram(NODE *word1, NODE *word2){
while(word1 && word2){
if(word1->data != word2-> data)
return false;
word1 = word1->next;
word2 = word2->next;
}
return word1 == NULL && word2 == NULL;
}
int main(){
NODE *word1, *word2;
printf("input word : ");
word1 = input_word();
printf("input other word : ");
word2 = input_word();
if(isAnagram(word1, word2))
printf("YES\n");
else
printf("NO\n");
//drop(word1);drop(word2);
return 0;
}

Resources