my problem is the following:
I have to create a tree from a file .txt, this is an example of what is inside the file:
the first element a is the root, after that is always this way:
the first element (x for example is the left tree) the second element (b for example is the right tree).
if an element is preceded by a point, that element for sure dont have a left or right child below.
so in this case the outgoing tree will be the following:
this is the structure in c language of my tree:
typedef char element;
typedef struct tree_element {
element value;
struct tree_element* left, * right;
} node;
typedef node* tree;
Any ideas on how to solve this?
my incorrect solution:
bool IsEmpty(tree t) {
return (t == NULL);
}
tree EmptyTree(void) {
return NULL;
}
tree Left(tree t) {
if (IsEmpty(t)) {
return NULL;
}
else {
return t->left;
}
}
tree Right(tree t) {
if (IsEmpty(t)) {
return NULL;
}
else {
return t->right;
}
}
tree ConsTree(const element* e, tree l, tree r) {
tree t = malloc(sizeof(node));
t->value = *e;
t->left = l;
t->right = r;
return t;
}
tree InsertValue(tree t, element e, int position) {
if (IsEmpty(t)) {
return ConsTree(&e, EmptyTree(), EmptyTree());
}
tree root = t;
while (true) {
if (position == 1) {
if (IsEmpty(Left(t))) {
t->left = ConsTree(&e, EmptyTree(), EmptyTree());
break;
}
else {
t = Left(t);
}
}
else {
if (IsEmpty(Right(t))) {
t->right = ConsTree(&e, EmptyTree(), EmptyTree());
break;
}
else {
t = Right(t);
}
}
}
return root;
}
extern tree LoadTree(const char* filename) {
FILE* f = fopen(filename, "r");
if (f == NULL) {
return EmptyTree();
}
else {
fseek(f, 0, SEEK_END);
if (ftell(f) == 0) {
fclose(f);
return EmptyTree();
}
else {
fseek(f, 0, SEEK_SET);
tree t = EmptyTree();
char c;
c = fgetc(f);
int i = 0;
element e;
e = c;
l++;
t = InsertValue(t,e,0);
while (c != EOF) {
c = fgetc(f);
if (c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != '\v' && c != '\f') {
i++;
}
}
fclose(f);
return t;
}
}
}
thanks in advance
The input file gives for each sub tree the value then if not prefixed by a dot the left tree then the right tree and that recursively, so the way to construct the tree can follow the same recursion :
node * read_tree(FILE * fp)
{
node * r = malloc(sizeof(node));
fscanf(fp, " %c", &r->value);
if (r->value != '.') {
r->left = read_tree(fp);
r->right = read_tree(fp);
}
else {
fscanf(fp, " %c", &r->value);
r->left = r->right = NULL;
}
return r;
}
The space before %c in the format bypass the possible space/newline/tab/... allowing to read a file with the indents or without them like a.xbd.s.u.c as you said in a remark.
The proposal above supposes/hopes the file is valid, else it is possible to do :
node * read_tree(FILE * fp)
{
node * r = malloc(sizeof(node));
const char * err;
if (r == NULL)
err = "not enough memory";
else if (fscanf(fp, " %c", &r->value) != 1)
err = "invalid file, unexpected EOF";
else if (r->value != '.') {
r->left = read_tree(fp);
r->right = read_tree(fp);
return r;
}
else if (fscanf(fp, " %c", &r->value) != 1)
err = "invalid file, unexpected EOF after '.'";
else if (r->value == '.')
err = "invalid file, two consecutive '.'";
else {
r->left = r->right = NULL;
return r;
}
fprintf(stderr, "%s\nposition in the file : %ld\n", err, ftell(fp));
exit(-1);
}
A full program can be :
#include <stdio.h>
#include <stdlib.h>
typedef char element;
typedef struct tree_element {
element value;
struct tree_element* left, * right;
} node;
node * read_tree(FILE * fp)
{
node * r = malloc(sizeof(node));
const char * err;
if (r == NULL)
err = "not enough memory";
else if (fscanf(fp, " %c", &r->value) != 1)
err = "invalid file, unexpected EOF";
else if (r->value != '.') {
r->left = read_tree(fp);
r->right = read_tree(fp);
return r;
}
else if (fscanf(fp, " %c", &r->value) != 1)
err = "invalid file, unexpected EOF after '.'";
else if (r->value == '.')
err = "invalid file, two consecutive '.'";
else {
r->left = r->right = NULL;
return r;
}
fprintf(stderr, "%s\nposition in the file : %ld\n", err, ftell(fp));
exit(-1);
}
void print_free_tree(node * tree, int lvl)
{
if (tree == NULL)
putchar('.');
else {
putchar('(');
print_free_tree(tree->left, lvl+1);
printf("-%c %d-", tree->value, lvl);
print_free_tree(tree->right, lvl+1);
putchar(')');
free(tree);
}
}
int main(int argc, char ** argv)
{
FILE * fp;
if (argc != 2)
fprintf(stderr, "Usage: %s <file>\n", *argv);
else if ((fp = fopen(argv[1], "r")) == NULL)
perror("cannot read file");
else {
node * tree = read_tree(fp);
/* must be at end of file except may be some space/newline */
char c;
if (fscanf(fp, " %c", &c) == 1)
fprintf(stderr, "invalid file, extra element(s) from the position %ld\n", ftell(fp));
fclose(fp);
/* show & free tree */
print_free_tree(tree, 1);
putchar('\n');
}
return 0;
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -Wall c.c
pi#raspberrypi:/tmp $ cat f
a
.x
bd.s.u.c
pi#raspberrypi:/tmp $ ./a.out f
((.-x 2-.)-a 1-(((.-s 4-.)-d 3-(.-u 4-.))-b 2-(.-c 3-.)))
pi#raspberrypi:/tmp $
to help to check the validity of the tree each value is written with the level of its node, the empty branches are indicated by a '.'.
Execution under valgrind :
pi#raspberrypi:/tmp $ valgrind ./a.out f
==13298== Memcheck, a memory error detector
==13298== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==13298== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==13298== Command: ./a.out f
==13298==
((.-x 2-.)-a 1-(((.-s 4-.)-d 3-(.-u 4-.))-b 2-(.-c 3-.)))
==13298==
==13298== HEAP SUMMARY:
==13298== in use at exit: 0 bytes in 0 blocks
==13298== total heap usage: 10 allocs, 10 frees, 5,556 bytes allocated
==13298==
==13298== All heap blocks were freed -- no leaks are possible
==13298==
==13298== For lists of detected and suppressed errors, rerun with: -s
==13298== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
pi#raspberrypi:/tmp $
Related
Object* createObject(char *fileName) {
FILE *fileToObject = fopen(fileName, "r");
if (fileToObject == NULL) {
printf("Failed opening the file , Exiting !\n ");
return NULL;
}
return objectFromFile(fileToObject);
}
//creates vertex
Vertex* createVertex(char *line, Vertex *v) {
float x, y, z;
sscanf(line, "%*c %f %f %f", &x, &y, &z);
v->x = x;
v->y = y;
v->z = z;
return v;
}
//creates face
Face* createFace(char *line, Face *face) {
char *delimeters = " ";
char *temp = (char*) calloc(1, sizeof(char));
temp = strtok(line, delimeters);
while (temp != NULL) {
temp = strtok(NULL, delimeters);
*face->vertex = atoi(temp);
}
return face;
}
//creates object
Object* objectFromFile(FILE *file) {
Object *obj = (Object*) malloc(sizeof(Object));
if (obj == NULL) {
printf("Failed allocating memory for object");
return NULL;
}
Vertex *vertexes = (Vertex*) malloc(sizeof(Vertex));
if (obj == NULL) {
printf("Failed allocating memory for vertex");
return NULL;
}
Face *faces = malloc(sizeof(Face));
if (obj == NULL) {
printf("Failed allocating memory for face");
return NULL;
}
obj->numberOfFaces = 0;
obj->numberOfVertexes = 0;
char *line = malloc(sizeof(char));
while (fgets(line, MAX_SIZE, file)) {
if (line[0] == 'v' && line[1] == ' ') {
vertexes = (Vertex*) realloc(vertexes,
(obj->numberOfVertexes + 1) * sizeof(Vertex));
if (vertexes == NULL) {
printf("Failed allocating vertexes");
return NULL;
}
vertexes[obj->numberOfVertexes++] = *createVertex(line, vertexes);
} else if (line[0] == 'f' && line[1] == ' ') {
faces = (Face*) realloc(faces,
(obj->numberOfFaces + 1) * sizeof(Face));
if (faces == NULL) {
printf("Faild allocating faces");
return NULL;
}
createFace(line, faces);
faces[obj->numberOfFaces++] = *createFace(line, faces);
}
}
obj->vertexes = vertexes;
obj->faces = faces;
free(line);
fclose(file);
return obj;
}
This function creates an object from a file, but as I try to return the value from the function I get this type of message - "conflicting type for 'objectFromFile'. " I tried finding the error but could not see it. I'm using eclipse environment with gcc compiler, on ubuntu using VM workstation player.
I would really appreciate you help.
You need to have a prototype for your functions.
Place this before createObject:
Object* objectFromFile(FILE *file);
This "conflicting type" error is caused by a legacy concept called implicit declaration, wherein all functions returned int if they weren't passed an argument.
You can compile with the options -std=c11 -pedantic -Wall -Wextra -Werror (C11 standard, strict compliance, all and extra warnings, warnings are errors) to catch these mistakes in the future.
The idea of my program is to read data from a file (in this case file includes 5 names), and store them in a list, so I can use the data later to for example calculating the min/max characters. So far I have been able to read the data and print it out, but rather than printing, I'd want to save them to a list. I couldn't find a way around how to do this, so I'd appreciate some help.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char file, filename[25];
FILE *f;
printf("Enter the file name: ");
scanf("%s", filename);
f = fopen(filename, "r");
if (f == NULL)
{
perror("No file found.\n");
return 0;
}
printf("The contents of %s file are:\n", filename);
while((file = fgetc(f)) != EOF)
printf("%c", file);
fclose(f);
return 0;
}
Just a simple example using linked names for your list :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct NameList {
char * name;
struct NameList * next;
} NameList;
int append(NameList ** head, NameList ** tail, char * s)
{
NameList * l;
if (((l = malloc(sizeof(NameList))) == NULL) ||
((l->name = strdup(s)) == NULL))
/* not enough memory */
return 0;
l->next = NULL;
if (*head == NULL) {
*head = *tail = l;
}
else {
(*tail)->next = l;
*tail = l;
}
return 1;
}
int main(void) {
char filename[25];
FILE * f;
printf("Enter the file name: ");
if (scanf("%24s", filename) != 1)
return 0;
f = fopen(filename, "r");
if (f == NULL)
{
puts("No file found.");
return 0;
}
NameList * head = NULL;
NameList * tail = NULL;
char s[64];
/* suppose a name has no space even composed and less than 64 characters */
while (fscanf(f, "%63s", s) == 1) {
if (!append(&head, &tail, s))
return 0;
}
fclose(f);
printf("The names in %s file are:\n", filename);
NameList * l;
l = head;
while (l != NULL) {
puts(l->name);
l = l->next;
}
/* search longer name */
size_t maxlen = 0;
char * longer = NULL;
l = head;
while (l != NULL) {
size_t ln = strlen(l->name);
if (ln > maxlen) {
maxlen = ln;
longer = l->name;
}
l = l->next;
}
if (longer != NULL)
printf("longer name is : %s\n", longer);
/* free resources */
while (head != NULL) {
l = head;
head = head->next;
free(l->name);
free(l);
}
return 0;
}
Compilation and execution
pi#raspberrypi:/tmp $ gcc -pedantic -Wextra l.c
pi#raspberrypi:/tmp $ cat aze
firstname secondname
anothername
lastname
pi#raspberrypi:/tmp $ ./a.out
Enter the file name: aze
The names in aze file are:
firstname
secondname
anothername
lastname
longer name is : anothername
Execution under valgrind
pi#raspberrypi:/tmp $ valgrind ./a.out
==10132== Memcheck, a memory error detector
==10132== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10132== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10132== Command: ./a.out
==10132==
Enter the file name: aze
The names in aze file are:
firstname
secondname
anothername
lastname
longer name is : anothername
==10132==
==10132== HEAP SUMMARY:
==10132== in use at exit: 0 bytes in 0 blocks
==10132== total heap usage: 12 allocs, 12 frees, 6,570 bytes allocated
==10132==
==10132== All heap blocks were freed -- no leaks are possible
==10132==
==10132== For counts of detected and suppressed errors, rerun with: -v
==10132== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
Note the linked list can be replaced by an array of char*, using realloc to increase its size when reading the names etc
Apart for details of the format of the input, reading in the data is not flexible in your current solution. Heres a more generous input reading. Combine this with the other answers and you should be on your way.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void) {
{
char *cwd = getcwd(NULL, 0);
printf("FYI, the current working directory of this program is : `%s'\n", cwd);
free(cwd);
}
printf("Enter the file name: ");
char *filename;
int scanf_return = scanf("%m[a-zA-Z./]", &filename);
if (scanf_return != 1) {
if (errno != 0) {
perror("scanf");
} else {
fprintf(stderr, "%s\n",
"Sorry, unable to read file name. "
"Only 'a'...'z', 'A'...'Z', '.' (period) "
"and '/' (slash) allowed in the name.");
}
return EXIT_FAILURE;
}
FILE *f = fopen(filename, "r");
if (f == NULL) {
perror(filename);
free(filename);
return EXIT_FAILURE;
}
printf("The contents of `%s' file are:\n", filename);
free(filename);
filename = NULL;
size_t line_sz = 0u;
char *line = NULL;
int nread;
errno = 0;
while ((nread = getline(&line, &line_sz, f)) != -1) {
// If we reached the EOF then there might not be a newline character
if (line[nread - 1] != '\n') {
nread++;
}
printf("`%.*s'\n", nread - 1, line);
}
if (errno != 0) {
perror("getline");
free(line);
fclose(f);
return EXIT_FAILURE;
}
free(line);
fclose(f);
return EXIT_SUCCESS;
}
So I'm looping through readdir() function calls and adding the resulting file name to a new node in a linked list. After fixing an issue by setting file_list = add_file_node(), I'm running into and issue where the dir_list loop is having problems accessing the directory.
hls: cannot access hls: cannot access h: No such file or directory
code:
#include "header.h"
/**
* main - main ls function
*
* #argc: argument count
* #argv: argument vector
*
* Return: 0, or the errno of the error
*/
int main(int argc, char **argv)
{
struct dirent *read;
char dir[400], error_message[400], format, hidden;
int i, j, dir_count, max_src_bytes = 397;
dir_list_t *dir_list, *dir_node;
file_list_t *file_list;
DIR *dirp;
int errno;
format = ' ';
hidden = ' ';
dir_count = 0;
strcpy(dir, ".");
for (i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
{
for (j = 1; argv[i][j]; j++)
{
if (argv[i][j] == '1')
format = '1';
else if (argv[i][j] == 'l')
format = 'l';
if (argv[i][j] == 'a')
hidden = 'a';
else if (argv[i][j] == 'A')
hidden = 'A';
}
}
else
{
memset(dir, 0, strlen(dir));
strcpy(dir, argv[i]);
dir_list = add_dir_list(&dir_list, dir);
dir_count++;
}
}
if (dir_count == 0)
dir_list = add_dir_list(&dir_list, dir);
for (dir_node = dir_list; dir_node != NULL; dir_node = dir_node->next)
{
dirp = opendir(dir_node->dir);
if (dirp == NULL)
{
strcpy(error_message, "hls: cannot access ");
max_src_bytes = 381;
perror(strncat(error_message, dir_node->dir, max_src_bytes));
return (errno);
}
if (dir_count > 1)
printf("%s:\n", dir_node->dir);
while ((read = readdir(dirp)) != NULL)
{
file_list = add_file_list(&file_list, read->d_name);
}
switch (format)
{
case '1':
print_ls(hidden, '\n', file_list);
break;
case 'l':
print_ls(hidden, '\n', file_list);
break;
default:
print_ls(hidden, '\t', file_list);
}
if (dir_node->next != NULL)
putchar('\n');
free_file_list(&file_list);
}
free_dir_list(&dir_list);
closedir(dirp);
return (0);
}
/**
* print_ls - print contents in the default ls format, i.e. columns
*
* #hidden: parameter denoting the option for revealing hidden files
* #format: printing format parameter
* #dirp: pointer to the directory data
*
* Return: 0 for success, 1 for failure
*/
int print_ls(char hidden, char format, file_list_t *file_list)
{
file_list_t *file_node;
for (file_node = file_list; file_node != NULL; file_node = file_node->next)
{
if (hidden == 'a')
{
printf("%s", file_list->file);
if (file_list->next != NULL)
putchar(format);
}
else if (hidden == 'A')
{
if (strcmp(file_list->file, ".") != 0 &&
strcmp(file_list->file, "..") != 0)
{
printf("%s", file_list->file);
if (file_list->next != NULL)
putchar(format);
}
}
else
{
if (file_list->file[0] != '.')
{
printf("%s", file_list->file); // (line 139)
if (file_list->next != NULL)
putchar(format);
}
}
}
if (format == '\t')
printf("\n");
return (0);
}
add_file_list():
/**
* add_file_list - add a new node at the start of a file_list_t linked list
*
* #head: start of linked list
* #file: file data to add to node
*
* Return: address of new node; NULL if failure
*/
file_list_t *add_file_list(file_list_t **head, const char file[256])
{
file_list_t *node;
node = malloc(sizeof(file_list_t));
if (node == NULL)
return (NULL);
strcpy(node->file, file);
node->next = *head;
node->prev = NULL;
*head = node;
return (node);
}
I'm thinking about trying this out with an array of pointers instead, but I don't want to throw away my code before getting some insight. Am I not inputting the data into the node correctly? If so, how would I do that?
this is wrong, just as valgrind says
file_head = file_list; <<<< file_list is not initlaized, file_head = junk
while ((read = readdir(dirp)) != NULL)
{
printf("read: %s\n", read->d_name);
append_file_list(&file_list, read->d_name);
printf("file_list: %s\n", file_list->file);
}
printf("file_head: %s\n", file_head->file); <<<<<= (line 78) file_head = junk
I've got a problem with reading words from file and passing it to binary tree. When I debug it, it says:
Unhandled exception at 0x76E7773B(ntdll.dll) in Projekt.exe: 0.C00000005:
Access violation reading location 0x0037902A.
Here is the source code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
typedef struct Tree {
int val;
char *word;
struct Tree *left;
struct Tree *right;
} Tree;
void show(Tree *hd) {
if (hd != NULL) {
show(hd->left);
show(hd->right);
printf("%s -- %d\n", hd->word, hd->val);
}
}
void zero(Tree *aTree) {
if (aTree == NULL)
return;
zero(aTree->left);
free(aTree);
zero(aTree->right);
}
int alpha(char *word1, char *word2) {
if (word1[0] == 0 && word2[0] == 0)
return 2;
else
if (word1[0] == word2[0])
return alpha(&word1[1], &word2[1]);
else
if (word1[0] < word2[0])
return 1;
else
return 0;
}
Tree *create(char *word) {
Tree *temp;
temp = (Tree*)malloc(sizeof(Tree));
temp->left = temp->right = NULL;
temp->val = 1;
temp->word = (char*)malloc(sizeof(char));
strcpy(temp->word, word);
return temp;
}
Tree *insert(Tree *aTree, char *word) {
if (aTree == NULL) {
aTree = create(word);
} else
if (alpha(aTree->word, word) == 0) {
aTree->left = insert(aTree->left,word);
} else
if (alpha(aTree->word, word) == 1) {
aTree->right = insert(aTree->right, word);
} else
if (alpha(aTree->word, word) == 2) {
aTree->val++;
}
return aTree;
}
int main(int argc, char *argv[]) {
Tree *myTree = NULL;
char buffer[256] = { 0 };
char temp = 0;
int i = 0;
FILE *fp = fopen(argv[1], "r");
if (fp) {
while (temp != EOF) {
temp = getc(fp);
temp = toupper(temp);
if (temp >= 65 && temp <= 90) {
buffer[i] = temp;
i++;
} else {
if (buffer[0] != 0) {
puts(buffer);
myTree = insert(myTree, buffer);
memset(buffer, 0, sizeof(buffer));
i = 0;
}
}
}
}
fclose(fp);
show(myTree);
return 0;
}
Your program has several problems:
in function zero, you free the pointer too soon, you should move the free(aTree); as the last statement, otherwise you invoke undefined behavior, possibly a crash (but not the one you have, since you never call this function):
void zero(Tree *aTree) {
if (aTree != NULL) {
zero(aTree->left);
zero(aTree->right);
free(aTree);
}
In function alpha, you use recursion where a simple loop would suffice. The compiler may convert this to a loop, but it does have to. This is not a bug but why not use a more idiomatic approach such as:
int alpha(const char *word1, const char *word2) {
for (size_t i = 0;; i++) {
if (word1[i] == '\0' && word2[i] == '\0')
return 2;
if (word1[i] == word2[i])
continue;
if (word1[i] < word2[i])
return 1;
else
return 0;
}
}
In function create, you allocate a single byte for the string, this is definitely a cause for the crash. You should allocate strlen(word) + 1 or use strdup(word). You should not cast the return value of malloc() either:
Tree *create(const char *word) {
Tree *temp;
temp = malloc(sizeof(Tree));
temp->left = temp->right = NULL;
temp->val = 1;
temp->word = strdup(word);
return temp;
}
In function insert you call alpha multiple times, this is inefficient: you could use a switch statement:
Tree *insert(Tree *aTree, const char *word) {
if (aTree == NULL) {
return create(word);
switch (alpha(aTree->word, word)) {
case 0:
aTree->left = insert(aTree->left, word);
break;
case 1:
aTree->right = insert(aTree->right, word);
break;
case 2:
aTree->val++;
break;
}
}
return aTree;
}
function main has multiple issues:
You do not check if argv[1] is provided to the program. It would be NULL if the program is run without a command line argument.
Your test for end of file is incorrect: temp should be defined as int and you should test its value after reading the byte from the file with getc(), it is idiomatic to name c a variable used for this.
You should use character literals instead of hard coded ASCII values.
the test if (c >= 'A' && c <= 'Z') would work for ASCII, which is almost universal today, but it is more reliable to use isupper(c) instead.
You do not need to clear the buffer, setting a '\0' at the end before inserting the word is enough.
You should also check for buffer overflow and refuse to handle words longer than 255 characters.
You should not call fclose(fp) when fp is NULL, this is undefined behavior.
Here is a corrected version:
int main(int argc, char *argv[]) {
Tree *myTree = NULL;
char buffer[256];
int c;
size_t i;
FILE *fp;
if (argc < 2) {
printf("missing argument\n");
return 2;
}
fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("cannot open %s\n", argv[1]);
return 1;
}
i = 0;
while ((c = getc(fp)) != EOF) {
c = toupper(c);
if (isupper(c)) {
if (i < sizeof(buffer))
buffer[i] = c;
i++;
} else {
if (i > 0 && i < sizeof(buffer)) {
buffer[i] = '\0';
puts(buffer);
myTree = insert(myTree, buffer);
i = 0;
}
}
}
fclose(fp);
show(myTree);
return 0;
}
Incorrect code to check if a word can be made of smaller given words (word break).This is the code I wrote for the above mentioned problem, however an online judge declares it as incorrect, what could be the possible reasons? And how should I modify my code?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Node structure */
typedef struct node {
int letter[26];
struct node* next[26];
int is_word;
} node;
/* Create node */
node* getnode(void) {
node* p = malloc(sizeof(node));
int i;
for (i = 0; i < 1004; i++) {
p->letter[i] = 0;
p->next[i] = NULL;
}
p->is_word = 0;
return p;
}
/* make dictionary */
void fill_dictionary(char word[], node* start) {
int len = strlen(word), i;
node* temp = start;
for (i = 0; i < len; i++) {
if (temp->letter[word[i] % 'a'] == 0) {
temp->letter[word[i] % 'a'] = 1;
temp->next[word[i] % 'a'] = getnode();
temp = temp->next[word[i] % 'a'];
} else {
temp = temp->next[word[i] % 'a'];
}
}
temp->is_word = 1;
return;
}
int spell_check(char line[100003], node* start) {
int len = strlen(line), i, flag = 0;
node* temp = start;
for (i = 0; i < len; i++) {
if (temp->letter[line[i] % 'a'] == 0) {
return 1;
} else {
temp = temp->next[line[i] % 'a'];
flag = 0;
if (temp->is_word == 1) {
flag = 1;
temp = start;
}
}
}
if (flag == 1) {
return 0;
} else {
return 1;
}
}
int main(void) {
int n, i, ans, m;
scanf("%d %d", &n,&m); // no. of words in dictionary
node* start = getnode();
for (i = 0; i < n; i++) {
char word[11]; // max length of dictionary word
scanf("%s", word);
fill_dictionary(word, start);
}
scanf("%d", &n); // no. of lines to be checked
for (i = 0; i < n; i++) {
char line[100003]; // max length of a line
scanf("%s", line);
ans = spell_check(line, start);
if (ans == 0) {
printf("YES\n");
} else {
printf("NO\n");
}
}
return 0;
}
Here's one way to to it. This compiles and runs. It displays the parsed result. It tries to read the dictionary from a file called "dictionary.text" in the current directory. You can change it to put the dictionary wherever you want. I commented it heavily to help you understand it but it has some subtle C things you may need to really think about and figure out. One bit of advice: Name everything in a program as extremely accurately for what it is/does as possible (but reasonably succinct). That will help immensely when trying to debug or figure out what you did wrong. Careless names really make code confusing and hard to debug.
Good luck!
Example:
$ gcc -o wordsplitter wordsplitter.c
$ wordsplitter xyzhellogoodbyefoodogcatpigcarwhereareyouhorse
xyz "hello" "goodbye" foo "dog" "cat" pigcar "where" "are" "you" horse
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DICTIONARY_FILEPATH "dictionary.txt"
#define MAX_WORD_SIZE 100
/*
* Error codes (usually this is put in a header file and included)
*/
#define SUCCESS 0
#define FILE_NOT_FOUND -1
#define OUT_OF_MEMORY -2
typedef struct word {
struct word *next;
char *word;
} word_t;
word_t *dictionaryListhead = NULL;
typedef struct wordsubcomponent {
struct wordsubcomponent *next;
char *text;
int isDictionaryWord;
} wordsubcomponent_t;
int
loadDictionaryFromFile(char *filename, word_t **listhead)
{
char wordFromFile[MAX_WORD_SIZE];
word_t *lastWordStored = NULL;
FILE *dictionaryFile = fopen(filename, "r");
if (dictionaryFile == NULL) {
return FILE_NOT_FOUND;
}
while(fgets(wordFromFile, sizeof(wordFromFile), dictionaryFile)) {
word_t *newDictionaryWordNode;
if ((newDictionaryWordNode = calloc(sizeof(word_t), 1)) == NULL) { // calloc automatically zeroes memory
return OUT_OF_MEMORY;
}
char *cp = strchr(wordFromFile, '\n');
if (cp != NULL)
*cp = '\0'; // get rid of trailing \n
newDictionaryWordNode->word = strdup(wordFromFile);
if (*listhead == NULL) {
lastWordStored = *listhead = newDictionaryWordNode;
} else {
lastWordStored = lastWordStored->next = newDictionaryWordNode;
}
}
fclose(dictionaryFile);
return SUCCESS;
}
wordsubcomponent_t
*newsubcomponent() {
wordsubcomponent_t *subcomp = NULL;
if ((subcomp = calloc(sizeof(wordsubcomponent_t), 1)) != NULL) {
subcomp->text = strdup(""); // seed with empty string (instead of NULL) so we can append
} else {
fprintf(stderr, "out of memory (fatal). program exiting\n");
exit(-1);
}
return subcomp;
}
/*
* Returns an linked list of word subcomponents for the given word, split up around dictionary words
*/
wordsubcomponent_t *getWordSubcomponents(char *wordToParse, word_t *listhead) {
wordsubcomponent_t *subcomponents, *currSubcomp;
subcomponents = currSubcomp = newsubcomponent();
for (char *cp = wordToParse; cp < wordToParse + strlen(wordToParse);) { // exit when cp gets to end of word to parse.
int matchFlag = 0;
for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
if (strncasecmp(cp, wordNode->word, strlen(wordNode->word)) == 0) { // prefix of cur. ptr is dict word.
if (strlen(currSubcomp->text) != 0) // Detected non-dict text in subcomp.
currSubcomp = currSubcomp->next = newsubcomponent(); // leave in list & add new subcomp for dict word.
currSubcomp->text = wordNode->word; // save dict-word in subcomp
currSubcomp->isDictionaryWord = 1;
currSubcomp = currSubcomp->next = newsubcomponent(); // dict-word in list, so get new subcomp
cp += strlen(wordNode->word); // advance cp past extracted dict-word
matchFlag = 1;
break; // break out of inner-loop
}
}
if (!matchFlag) { // No dict-word found at cp
char oneNullTerminatedLetter[2] = { *cp++, '\0' }; // put 1st ltr into NULL-terminated string & adv cp.
strcat(currSubcomp->text, oneNullTerminatedLetter); // append letter-as-string to curr subcomp
}
}
return subcomponents;
}
void
dumpDictionary(word_t *listhead) {
printf("\nList of dictionary words:\n");
printf("----------------\n");
for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
printf(" %s\n", wordNode->word);
}
printf("----------------\n\n");
}
int
main(int argc, char **argv)
{
int status;
if ((status = loadDictionaryFromFile(DICTIONARY_FILEPATH, &dictionaryListhead)) < 0) {
switch(status) {
case FILE_NOT_FOUND:
fprintf(stderr, "Error accessing dictionary: %s\n", argv[0]);
break;
case OUT_OF_MEMORY:
fprintf(stderr, "Out of memory");
break;
}
return EXIT_FAILURE;
}
/*
* Load dictionary first so we can show them the list of words if they didn't
* pass in a command line argument with the word to parse.
*/
if (argc < 2) {
fprintf(stderr, "Usage: %s <word_to_parse>\n\n", argv[0]);
dumpDictionary(dictionaryListhead);
return EXIT_FAILURE;
}
wordsubcomponent_t *subcomp = getWordSubcomponents(argv[1], dictionaryListhead);
while(subcomp != NULL && strlen(subcomp->text) > 0) {
if (subcomp->isDictionaryWord)
printf("\"%s\" ", subcomp->text);
else
printf("%s ", subcomp->text);
subcomp = subcomp->next;
}
printf("\n");
return EXIT_SUCCESS;
}
#nerdist colony:
There is a resource leak in loadDictionaryFromFile. This means a file pointer was not closed when returning from this function in case of an error.
Here is a corrected copy of this function
int loadDictionaryFromFile(char *filename, word_t **listhead)
{
char wordFromFile[MAX_WORD_SIZE];
word_t *lastWordStored = NULL;
FILE *dictionaryFile = fopen(filename, "r");
if (dictionaryFile == NULL) {
return FILE_NOT_FOUND;
}
while(fgets(wordFromFile, sizeof(wordFromFile), dictionaryFile)) {
word_t *newDictionaryWordNode;
if ((newDictionaryWordNode = calloc(sizeof(word_t), 1)) == NULL) { // calloc automatically zeroes memory
fclose(dictionaryFile); // <-- Close the file pointer
return OUT_OF_MEMORY;
}
char *cp = strchr(wordFromFile, '\n');
if (cp != NULL)
*cp = '\0'; // get rid of trailing \n
newDictionaryWordNode->word = strdup(wordFromFile);
if (*listhead == NULL) {
lastWordStored = *listhead = newDictionaryWordNode;
} else {
lastWordStored = lastWordStored->next = newDictionaryWordNode;
}
}
fclose(dictionaryFile);
return SUCCESS;
}