I am creating a music library program in C using linked lists. Users should be able to create a node containing: song name, artists, and genre. These nodes should be sorted alphabetically by song name.
I am having trouble, however, creating new nodes without affecting my current head node. The picture below will illustrate this better. I call a line of code that is meant to receive a new value from the user and it resets the song name value in the head node and I have no clue why. Any help is appreciated.
(Problem occurs between Test Point 1 and Test Point 2 printf statements, I intend for Test Point 2 to display "zz" instead of "aa").
Code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
typedef struct node
{
char* artist;
char* songName;
char* genre;
struct node* nextNode;
} Node;
const int MAX_LENGTH = 1024;
void inputStringFromUser(char prompt[], char s[], int arraySize);
int main(void)
{
// Declare the head of the linked list.
// ADD YOUR STATEMENT(S) HERE
Node* head = NULL;
// Announce the start of the program
printf("Personal Music Library.\n\n");
printf("%s",
"Commands are I (insert), D (delete), S (search by song name),\n"
"P (print), Q (quit).\n");
char response;
char input[MAX_LENGTH + 1];
char input4[MAX_LENGTH + 1];
char input2[MAX_LENGTH + 1];
char input3[MAX_LENGTH + 1];
inputStringFromUser("\nCommand", input, MAX_LENGTH);
response = toupper(input[0]);
if (response == 'I') {
//insert a node code
char* promptName = "Song name";
char* promptArtist = "Artist";
char* promptGenre = "Genre";
char* newName;
char* newArtist;
char* newGenre;
//test points for the songname in the head node
if (head != NULL) {
printf("Test Point 1: %s\n", head->songName);
}
inputStringFromUser(promptName, input4, MAX_LENGTH);
newName = input4;
if (head != NULL) {
printf("Test Point 2: %s\n", head->songName);
}
inputStringFromUser(promptArtist, input2, MAX_LENGTH);
newArtist = input2;
inputStringFromUser(promptGenre, input3, MAX_LENGTH);
newGenre = input3;
//if it is the first node then just create a node then assign the values to the user input
if (head == NULL) {
head = malloc(sizeof(Node));
head->artist = newArtist;
head->genre = newGenre;
head->songName = newName;
} else {
//sorts through list until it finds the first node where the song name is not alphabetically ahead
//of the current entered name
Node* current = head;
while (strcmp(current->songName, newName) == 1) {
//if the loop goes to the end of the list place the new node at the end
if (current->nextNode != NULL) {
current = current->nextNode;
} else {
current->nextNode = malloc(sizeof(Node));
current = current->nextNode;
current->artist = newArtist;
current->genre = newGenre;
current->songName = newName;
break;
}
}
//if the loop finds the correct place for a node it shifts all the other ones down
//then create a new end node
char* tempName = " ";
char* tempName2 = " ";
char* tempArtist = " ";
char* tempArtist2 = " ";
char* tempGenre = " ";
char* tempGenre2 = " ";
tempName = current->songName;
tempArtist = current->artist;
tempGenre = current->genre;
current->artist = newArtist;
current->genre = newGenre;
current->songName = newName;
while (current->nextNode != NULL) {
current = current->nextNode;
tempName2 = current->songName;
tempArtist2 = current->artist;
tempGenre2 = current->genre;
current->songName = tempName;
current->artist = tempArtist;
current->genre = tempGenre;
tempName = tempName2;
tempGenre = tempGenre2;
tempArtist = tempArtist2;
}
current->nextNode = malloc(sizeof(Node));
current = current->nextNode;
current->songName = tempName;
current->artist = tempArtist;
current->genre = tempGenre;
}
}
}
// Support Function Definitions
// Prompt the user for a string safely, without buffer overflow
void inputStringFromUser(char prompt[], char s[], int maxStrLength)
{
int i = 0;
char c;
printf("%s --> ", prompt);
while (i < maxStrLength && (c = getchar()) != '\n')
s[i++] = c;
s[i] = '\0';
}
This is one example of what's wrong:
current->genre = newGenre;
You saving the value of the pointer newGenre (which is pointing to input3). So all nodes will end pointing to same object, i.e. when changing input3 all nodes will point the new value.
Try:
typedef struct node
{
char artist[MAX_LENGTH + 1];
char songName[MAX_LENGTH + 1];
char genre[MAX_LENGTH + 1];
struct node* nextNode;
} Node;
and then do:
strcpy(current->genre, newGenre);
to copy the value into the node.
Alternatively, you can keep the pointers and use dynamic memory allocation.
Related
I am trying to insert words into a hash table and it looks like it works but when I try to print the word inside the node (just to check if its still correct) I get a bogus value. When my code prompts for the word I said 'Hey' and when it prompts for place I said '5'. The string that is printed out(which is supposed to be the word inside the node) is HH9[]A\A]A^A_f. What is happening to the word inside the node and am I inserting the node correctly?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct node
{
char word[20];
struct node *next;
}
node;
int main (void)
{
node* table[10];
char wrd[10];
printf("Word to insert: ");
fgets(wrd, 10, stdin);
int place;
printf("Place to insert word: ");
scanf("%d", &place);
node *n = malloc(sizeof(node));
if(n == NULL)
{
return 1;
}
strcpy(n->word, wrd);
if(table[place] == NULL)
{
n = table[place];
n->next = NULL;
}
else
{
n->next = table[place];
n = table[place];
}
printf("Word inside node: %s \n" , n->word);
}
EDIT
I changed the code and tried to implement it on a larger scale but my while loop gives me a segfault. This is the function I put it in:
FILE* dct = fopen ("/dictionaries/large", "r");
char *wrd = NULL;
while(fscanf(dct, "%s", wrd) != EOF)
{
int place = hash(wrd);
node *n = malloc(sizeof(node));
node *anchor = NULL;
node *end = NULL;
if(n == NULL)
{
return 1;
}
strcpy(n->word, wrd);
n->next = NULL;
if (!end) //Initial state
anchor = end = n;
else //Every following node.
end = end->next = n;
strcpy(n->word, wrd);
n->next = table[place];
table[place] = n;
counter++;
}
return false;
It has to read from the dictionary file and load the word into memory(or a hash table).
A linked list is a linked list because it does not have a fixed size.
The table array is therefor superfluous.
What you need for your linked list to work is to remember the anchor and nothing more.
A small example:
Node *anchor = NULL;
Node *end = NULL;
Node *node = malloc(sizeof(Node));
node->next = NULL;
if (!end) //Initial state
anchor = end = node;
else //Every following node.
end = end->next = node;
At this point, you can still access the node you've just filled. Don't forget to iterate over your list later and free those allocations though.
This code doesn't make any sense:
if(table[place] == NULL)
{
n = table[place]; // since we know table[place] is null, that sets n to null!
n->next = NULL; // We just set n to NULL, we can't access n->next!
}
else
{
n->next = table[place]; // This sets n to a garbage value since table[place] was never assigned a value
n = table[place]; // This leaks the value we malloc'ed. We were supposed to link it to the list!
}
I have a project about linked lists but I'm having a hard time doing it. The teacher wants me to read a .txt file and create singly linked list from it. After that, I need to reverse odd numbers of every line. Then print it. Here is the code which I used for printing the linked list. But I need help to reverse the odd numbers of each line.
This is the code which I used to print the list:
#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[10];
LIST *current, *head;
head = current = NULL;
fp = fopen("data.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 {
current = current->next = node;
}
}
fclose(fp);
for(current = head; current ; current=current->next){
printf("%s", current->string);
}
return 0;
}
Here is the content of the .txt file:
10
9,6,11,7,12,18,19,14,15,13
13,14,9,12,15,3,18,20,1,2
4,11,8,17,12,15,20,10,3,16
19,4,11,1,13,17,12,16,20,18
1,6,20,11,13,9,7,16,10,2
12,4,11,16,3,20,9,19,17,15
20,3,10,12,18,2,5,14,15,16
18,19,15,2,6,9,1,3,17,4
7,6,20,1,11,4,3,5,8,16
1,2,16,13,17,10,12,9,4,15
"But I need help to reverse the odd numbers of each line."
There are several other parts that need to be considered before this step can be developed.
Following are suggestions for a functions approach implementation using your problem description. A few items are simply suggestions to simplify the existing code. And a few other steps, are not mentioned as necessary, but should be considered:
Since you are not mandated to use char *string; in your problem description, choose to use a reasonable string length variable that does not require an additional layer of dynamic allocation, such as char string[260]; (or even smaller to fit your input file.) This will greatly simplify the code.
Because the input file is sized with lines ~30 char long, declare the variable line to be at least large enough to contain one line, eg 80 would allow larger values, and still allow enough space, but since memory is cheap, go with the same size as is used in the string member of your linked list.
Move the work of populating each new node to a function. It also will greatly simplify the program, and provide greater readability. Eg: void insert(LIST **head_ref, char *str);
Always test the return of fopen() before attempting to use the file descriptor.
To manipulate the contents of each odd row (eg 1, 3, 5, 7, 9), as numbers, the contents of each line read in from a file as a string, needs to first be converted to a collection of numbers. This suggests an additional member be added to the struct. For example int num[10].
The previous observation implicitly suggests the need of an additional function to parse and convert each comma delimited string into discrete integer values. Perhaps with the prototype: void parseIntArray(LIST **list);
The next and final task also suggests an additional function to reverse the contents of selected array member integer arrays. This one might use a prototype such as: void reverse_odd(LIST **list, size_t size);
Finally, because each node of LIST created required dynamically allocated memory, once finished using LIST, the memory must be given back to the OS to prevent memory leaks. An additional function to do this could be prototyped: void freeList(LIST **head);
Following are the main() function and preceding support declarations etc. It is intended here to illustrate the above suggested steps, and the benefits of breaking down a bigger problem into smaller problems, then implementing each smaller solution to support the whole. Benefits include for example readability and maintainability and potential re-use of code-base, (Note the similarity of argument lists in each supporting function.):
#define MAX_STRLEN 260 //use mnemonic values to avoid magic numbers in code
struct list {
char string[MAX_STRLEN];
int arr[10];
struct list *next;
};
typedef struct list LIST;
//Prototypes of 'smaller' solutions
void insert(LIST **head_ref, char *str);
void parseIntArray(LIST **list);
void reverse_odd(LIST **list, size_t size);
void freeList(LIST **head);
int main(void)
{
FILE *fp;
char line[MAX_STRLEN];
LIST *current, *head;
char *convPtr = NULL;
head = current = NULL;
fp = fopen("data.txt", "r");
if(fp)
{
//consume 1st line
if(fgets(line, sizeof(line), fp));//10
{
sizeArray = strtol(line, &convPtr, 10);
if(errno != ERANGE)
{
while(fgets(line, sizeof(line), fp))
{
//(see implementations of each below)
//create new node, insert num string
insert(¤t, line);
//convert new->string to integers, place in new->array
parseIntArray(¤t);
//reverse 'odd' contents of each array
reverse_odd(¤t, sizeArray);
}
}else{//handle error and leave}
}
fclose(fp);
}else{//handle error and leave}
//At this point in code, entire file is captured into nodes of list.
//use list as needed
//When finished using list, memory must be freed to prevent memory leaks
head = current;
freeList(&head);
return 0;
}
The remaining code segments are the function implementations used above:
void freeList(LIST **head)
{
LIST *tmp;
while (*head != NULL)
{
tmp = (*head);
(*head) = (*head)->next;
free(tmp);
}
}
//create new node, insert num string
void insert(LIST **head_ref, char *str)
{
int *arr = malloc(numNodes * sizeof(*arr));
//allocate node
LIST* new = calloc(1, sizeof(*new));
//put in the data
strcpy(new->string, str);
//Make next of new node as head
new->next = (*head_ref);
//Move the head to point to the new node
(*head_ref) = new;
}
//convert new->string to integers, place in list->array
void parseIntArray(LIST **list)
{
char *tok = NULL;
int i = 0;
int tmp = 0;
char *sArray = strdup((*list)->string);
tok = strtok(sArray, ",\n ");
while(tok)
{
errno = 0;
tmp = atoi(tok);
if(errno == ERANGE)
{
printf("Error converting string to number\nExiting.");
return;
}
(*list)->arr[i] = tmp;
i++;
tok = strtok(NULL, ",\n ");
}
}
//reverse 'odd' contents of list->array
void reverse_odd(LIST **list, size_t size)
{
int *ptr = &((*list)->arr[0]);
int *tmp = malloc(size * sizeof(*tmp));
memset(tmp, -1, size*sizeof(*tmp));
for(int i=0;i<size;i++)
{
if(ptr[i]%2 != 0)
tmp[size-1-i] = ptr[i];
}
for(int i=0;i<size;i++)
{
if(tmp[i] < 0)
{
while((*ptr)%2 != 0 ) ptr++;
tmp[i] = *ptr;
ptr++;
}
}
memcpy((*list)->arr, tmp, size*sizeof(int));
}
This hope this code will do the job.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct line {
struct num *first;
struct line *next;
} LineNode;
typedef struct num {
int num;
int order;
struct num *next;
} NumNode;
int main() {
FILE *fp;
char ch;
int counter = 0;
NumNode *curr_num, *even_ptr, *odd_ptr, *odd_head, *even_head;
LineNode *curr_line, *line_head;
curr_num = even_head = odd_head = even_ptr = odd_ptr = NULL;
line_head = curr_line = NULL;
fp = fopen("data.txt", "r");
if (fp == NULL)
{
return 1;
}
ch = fgetc(fp);
while(ch != EOF){
if (ch >= 48 && ch <= 57)
{
int n = 0;
while (ch != EOF && ch != '\n' && ch >= 48 && ch <= 57)
{
int x = ch - 48;
n = n * 10 + x;
ch = fgetc(fp);
}
NumNode *node = malloc(sizeof(NumNode));
node->num = n;
node->order = counter;
node->next =NULL;
if (n % 2 == 0){
if(even_head == NULL){
even_head = even_ptr = node;
} else {
even_ptr = even_ptr->next = node;
}
}else{
if(odd_head == NULL){
odd_head = node;
} else {
node->next = odd_head;
odd_head = node;
}
}
counter++;
}
if (ch == '\n' || ch == EOF)
{
NumNode *num_node, *head;
num_node = head = NULL;
even_ptr = even_head;
odd_ptr = odd_head;
counter = 0;
if (even_head != NULL && even_head->order == counter){
head = num_node = even_ptr;
even_ptr = even_ptr->next;
} else {
head = num_node = odd_ptr;
odd_ptr = odd_ptr->next;
}
counter++;
while (even_ptr != NULL)
{
if (even_ptr->order == counter) {
num_node = num_node->next = even_ptr;
even_ptr = even_ptr->next;
}
else if (odd_ptr != NULL) {
num_node = num_node->next = odd_ptr;
odd_ptr = odd_ptr->next;
}
counter++;
}
while (odd_ptr != NULL)
{
num_node = num_node->next = odd_ptr;
odd_ptr = odd_ptr->next;
}
LineNode *node = malloc(sizeof(LineNode));
node->next =NULL;
node->first = head;
if (line_head == NULL)
line_head = curr_line = node;
else
curr_line = curr_line->next = node;
odd_head = even_head = NULL;
counter = 0;
}
ch = fgetc(fp);
}
fclose(fp);
for(curr_line = line_head; curr_line != NULL ; curr_line=curr_line->next) {
for(curr_num = curr_line->first; curr_num != NULL ; curr_num=curr_num->next) {
printf("%d", curr_num->num);
if (curr_num->next != NULL)
printf(",");
}
printf("\n");
}
return 0;
}
I'm working on a small program that will get the user input and then stores that input into a linked list and then finally prints the history of what that user has entered.
So if a user enters the string "hello world" then the program will show
1 hello world
but if the user presses 1 to enter another string "hi everyone" then result should show
1 hello world
2 hi everyone
but my program isn't working correctly, it shows this instead
1 hello world
2 hello world
i think it has to do with fgets because when I manually enter the strings with history i get the correct result
It basically will just repeat the last string the user entered. please help!
my code
#include <stdio.h>
#include <stdlib.h>
int string_length(char* str){
int length = 0;
int i = 0;
for(i = 0; str[i] != '\0'; i++){
length += 1;
}
return length;
}
typedef struct s_Item {
int id;
char* str;
struct s_Item* next;
} Item;
typedef struct s_List {
struct s_Item* root;
} List;
List* init_history(){
List *list = NULL;
list = malloc(sizeof(List));
return list;
}
void add_history(List *list, char *str){
Item *newItem = (Item*)malloc(sizeof(Item*) * 500);
newItem->str = str;
if (list->root == NULL){
newItem->id = 1;
list->root = newItem;
}
else{
Item *history = list->root;
newItem->id = 1;
while (history->next != NULL){
newItem->id += 1;
history = history->next;
}
history->next = newItem;
newItem->id += 1;
}
}
char *get_history(List *list, int id){
Item *node = list -> root;
char *info = "";
while(node!= NULL){
if(node->id ==id){
info= node->str;
return info;
}
node = node->next;
}
return info;
}
void print_history(List* list){
Item* p = list->root;
printf("History: \n");
while(p){
if(p->str)
printf("%d %s \n", p->id, p->str);
p = p->next;
}
}
int main(){
char s[100];
char c = '0';
List *historyList = init_history();
while(1){
printf("type 1 to save string to history, 2 to view history or 3 to quit: \n");
fgets(s, 100, stdin);
size_t ln = string_length(s)-1;
if (s[ln] == '\n')
s[ln] = '\0';
c = *s;
if(c == '3'){
printf("program terminating...\n");
break;
}
else if(c == '2'){
printf("Printing History...\n");
print_history(historyList);
}
else{
printf("Enter string: ");
char buffer[50];
fgets(buffer, 50, stdin);
printf("BUFFER: %s\n", buffer);
//add history
add_history(historyList, buffer);
print_history(historyList);
}
}
}
fgets fills the same buffer each time, so you are storing in your list multiple copies of the same item. the buffer in main. (Consider strdup?)
Also your malloc is over generous. You need to malloc the size of a list (not a pointer).
Item *newItem = (Item*)malloc(sizeof(Item) );
At some point freeing an item in the list will be needed, where you free the string and the pointer to the Item memory.
I am writting a program on doubly linked list with the following data structure:
typedef struct telephoneBookNode {
int id;
char name[NAME_LENGTH];
char telephone[TELEPHONE_LENGTH];
struct telephoneBookNode * previousNode;
struct telephoneBookNode * nextNode;
} TelephoneBookNode;
typedef struct telephoneBookList {
TelephoneBookNode * head;
TelephoneBookNode * tail;
TelephoneBookNode * current;
} TelephoneBookList;
In the following function, I read data from a text file to the linked list, the file content look like this:
/*100, Alice, 0411112222
101, Bob, 0411112222
102, Ali, 0411112223*/
TelephoneBookList * commandLoad(char* fileName) {
TelephoneBookList *(*createList)(TelephoneBookNode*, char[]) = createTelephoneBookList;
char entry[100], *temp1, *temp2;
TelephoneBookList* aList = NULL;
TelephoneBookNode* aNode = NULL;
FILE* telephoneListFile = NULL;
int countEntry = 0;
Boolean check;
telephoneListFile = fopen(fileName, "r");
if (!telephoneListFile)
return NULL;
else {
while (fgets(entry, 100, telephoneListFile)) {
temp2 = strcpy(temp2, entry);
temp1 = strtok(entry, "\n");
check = addressBookEntryCheck(temp1);
if (!check)
return NULL;
else
//here I pass aNode pointer to the below function
aList = (*createList)(aNode, temp2);
}
fclose(telephoneListFile);
printf("printed"); //This line is reached when program complied
return aList;
}
}
This is the function to create the list, problem may be here: it doesnot add new node to the list, it just replaces the first node with the new one. Finally, the linked list only has 1 record which was the last one in text file. How can I fix the code? Thank you!
TelephoneBookList * createTelephoneBookList(TelephoneBookNode* node, char entry[]) {
TelephoneBookList* aList = malloc(sizeof *aList);
TelephoneBookNode* aNode = (TelephoneBookNode*) malloc(sizeof *aNode);
char *tokens;
tokens = strtok(entry, ", ");
aNode->id = atoi(tokens);
tokens = strtok(NULL, ", ");
strcpy(aNode->name, tokens);
tokens = strtok(NULL, ", ");
strcpy(aNode->telephone, tokens); //Just assigning values to a node
//program always go to this block, means `node` is always null
if (node == NULL) {
aNode->nextNode = NULL;
aNode->previousNode = NULL;
node = aNode;
aList->current = node;
aList->head = node;
aList->tail = node;
}
else { //This block is not reached
while (node->nextNode)
node = node->nextNode;
node->nextNode = aNode;
aNode->previousNode = node;
aList->tail = node->nextNode;
}
return aList;
}
This is the function to check entry:
Boolean addressBookEntryCheck(char entry[]) {
char *tokens;
tokens = strtok(entry, ", ");
if(!tokens || strlen(tokens) < 1 || strlen(tokens) > 3)
return FALSE;
else {
if (!isNumber(tokens))
return FALSE;
else {
tokens = strtok(NULL, ", ");
if (!tokens)
return FALSE;
else
{
tokens = strtok(NULL, ", ");
if (!tokens)
return FALSE;
else if (!isNumber(tokens) || strlen(tokens) != 10)
return FALSE;
else
return TRUE;
}
}
}
}
Every time you call
createTelephoneBookList
you create a new list
TelephoneBookList* aList = malloc(sizeof *aList);
You also copy to an uninitialized pointer
temp2 = strcpy(temp2, entry);
I would suggest you create one function to create the list header, one function to add new items e.g.
aList = createList()
while (fgets(entry,sizeof(entry),fp)!=NULL)
{
if (!addEntry(aList,entry))
{
fprintf(stderr, "failed additem item %s\n", entry);
}
}
...
In addEntry parse the string
int id = 0;
char name[NAME_LENGTH];
char telephone[TELEPHONE_LENGTH];
p = strtok(entry, ","); // id
if (p != NULL)
{
id = atoi(p);
p = strtok(NULL, ","); // name, store to temporary string
if (p != NULL )
{
strcpy(name,p);
p = strtok(NULL, ","); // telephone number, store to temporary string
if ( p != NULL )
{
strcpy(telephone,p);
// here you can allocate the new node
}
}
}
// disclaimer omitted checks for length etc which any good program should have. also make sure you have room for \0
if any of the strtok above fail return 0 otherwise allocate a new entry
TelephoneBookNode* aNode = malloc(sizeof(TelephoneBookNode));
aNode->id = id;
strcpy(aNode->name, name);
strcpy(aNode->telephone, telephone);
Then add to your aList
//program always go to this block, means `node` is always null
if (node == NULL) {
....
This is because the caller of the function passed aNode and it never changes within that loop. So it will always pass same value of aNode which is NULL.
I haven't looked at the logic of your code in details, but I think you may want to pass aList->head or rather you already pass aList so just use that.
Given an input, I am trying to build a tree which should grow horizontally applying transformations to that input and the consequent children.
For example, given the input 'aab' and two transformation rules like:
ab -> bba
b -> ba
A tree like this would need to be built:
I have written the code, but the way I have done it, my tree works vertically, and I don't want that. I need it to work horizontally and I fail to see where/how I would write the recursion. Here is what I have right now:
#include <string.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct t_string_node {
struct t_string_node *next;
char *value;
} string_node;
typedef struct t_transformation_rule {
struct t_transformation_rule *next;
char *needle;
char *replacement;
} transformation_rule;
void findTransformations(char *origin, string_node **transformations, char *needle, char *replacement)
{
char *str = origin;
for (char *p = str; *p != '\0'; p++) {
if (strncmp(p, needle, strlen(needle)) == 0) {
char *str_ = malloc(strlen(str)+1+strlen(replacement)-strlen(needle));
strcpy(str_, str);
char *p_ = p - str + str_;
memmove(p_+strlen(replacement), p_+strlen(needle), strlen(p_)+1-strlen(replacement));
memcpy(p_, replacement, strlen(replacement));
//Create new string node.
string_node *transformation;
transformation = malloc(sizeof(string_node));
transformation->value = str_;
transformation->next = NULL;
while (*transformations != NULL) {
transformations = &(*transformations)->next;
}
*transformations = transformation;
}
}
}
int hasTransformation(char *origin, char *target, transformation_rule *list_of_rules)
{
int level;
level = 0;
int found;
string_node *current;
current = malloc(sizeof(string_node));
current->value = origin;
current->next = NULL;
if(list_of_rules == NULL) {
if (strcmp(origin, target) == 0) {
printf("Solution in 0 steps");
return 1;
} else {
printf("No solution");
return 0;
}
}
string_node *transformations;
transformations = NULL;
while (current != NULL) {
findTransformations(current->value, target, &transformations, list_of_rules->needle, list_of_rules->replacement);
findTransformations(current->value, &transformations, list_of_rules->next->needle, list_of_rules->next->replacement);
current = current->next;
}
while (transformations != NULL) {
printf("%s \n", transformations->value);
transformations = transformations->next;
}
return 1;
}
void main()
{
char *input = "aab";
char *target = "bababab";
char *needle = "ab";
char *replacement = "bba";
transformation_rule *list_of_rules;
list_of_rules = NULL;
list_of_rules = malloc(sizeof(transformation_rule));
list_of_rules->needle = "ab";
list_of_rules->replacement = "bba";
list_of_rules->next = NULL;
//Create another rule
transformation_rule *new_rule;
new_rule = malloc(sizeof(transformation_rule));
new_rule->needle = "b";
new_rule->replacement = "ba";
new_rule->next = NULL;
list_of_rules->next = new_rule;
int has_trans;
has_trans = hasTransformation(input, target, list_of_rules);
}
Anybody could help me to realize how would I do this so that the tree grows horizontally instead of vertically?
Thanks
#All: This question is a continuation on THIS question (even using the picture i made).
Now the answer to the depth-first vs breadth-first issue: To to this you should not build a tree-datastructure at all. All you have to care about is the current layer and the next layer.
So you just create one list for each. In the beginning you put your start-string in the current and your next is empty. You then see that you can derive abba and aaba so you put them into next. Then you clear current and put everything from next into current and then clear next.
You keep repeating this until you notice that you are adding your target string to next then you can stop searching.
And: As i said in the answer referenced above: This may not terminate and is indecidable whether it will eventually terminate (Halting-problem), BUT there are many heuristics to detect non-termination in specific cases.
EDIT: Ok, here's the code!
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
struct list_s {
struct list_s* next;
char* entry;
};
char* paste(char* begin, int len1, char* mid, int len2, char* end, int len3) {
char* a = malloc(len1+len2+len3+1);
memcpy(a, begin, len1);
memcpy(a+len1, mid, len2);
memcpy(a+len1+len2, end, len3);
a[len1+len2+len3] = '\0';
return a;
}
void push(struct list_s** top, char* p) {
struct list_s* l = malloc(sizeof(struct list_s));
l->next = *top;
l->entry = p;
*top = l;
}
char* pop(struct list_s** top) {
char* res = (*top)->entry;
struct list_s* next = (*top)->next;
free(*top);
*top = next;
return res;
}
int main() {
char* input = "aab";
// char* target = "bbabaa"; // 11th try
char* target = "abbaa"; // 5th try
// char* target = "bababab";// has no solution
#define cRules 2
char* from[cRules] = {"ab", "b"}; // ab->bba and b->ba
char* to[cRules] = {"bba", "ba"};
struct list_s* current = 0;
struct list_s* nextLayer = 0;
char* inputAlloc = malloc(strlen(input));
strcpy(inputAlloc, input);
push(¤t, inputAlloc);
int counter = 0;
while(current) { // = while not empty
char* cur = pop(¤t);
int lenCur = strlen(cur);
printf("%s:\n", cur);
int iRule=0; for(; iRule<cRules; ++iRule) { // for each rule
char* pos = cur;
for(;;) { // apply the rule wherever it fits
pos = strstr(pos, from[iRule]);
if(!pos) break;
char* mod = paste(
cur, pos-cur,
to[iRule], strlen(to[iRule]),
pos+strlen(from[iRule]),
cur+lenCur-(pos+strlen(from[iRule])) );
printf("->%s\n", mod);
if(!strcmp(mod, target)) {
printf("DONE\n");
return 0;
}
push(&nextLayer, mod);
++pos;
}
}
free(cur);
if(!current) { // next round!
current = nextLayer;
nextLayer = 0;
}
++counter;
// here you can add some of the fail-conditions we talked about
if(counter==100) {
printf("heuristic: no solution\n");
return 0;
}
}
return 0;
}