I am trying to write a program that counts how many times a word is used in a text document. To do this I created a function called wordList that creates a linked list with a node for each word. Unfortunately, whenever I try to read a word from the linked list with printf there is a segmentation fault. I believe this is because the linked list is not actually copying any of the words. I am wondering how I can resolve this issue. At the moment I do not know how to proceed. Thanks:)
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
struct Node {
int timesUsed;
char* word;
struct Node* next;
};
struct Node* wordList(FILE *fp, struct Node* head);
struct Node* createNode(struct Node* head, char* word);
char* title(char* file);//creates file name based on command line input
int main(int argc, char** argv){
//Access file information---------------------------------------------
FILE *fp;
char* fileName = title(argv[1]);
fp = fopen(fileName, "r");
//Define Head node--------------------------------------------------------
struct Node* head = (struct Node*)malloc(sizeof(struct Node));
if (head == NULL){
printf("there is not enough memory on your device to continue\n");
}
//Access words--------------------------------------------------------
head = wordList(fp, head);
printf("%s\n",head->word);
free(head);
free(fileName);
return 0;
}
//Function that is causing problems==================================
struct Node* wordList(FILE *fp, struct Node* head){
char c;
char wordHolder[1240];//characters
int j = 0;
int count = 0;
do{
c = getc(fp);
printf("%c\n",c);
if(isalpha(c) || isdigit(c) || c == '\''){
wordHolder[j] = c;
j++;
}
else{
if(count){
char* tempWord = strdup(wordHolder);
head->word = tempWord;
head->timesUsed = 1;
head->next = NULL;
count = 1;
j = 0;
for(i = 0; i< strlen(wordHolder); i++){
wordHolder[i] = '\0';
}
}
else{
head = createNode(head, wordHolder);
j = 0;
for(i = 0; i< strlen(wordHolder); i++){
wordHolder[i] = '\0';
}
}
}
}
while(c != EOF);
return head;
}
//Creates a new node at end of list=====================================
struct Node* createNode(struct Node* head, char* word){
struct Node* temp = head;
while(temp != NULL){
temp = temp->next;
}
temp = (struct Node*)malloc(sizeof(struct Node));
temp->timesUsed = 1;
char* tempWord = strdup(word);
temp->word = tempWord;
temp->next = NULL;
return head;
}
//Creates fileName======================================
char* title(char* file){
char nameOfFile[500];
strcpy(nameOfFile, file);
strcat(nameOfFile, ".txt");
char* temp;
temp = strdup(nameOfFile);
if(temp == NULL){
printf("Your computer has litte memory.\n");
}
return temp;
}
Related
Basically for my assignment I need to implement code to do Huffman coding. For that I need to take input as a string and then create a list of characters and their frequencies. I need to create a new node when there is a new character. I have tried doing it in C with no result. When I try to print my linked list I simply cannot get any output. I believe I have failed in creating the list from the start.
My C code is below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
struct node {
char character;
int frequency;
struct node *next;
}head;
struct node *insert(int frequency, char character) {
struct node *newNode = malloc(sizeof(struct node));
newNode->character = frequency;
newNode->character = character;
return newNode;
}
void create_freq_list(struct node *initial, int str_size, char str[]) {
int i;
struct node *temp;
bool has_node;
for (i = 0; i < str_size; i++) {
temp = initial;
has_node = false;
while (temp->next != NULL) {
if (temp->character == str[i]) {
has_node = true;
temp->frequency++;
}
temp = temp->next;
}
if (has_node == false) {
while (temp->next != NULL) {
temp = temp->next;
if (temp->next == NULL) {
temp->next = insert(0, str[i]);
}
}
}
}
}
int main() {
struct node *temp;
char str[100];
gets_s(str, 100);
create_freq_list(&head, 100, str);
temp = &head;
while (temp->next != NULL) {
printf("'%c' : %d", temp->character, temp->frequency);
temp = temp->next;
}
getch();
exit(0);
}
There are multiple issues in your code:
Your handling of the head node is incorrect: head should be defined as a node * and you should pass its address to create_freq_list().
There is a typo in the insert() function: newNode->character = frequency;
You should not iterate on characters of the string beyond the null terminator.
The output loop is incorrect: it should iterate while (head), not while (head->next). As coded, the initial node is output but meaningless and the last node is ignored.
Here is a modified version:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char character;
int frequency;
struct node *next;
};
struct node *insert(int frequency, char character) {
struct node *newNode = malloc(sizeof(struct node));
if (newNode != NULL) {
newNode->frequency = frequency;
newNode->character = character;
}
return newNode;
}
void create_freq_list(struct node **headp, const char str[]) {
for (int i = 0; str[i]; i++) {
struct node **tailp = *headp;
struct node *temp;
while ((temp = *tailp) != NULL) {
if (temp->character == str[i]) {
temp->frequency++;
break;
}
tailp = &temp->next;
}
if (temp == NULL) {
*tailp = insert(1, str[i]);
}
}
}
int main() {
struct node *head = NULL;
char str[100];
gets_s(str, 100);
create_freq_list(&head, str);
for (struct node *temp = head; temp != NULL; temp = temp->next) {
printf("'%c': %d\n", temp->character, temp->frequency);
}
getch();
return 0;
}
Note that it is much simpler to use an array with 256 elements to compute the character frequencies.
May I propose a variant, using macros of the excellent <sys/queue.h>
This is not a standard include, but every well packaged system should have it.
Well, it's probably less pedagogical than coding linked-list by hands, but it's more secure ;-)
Have a look at man queue (or man LIST_INIT) to see features.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
typedef LIST_HEAD(listhead, entry) nodes_t;
typedef struct entry {
char character;
int frequency;
LIST_ENTRY(entry) entries;
} node_t;
void insert(nodes_t *list, char character) {
node_t *newNode = malloc(sizeof(node_t));
if (newNode != NULL) {
newNode->frequency = 1;
newNode->character = character;
LIST_INSERT_HEAD(list, newNode, entries);
}
}
node_t *get_node(nodes_t *list, char character) {
node_t *n;
LIST_FOREACH(n, list, entries)
if (n->character == character)
return n;
return NULL;
}
void create_freq_list(nodes_t *list, const char str[]) {
node_t *n;
for (int i = 0; str[i]; i++) {
n = get_node(list, str[i]);
if (n == NULL)
insert(list, str[i]);
else
n->frequency++;
}
}
void print_list(nodes_t *list) {
node_t *n;
LIST_FOREACH(n, list, entries)
printf("'%c': %d\n", n->character, n->frequency);
}
int main(int argc, char* argv[]) {
nodes_t list;
if (argc != 2) {
fprintf(stderr, "Usage: %s <string>\n", argv[0]);
return -1;
}
LIST_INIT(&list);
create_freq_list(&list, argv[1]);
print_list(&list);
return 0;
}
I'm having trouble reading in values to a linked list using fscanf in a loop.
The program ultimately compiles and runs, but the print function is not producing any output which leads me to believe that my linked list is not actually being created in my read function.
I set up a few error checking printf statements and discovered that my student *head value is NULL when it is returned back to main and then sent to the print function.
My functions:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Student{
char* first;
char* last;
int i;
int j;
struct Student* next;
}student;
int main(int argc, char* argv[])
{
student *start = NULL;
char *studentInput = argv[1];
start = buildStudentList(studentInput,start);
printStudents(start);
free_students(start);
return 0;
}
student* buildList(char* studentsFile, student* head)
{
student *current = head;
char *f = malloc(sizeof(char) * 25);
char *l = malloc(sizeof(char) * 25);
int prior,level = 0;
FILE *in = fopen(studentsFile, "r");
if(in == NULL)
{
printf("\nThe input file failed to open\n");
return NULL;
}
else
{
while(!feof(in))
{
fscanf(in, "%s %s %d %d",f,l,&prior,&level);
student *new = (student*)malloc(sizeof(student));
new->first = (char*)malloc(sizeof(char) * 25);
new->last = (char*)malloc(sizeof(char) * 25);
current = new;
strcpy(current->first,f);
strcpy(current->last,l);
current->i = prior;
current->j = level;
current->next = NULL;
current = current->next;
}
free(first);
free(last);
fclose(in);
return head;
}
}
void print(student* head)
{
if(head == NULL)
{
printf("head is null");
return;
}
student *current = head;
while(current->next != NULL)
{
printf("\n\nFirst Name: %s\nLast Name: %s\nPriority: %d\nReading Level: %d\n\n", current->first, current->last, current->i, current->j);
current = current->next;
printf("makes to loop");
}
}
void free_students(student *head)
{
if(head == NULL)
{
return;
}
student *current = head;
while(current->next != NULL)
{
student *temp = current;
current = current->next;
free(temp->first);
free(temp->last);
free(temp);
}
free(current->first);
free(current->last);
free(current);
}
At this point the output is "head is null".
I'm currently creating a linked list of strings that user enters. As of right now I have my linked list working (I just have to free the memory). However, I'm trying to detect for commas in the user input. If there is a comma make the linked list print out a new line, and just ignore the commas.
Any advice?
For example:
Enter a string:
hello,world,how,are,you
The output is currently:
hello,world,how,are,you
The output should be:
hello
world
how
are
you
Here's my current code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
struct Word
{
char* data;
struct Word* next;
};
struct Word* ptr = NULL;
void insert(char c)
{
struct Word* temp = (struct Word*)malloc(sizeof(struct Word));
temp->data = c;
temp->next = NULL;
if (ptr) {
struct Word* temp1 = ptr;
while(temp1->next != NULL) {
temp1 = temp1->next;
}
temp1->next = temp;
} else {
ptr = temp;
}
}
void print() {
struct Word *temp;
temp = ptr;
while(temp != NULL) {
printf("%c", temp->data);
temp = temp->next;
}
printf("\n");
}
int main(int argc, char *argv[])
{
int c;
printf("enter a string\n");
while (((c=getchar())!=EOF) && c!='\n') {
insert((char)c);
}
print(); /*print the list*/
return 0;
}
To print every word in the new line you just have to modify your print statement to check for , character in the linked list.
void print() {
struct Word *temp;
temp = ptr;
char c;
while(temp != NULL) {
if (temp->data == ',') {
printf("\n");
temp = temp->next;
} else {
printf("%c", temp->data);
temp = temp->next;
}
}
printf("\n");
}
This will check if there is a , in the linked list and print a \n to print newline character and move to the next node.
Also you should free your linked list after the program is complete to avoid memory leaks.
void freeData(struct Word* head)
{
struct Word* tmp;
while (head != NULL)
{
tmp = head;
head = head->next;
free(tmp);
}
}
Code link
Just try it out.
The program runs fine and displays the data I want but then crashes. I don't think it is a memory leak from the linked list because I've tried many ways to free it and none have worked.
#include "Buildings.h"
void displayBuilding(struct node *x){
printf("Building Name: %s\n\tFloors: %d\n\tValue: %d\n\n", x->payload.name, x->payload.floors, x->payload.value);
if(x->last!=1){
displayBuilding(x->next);
}
}
void insert(struct node *x, char str[50]){
srand(t);
int f = (rand() % 6)+1;
int v = ((rand() % 20)+1)*f;
//printf("Floors: %d and Value: %d\n", f, v);
strcpy(x->payload.name, str);
x->payload.floors = f;
x->payload.value = v;
srand(time(NULL));
t+=f+v*(rand()%1000);
}
FILE* openData(FILE *f){
f = fopen("Buildings-Data.txt", "r");
if(f==NULL){
printf("No File!");
return 0;
}
return f;
}
void freeList(struct node* head)
{
struct node* tmp;
while (head != NULL)
{
tmp = head;
head = head->next;
free(tmp);
}
}
int main(){
FILE *f1;
struct node *head;
struct node *curr;
head = malloc(sizeof(struct node));
curr = malloc(sizeof(struct node));
curr = head;
int i;
for(i=0;i<9;i++){
curr->next = malloc(sizeof(struct node));
curr = curr->next;
}
f1 = openData(f1);
curr = head;
int readNum;
char trash;
fscanf(f1, "%d", &readNum);
fscanf(f1, "%c", &trash);
for(i=0;i<readNum;i++){
char str[50];
fscanf(f1, "%s",str);
insert(curr, str);
curr->last = 0;
if(readNum-i==1){
curr->last = 1;
}else{
curr = curr->next;
}
}
fscanf(f1, "%c", &trash);
fclose(f1);
curr = head;
printf("\n");
displayBuilding(curr);
curr = head;
freeList(head);
return 0;
}
My header file:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
struct building{
char name[50];
int floors;
int value;
};
typedef struct building place;
struct node{
place payload;
struct node *next;
int last;
};
int t = 500;
The problem is that when you create the linked list, you never set next to NULL in the last node of the list. You need to do that after the loop:
for(i=0;i<9;i++){
curr->next = malloc(sizeof(struct node));
curr = curr->next;
}
curr->next = NULL;
Because of this, the while (head != NULL) loop in freeList() never stops, and eventually tries to free the uninitialized pointer in the last node of the list.
I am trying to sort a linked list in alphabetical order using bubble sort, but I am getting a segfault when I run the program. I can print off the names before sorting, but when I sort them and try to display them, it doesn't work.
Here is the code that I have and the output I want is to just display the names in order.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAX_STR_LEN 25
typedef struct Data_ {
char *name;
struct Data_ *next;
} Data;
Data* bubble_sort(Data *list);
Data* read_from_file(const char *file, const int size);
void display(Data *list);
void push(Data **head, char *name);
int main(int argc, char **argv) {
if(argc != 2){
printf("Not enough parameters!");
exit(0);
}
Data *head = NULL;
int size = 10;
head = read_from_file(argv[1], size);
printf("\nBefore sort");
display(head);
printf("\nBubble Sort\n");
head = bubble_sort(head);
display(head);
}
Data* bubble_sort(Data *head) {
int count = 0, i;
Data *start = head;
Data *curr = NULL;
Data *trail = NULL;
Data *temp = NULL;
//grab the count
while(start != NULL) {
count++;
start = start->next;
}
for( i = 0; i < count; ++i) {
curr = trail = head; //set curr and trail at the start node
while(curr->next != NULL){
if(strcmp(curr->name, curr->next->name) > 0) {
temp = curr->next;
curr->next = curr->next->next;
temp->next = curr;
if(curr==head)
head = trail = temp;
else
trail->next = temp;
curr = temp;
}
trail = curr;
curr = curr->next;
}
}
return head;
}
void push(Data **head, char *name) {
Data *temp = malloc(sizeof(Data));
temp->name = strdup(name);
temp->next = *head;
*head = temp;
}
Data* read_from_file(const char *file, const int size) {
FILE *input;
input = fopen(file, "r");
Data *new_ = (Data*)malloc(sizeof(Data*));
new_->next = NULL;
int i;
char name[MAX_STR_LEN];
for(i = 0; i < size; i++) {
fscanf(input, "%24s", &name);
push(&new_, name);
}
return new_;
}
void display(Data *list) {
Data *current = list;
while(current->next != NULL) {
printf("\n%s", current->name);
current = current->next;
}
}
The list of names that I read in is
Derek
Drew
Randell
Terrell
Carmen
Colin
Eddy
Pablo
Lamont
Dexter
In addition to the problem pointed out by BLUEPIXY there were a couple of other problems in the code. I tested this and it seems to work.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAX_STR_LEN 25
typedef struct Data_ {
char *name;
struct Data_ *next;
} Data;
Data* bubble_sort(Data *list);
Data* read_from_file(const char *file);
void display(Data *list);
void push(Data **head, char *name);
int main(int argc, char **argv) {
if(argc != 2){
printf("Not enough parameters!");
exit(0);
}
Data *head = NULL;
head = read_from_file(argv[1]);
printf("\nBefore sort");
display(head);
printf("\nBubble Sort\n");
head = bubble_sort(head);
display(head);
}
Data* bubble_sort(Data *head) {
int i = 1;
Data *curr = NULL;
Data *trail = NULL;
Data *temp = NULL;
Data *after = NULL;
while( i == 1) { // keep sorting
i = 0; // if not changed loop will exit
curr = trail = head; //set curr and trail at the start node
while(curr->next != NULL){
if(strcmp(curr->name, curr->next->name) > 0) {
i = 1; // still sorting
after = curr->next;
temp = after->next; // temp may be NULL. thats ok
after->next = curr;
curr->next = temp;
if(curr==head) {
head = after;
}
else {
trail->next = after;
}
curr = after;
}
trail = curr;
curr = curr->next;
}
}
return head;
}
void push( Data **head, char *name) {
Data *temp = malloc(sizeof(Data));
temp->name = strdup(name);
temp->next = *head;
*head = temp;
}
Data* read_from_file(const char *file) {
FILE *input;
Data *new_ = NULL; // allocation will take place in push
input = fopen(file, "r");
char name[MAX_STR_LEN];
while( fscanf(input, "%24s", name) == 1) { // scan until scan fails to return one value
push( &new_, name);
}
return new_;
}
void display(Data *list) {
Data *current = list;
while(current != NULL) {
printf("\n%s", current->name);
current = current->next;
}
}