C Program: Print Linked List from Recursive Ordering Function - c

I am creating a linked list by reading in a text file and inserting the letters in alphabetical order in the list. I need to print the list, but cannot seem to get the correct function. I keep getting an error
error: invalid type argument of ‘->’ (have ‘order_list’)
error: invalid type argument of ‘->’ (have ‘order_list’)
I know this is incorrect, but I am at a loss for correctly stating the print_alph function. Any help in finding a way to correctly print my list would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
typedef struct list_node_alph {
int key;
struct list_node_alph *rest_old;
} list_node_order;
typedef struct {
list_node_order *the_head;
int size;
} order_list;
list_node_order *rec_alph_order(list_node_order * old_list, int new_key);
void insert_node(order_list *the_alph, int key);
void print_alph(order_list my_list);
list_node_order *rec_alph_order(list_node_order *old_list, int new_key) {
list_node_order *new_list;
if (old_list == NULL) {
new_list = (list_node_order *)malloc(sizeof (list_node_order));
new_list->key = new_key;
new_list->rest_old = NULL;
} else if (old_list->key >= new_key) {
new_list = (list_node_order *)malloc(sizeof (list_node_order));
new_list->key = new_key;
new_list->rest_old = old_list;
} else {
new_list = old_list;
new_list->rest_old = rec_alph_order(old_list->rest_old, new_key$
}
return (new_list);
}
void insert_node(order_list * the_alph, int key) {
++(the_alph->size);
the_alph->the_head = rec_alph_order(the_alph->the_head, key);
}
void print_alph(order_list my_list) {
printf("Pangram in alphabetical order: ");
while(my_list->head != NULL) { //ERROR
printf("%c", my_list->the_head); //ERROR
}
}
int main(void) {
int ch_count;
int count_pangram;
char *pang_arr;
FILE *alph_text;
alph_text = fopen("pangram.txt", "r");
if (alph_text == NULL) {
printf("Empty file. \n");
}
order_list my_alph = {NULL, 0};
while (( ch_count = fgetc(alph_text)) != EOF) {
putchar(ch_count);
char next_key;
int the_count;
for (the_count = 0; the_count < 100; the_count++) {
if (fscanf(alph_text, "%c", &next_key) != ' ') {
//order_list my_alph = {NULL, 0};
//for(next_key; next_key != SENT; scanf("&c", &next_key$
insert_node(&my_alph, next_key);
}
}
}
print_alph(my_alph);
fclose(alph_text);
return(0);
}

Here in print_alph() you are passing instance of type order_list
so to access its member you should use . not ->
so change
while(my_list->head != NULL){
to
while(my_list.the_head != NULL){
But i think instead of passing its instance you should pass pointer of that object in print_alph()
In that case -> is fine to access its member.
void print_alph(order_list *my_list)
and call it as
print_alph(&my_alph);

You need to use . instead of -> inside print_alph function as you have not passed order_list as pointer
void print_alph(order_list my_list){
printf("Pangram in alphabetical order: ");
while(my_list.head != NULL){
printf("%c", my_list.the_head);
}
}

Related

Can't access pointer while navigating linked list

I'm making a simple hash table and a hash function. Each element of the table has a pointer to another node that is used by the insert function when a collision occurs. The problem is that when a collision occurs my code simply crashes when it's navigating the linked list. Here is the code (sorry if it's a little lengthy):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hash.h"
#define TAM 50
int funcaoHash(int chave, char nome[50]) //Hash function
{
int i;
int hash = chave;
for(i = 0; nome[i] != '\0'; i++)
{
hash = hash + (int)nome[i];
}
hash = hash%TAM;
return hash;
}
void insere(int chave, char nome[50], itemTabela* TabelaHash[TAM]) //Insert function
{
int idx = funcaoHash(chave, nome);
itemTabela* ItemAux = (itemTabela*)malloc(sizeof(itemTabela));
itemTabela* ptrAux = NULL;
ItemAux->chave = chave;
strcpy(ItemAux->nome, nome);
if(TabelaHash[idx] == NULL) //No collision occurred
TabelaHash[idx] = ItemAux;
//If there is a collision
else
{
ptrAux = TabelaHash[idx]->ptr;
//Here the code breaks
while(ptrAux->ptr != NULL)
{
ptrAux = ptrAux->ptr;
}
ptrAux = ItemAux;
}
}
void inicializaTabela(itemTabela* TabelaHash[TAM]) //Initialize tabl
{
int i;
for(i = 0; i < TAM; i++)
TabelaHash[i] = NULL;
}
Here is the node structure:
typedef struct itemTabela
{
char nome[50];
int chave;
struct itemTabela* ptr;
}itemTabela;
And here is the main function:
int main()
{
itemTabela *ptrTabela[TAM] = {};
inicializaTabela(ptrTabela);
insere(6, "Chico", ptrTabela);
insere(6, "Chico", ptrTabela);
return 0;
}
Am I accessing the pointers in the wrong way or doing some ilegal access?
Thanks for your time!
1)
Initialization of ItemAux also requires ptr initialization. like ItemAux->ptr = NULL;
2)
ptrAux = TabelaHash[idx]->ptr;
//Here the code breaks
while(ptrAux->ptr != NULL)
{
ptrAux = ptrAux->ptr;
}
ptrAux = ItemAux;
should be
ptrAux = TabelaHash[idx];
while(ptrAux->ptr != NULL)
{
ptrAux = ptrAux->ptr;
}
ptrAux->ptr = ItemAux;

How to return linked list from a function?

Firstly, sorry for my bad english, hope you understand me.
I'm new into programming in general and need help in a small project our teacher asked us to do. (Homework.)
In this homework I created a linked list:
struct No {
char Nome[30];
char Endereco[30];
int Numero;
int aux;
struct No *prox;
};
typedef struct No no;
Then, I added functions to populate an array. The problem is just that one of my function isn't changing the array in any way, its like if I'm not calling the function at all.
Here are the important parts:
int main(void)
{
no *lista = (no *) malloc(sizeof(no)); //This is the linked list I'm talking about.
Contagem=0;
int iOpcao;
while(iOpcao) {
iOpcao=Escolha();
if(selecionarOpcao(lista,iOpcao) == 0)
return 0;
}
return 0;
}
int selecionarOpcao(no *entrada, int op)
{
no *tmp;
switch(op){
case 0:
return 0;
case 1:
ListarContatos(entrada);
break;
case 2:
AdicionarContato(entrada);
break;
case 3:
RemoverContato(entrada);
break;
case 4:
EditarContato(entrada);
break;
case 5:
entrada = OrganizarLista(entrada); //This is the function not working correctly, the other ones are working perfectly fine.
break;
default:
printf("Comando invalido\n\n");
}
return 1;
}
And finally the function itself:
no* OrganizarLista(no* entrada) {
no* ordenada = (no *) malloc(sizeof(no));
no* temp = entrada;
no* maiorNo = NULL;
while(1 == 1) {
while(temp != NULL) {
temp = temp->prox;
if(temp != NULL) {
if(JaExistente(ordenada, temp->Numero) == 1)
continue;
if(temp->prox != NULL && maiorNo == NULL) {
if(JaExistente(ordenada, temp->prox->Numero) == 1) {
maiorNo = temp;
continue;
}
//printf("%s contra %s", temp->Nome, temp->prox->Nome);
if(maiorNo == NULL)
maiorNo = CompararNos(temp, temp->prox);
//printf("%s ganhou.\n", maiorNo->Nome);
}
else if(maiorNo != NULL) {
//printf("%s contra %s", maiorNo, temp->Nome);
maiorNo = CompararNos(maiorNo, temp);
//printf("%s ganhou.\n", maiorNo->Nome);
}
}
}
if(maiorNo != NULL) {
//printf("Maiorno->nome = %s", maiorNo->Nome);
AdicionarLista(ordenada, maiorNo->Nome, maiorNo->Endereco, maiorNo->Numero, 1);
temp = entrada;
maiorNo = NULL;
}
else {
temp = entrada;
while(temp != NULL) {
if(JaExistente(ordenada, temp->Numero) == 0)
AdicionarLista(ordenada, temp->Nome, temp->Endereco, temp->Numero, 1);
temp = temp->prox;
}
break;
}
}
free(temp);
return ordenada;
}
I spent the whole day trying to figure it out however it is still not working. When I check the values inside the function they are all correct but when the values are returned it seems like the program just ignore them.
Any help is appreciated, again, sorry for my english and thanks everyone!
You are trying to set a new value for parameter that was sent by value.
In order to send a pointer or any variable to a function and let the function change its value, you should send it by reference, its address.
Assumimg you have the following functions:
void changePtr(no **ptr) {
*ptr = // .. some value
}
void dontChangePtr(no *ptr) {
ptr = // some value
}
You should notice the differences between the function calls:
no *n = (no*)malloc(sizeof(no));
dontChangePtr(n); // n will be sent by value and will not be changed
changePtr(&n); // n will be sent by reference and will be changed

Differentiating words in trie

I have a word "all" in my trie and a word "alter" but "alt" is not a word in the trie. But when I check for "alt" it still returns true because is_word is true as "all" was a word. How am is supposed to work this error.
//Here's the code
typedef struct node{
bool is_word;
struct node *children[27];
} node;
unsigned int wsize=0;
node * root;
bool check(const char* word)
{
// TODO
node *chrawler=root;
for(int i=0;i<strlen(word)-1;i++)
{
int t;
if(word[i]>=65&&word[i]<=90)
{
t=word[i]-'A';
}
else if(isalpha(word[i]))
t=word[i]-'a';
else
t=26;
if(chrawler->children[t]==NULL)
return false;
else
chrawler=chrawler->children[t];
}
if(chrawler->is_word)
return true;
return false;
}
// Load function
bool load(const char* dictionary)
{
// TODO
FILE *inptr=fopen(dictionary,"r");
if(inptr==NULL)
{
return false;
}
node *new_node=malloc(sizeof(node));
root=new_node;
char * word=malloc((LENGTH+1)*sizeof(char));
int index=0;
for(int c=fgetc(inptr);c!=EOF;c=fgetc(inptr))
{
char ch=c;
if(ch=='\n')
{
word[index]='\0';
index=0;
node *chrawler=root;
for(int i=1;i<strlen(word);i++)
{
int t;
if(isalpha(word[i-1]))
t=word[i-1]-'a';
else
t=26;
if(chrawler->children[t]==NULL)
{
node *new_node=malloc(sizeof(node));
chrawler->children[t]=new_node;
chrawler=chrawler->children[t];
}
else
chrawler=chrawler->children[t];
}
chrawler->is_word=1;
wsize++;
}
else
{
word[index]=ch;
index++;
}
}
return true;
}
You need to ensure that all the pointers in a new node are null, as well as setting the is_word value to false. This is, perhaps, most easily done by using calloc() to allocate the space. Creating a function to allocate and error check the allocation of a node makes it easier. Similarly, you have two blocks of code mapping characters to trie indexes. You should use functions — even small ones — more generously.
The character-by-character input for a line of data is not really necessary, either; it would be better to use fgets() to read lines.
Adding these and sundry other changes (for example, local array word instead of dynamically allocated array — which wasn't freed; closing the file when finished; etc.) gives an MCVE (Minimal, Complete, Verifiable Example) like this:
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { LENGTH = 256 };
// Here's the code
typedef struct node
{
bool is_word;
struct node *children[27];
} node;
unsigned int wsize = 0;
node *root;
static inline int map_char(unsigned char c)
{
int t;
if (isalpha(c))
t = tolower(c) - 'a';
else
t = 26;
return t;
}
static inline node *alloc_node(void)
{
node *new_node = calloc(1, sizeof(node));
if (new_node == 0)
{
fprintf(stderr, "Memory allocation failed in %s\n", __func__);
exit(1);
}
return new_node;
}
static bool check(const char *word)
{
node *chrawler = root;
int len = strlen(word);
for (int i = 0; i < len; i++)
{
int t = map_char(word[i]);
if (chrawler->children[t] == NULL)
return false;
else
chrawler = chrawler->children[t];
}
return chrawler->is_word;
}
// Load function
static bool load(const char *dictionary)
{
FILE *inptr = fopen(dictionary, "r");
if (inptr == NULL)
{
fprintf(stderr, "Failed to open file '%s' for reading\n", dictionary);
return false;
}
root = alloc_node();
char word[LENGTH];
while (fgets(word, sizeof(word), inptr) != 0)
{
word[strcspn(word, "\n")] = '\0';
printf("[%s]\n", word);
node *chrawler = root;
int len = strlen(word);
for (int i = 0; i < len; i++)
{
int t = map_char(word[i]);
//printf("t = %d (%c)\n", t, word[i]);
if (chrawler->children[t] == NULL)
chrawler->children[t] = alloc_node();
chrawler = chrawler->children[t];
}
chrawler->is_word = 1;
wsize++;
}
printf("%d words read from %s\n", wsize, dictionary);
fclose(inptr);
return true;
}
int main(void)
{
const char *wordfile = "words.txt";
if (load(wordfile))
{
char line[4096];
while (fgets(line, sizeof(line), stdin) != 0)
{
line[strcspn(line, "\n")] = '\0';
if (check(line))
printf("[%s] is a word\n", line);
else
printf("[%s] is unknown\n", line);
}
}
return 0;
}
There are other changes that should be made. For example,
the wsize variable should be made non-global; it isn't really used outside the load() function. It's easily arguable that the root node should not be global either; the load() function should return the root node, and the check() function should be passed the root node. In general, global variables should be avoided when possible, and it is usually possible.
Given a file words.txt containing:
abelone
abyssinia
archimedes
brachiosaurus
triceratops
all
alter
asparagus
watchamacallit
a
abracadabra
abyss
ant
the output from a run of the program is:
[abelone]
[abyssinia]
[archimedes]
[brachiosaurus]
[triceratops]
[all]
[alter]
[asparagus]
[watchamacallit]
[a]
[abracadabra]
[abyss]
[ant]
13 words read from words.txt
a
[a] is a word
ab
[ab] is unknown
al
[al] is unknown
all
[all] is a word
alt
[alt] is unknown
alte
[alte] is unknown
alter
[alter] is a word
triceratops
[triceratops] is a word
brachiosaurus
[brachiosaurus] is a word
abys
[abys] is unknown
abbey
[abbey] is unknown
abyss
[abyss] is a word
ant
[ant] is a word
a
[a] is a word
archimedes
[archimedes] is a word

Finding words in tree by prefix

In my binary search tree I want to create a function that can get all words starting with a prefix and store all words in an array called results
this is my tree
struct BinarySearchTree_t
{
char *mot,*def;
struct BinarySearchTree_t *left;
struct BinarySearchTree_t *right;
};
typedef struct BinarySearchTree_t BinarySearchTree;
my function :
size_t findWordsByPrefix(BinarySearchTree* tree, char* prefix, char*** results)
{
BinarySearchTree *tmp;
tmp=tree;
static int size=0;
if (!tmp)
return 0;
else if (strncmp(tmp->mot,prefix,strlen(prefix))==0)
{
(*results)= realloc(*results,(1+size)*sizeof(*(*results)));
(*(*results+size))= malloc(strlen(tmp->mot)*sizeof(char));
strcpy((*results)[size],tmp->mot);
size++;
return (1 + findWordsByPrefix(tmp->left,prefix, &results) + findWordsByPrefix(tmp->right,prefix, &results));
}
else
return (strncmp(tmp->mot,prefix,strlen(prefix))<0)?findWordsByPrefix(tmp->right,prefix, &results):findWordsByPrefix(tmp->left,prefix, &results) ;
}
This function should return a number of words starting with the given prefix.
my problem is that the program crash when it is run , and I don't how to resize my array results
so every time I found a word I should increase the size of the results array .
and I would know how exacly manipulate the pointer of pointer of pointer given in arg of this function (char ***results) : what exactly means?
If I simply compile your code, I get severe compiler warnings including:
1>binarysearchtree.c(98) : warning C4047: 'function' : 'char ***' differs in levels of indirection from 'char ****'
1>binarysearchtree.c(98) : warning C4024: 'findWordsByPrefix' : different types for formal and actual parameter 3
This alone will cause a crash -- you are calling your own function recursively with the wrong arguments.
Next, I believe you need to allocate one more than the length of the string, to hold a copy of a string:
malloc((strlen(tmp->mot) + 1 )*sizeof(char))
Next, you're passing around an array of strings of variable size -- and storing the size in a static variable. It's impossible to know if this will work, so don't do it.
Instead, if you want to use a dynamic array of strings, I suggest extracting out a struct to hold them, like so:
struct ResultTable_t
{
int size;
char **results;
};
typedef struct ResultTable_t ResultTable;
void InitializeResults(ResultTable *p_table)
{
p_table->size = 0;
p_table->results = NULL;
}
void AddResult(ResultTable *p_table, char *result)
{
if (result == NULL)
return;
p_table->size++;
p_table->results = realloc(p_table->results, p_table->size * sizeof(*p_table->results));
p_table->results[p_table->size-1] = malloc((strlen(result) + 1) * sizeof(**p_table->results));
strcpy(p_table->results[p_table->size-1], result);
}
void FreeResults(ResultTable *p_table)
{
if (p_table->results != NULL)
{
int i;
for (i = 0; i < p_table->size; i++)
{
free(p_table->results[i]);
}
free(p_table->results);
}
p_table->size = 0;
p_table->results = NULL;
}
(As an improvement, you might consider using geometric growth instead of linear growth for your table of results.)
Then your function becomes:
size_t findWordsByPrefix(BinarySearchTree* tree, char* prefix, ResultTable *p_table)
{
if (!tree)
return 0;
else if (strncmp(tree->mot,prefix,strlen(prefix))==0)
{
AddResult(p_table, tree->mot);
return (1 + findWordsByPrefix(tree->left,prefix, p_table) + findWordsByPrefix(tree->right,prefix, p_table));
}
else if (strncmp(tree->mot,prefix,strlen(prefix))<0)
{
return findWordsByPrefix(tree->right,prefix, p_table);
}
else
{
return findWordsByPrefix(tree->left,prefix, p_table);
}
}
And you would use it like:
ResultTable results;
InitializeResults(&results);
// Get some prefix to search for.
char prefix = GetSomePrefix();
int size = findWordsByPrefix(tree, prefix, &results);
// Do something with the results
// Free all memory of the results
FreeResults(&results);
Update
If the ResultTable is distasteful for some reason, you can pass the dynamic array and array sizes in directly:
void AddResult(char ***p_results, int *p_size, char *word)
{
if (word == NULL)
return;
(*p_size)++;
(*p_results) = realloc(*p_results, ((*p_size)+1) * sizeof(**p_results));
(*p_results)[(*p_size)-1] = malloc((strlen(word) + 1) * sizeof(***p_results));
strcpy((*p_results)[(*p_size)-1], word);
}
void FreeResults(char ***p_results, int *p_size)
{
int i;
if (p_results == NULL || *p_results == NULL)
return;
for (i = 0; i < (*p_size); i++)
{
free ((*p_results)[i]);
}
free (*p_results);
*p_results = NULL;
*p_size = 0;
}
size_t findWordsByPrefix(BinarySearchTree* tree, char* prefix, char ***p_results, int *p_size)
{
if (!tree)
return 0;
else if (strncmp(tree->mot,prefix,strlen(prefix))==0)
{
AddResult(p_results, p_size, tree->mot);
return (1 + findWordsByPrefix(tree->left,prefix, p_results, p_size) + findWordsByPrefix(tree->right,prefix, p_results, p_size));
}
else if (strncmp(tree->mot,prefix,strlen(prefix))<0)
{
return findWordsByPrefix(tree->right,prefix, p_results, p_size);
}
else
{
return findWordsByPrefix(tree->left,prefix, p_results, p_size);
}
}
and use like:
char **results = NULL;
int tablesize = 0;
// Get some prefix to search for.
char prefix = GetSomePrefix();
int size = findWordsByPrefix(tree, prefix, &results, &tablesize);
// Do something with the results
// Free all memory of the results
FreeResults(&results, &tablesize);

having trouble with storing string in linked list

I am having trouble storing a string in a linked list. This is the function that inserts a node to the list:
void insert_rec(rec_ptr *h_ptr, rec_ptr *t_ptr, int a, int b, int c, char* cs)
{
rec_ptr new_ptr;
new_ptr = rec_ptr( malloc( sizeof(REC) ) );
if(new_ptr != NULL)
{
new_ptr->x = a;
new_ptr->y = b;
new_ptr->z = c;
new_ptr->c = cs;
new_ptr->next = NULL;
if(*h_ptr == NULL){
*h_ptr = new_ptr;
}
else{
(*t_ptr)->next = new_ptr;
}
*t_ptr = new_ptr;
}
else
{
printf("%d %d %d not inserted. No memory available.\n",a,b,c);
}
}
This is the function that reads input from an output file. I am inserting a string into the list as a char*. The fscanf() has read the string in correctly.
void read_from_input2(rec_ptr & hptr, rec_ptr & tptr)
{
fp3=fopen("input2.txt","r");
if (fp3 == NULL)
printf("Error: Couldn't open file: input2.txt\n");
else
{
while(!feof(fp3))
{
int x,y,z;
char c1[10];
fscanf(fp3,"%d",&x);
fscanf(fp3,"%d",&y);
fscanf(fp3,"%d",&z);
fscanf(fp3,"%s",c1);
char *c2 = c1;
insert_rec(&hptr,&tptr,x,y,z,c2);
}
}
fclose(fp3);
}
This is the function where I am having problems. When I extract the data from the linked list, the variable c1 outputs garbage.
void write_to_output2(rec_ptr hptr)
{
fp4=fopen("output2.txt","w");
if (fp4 == NULL)
printf("Error: Couldn't open file: output2.txt\n");
else
{
if(hptr == NULL){
printf("List is empty.\n\n");
}
else{
while(hptr != NULL)
{
int x,y,z;
char *c1,*c2;
x = hptr->x;
y = hptr->y;
z = hptr->z;
c1 = hptr->c;
c2 = get_class(x,y,z);
fprintf(fp4,"%d %d %d %s %s\n",x,y,z,c1,c2);
hptr = hptr->next;
}
}
}
fclose(fp4);
}
If anyone can see my error please help me out. Thanks.
char c1[10];
/* ... */
char *c2 = c1;
insert_rec(&hptr,&tptr,x,y,z,c2);
The problem is c1 is on the stack of read_from_input2 and then you store a pointer to its contents. It will go out of scope when the while ends thus access to it will be invalid.
You'll want to strdup it (or equivalent).
char *c2 = strdup(c1);
/* or */
new_ptr->c = strdup(cs);
And don't forget to free it at some point.

Resources