C Program: Create Linked List Using argv, argc, Segmentation Fault - c

I have a program that takes in strings using the command line prompts argv and argc. I keep getting a segmentation fault when I go to run the code and after much researching, I cannot determine what might be causing this. Maybe how I execute the code is the issue? I am using gcc -o code code.c then ./code one two three with one two three being the strings added to the linked list. Any assistance in determining where my error might be would be great.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct list_node_s{
char the_char;
struct list_node_s *next_node;
}list_node;
void insert_node(list_node *the_head, char the_char);
void print_list(list_node *the_head);
int main(int argc, char *argv[]){
char next_char;
list_node *the_head = NULL;
insert_node(the_head, next_char);
the_head->next_node = malloc(sizeof(list_node));
if(the_head == NULL){
return 1;
}
the_head->the_char = 1;
the_head->next_node == NULL;
int the_count, the_count2;
for(the_count = 0; the_count < sizeof(argv); the_count++){
for(the_count2 = 0; argv[the_count][the_count2] != '\0'; the_count2++){
next_char = argv[the_count][the_count2];
insert_node(the_head, next_char);
}
}
print_list(the_head);
return (0);
}
void insert_node(list_node *the_head, char the_char){
list_node * current_node = the_head;
while (current_node->next_node != NULL) {
current_node = current_node->next_node;
}
current_node->next_node = malloc(sizeof(list_node));
current_node->next_node->the_char = the_char;
current_node->next_node->next_node = NULL;
}
void print_list(list_node *the_head){
if(the_head == NULL){
printf("\n");
}else{
printf("%c", the_head->the_char);
print_list(the_head->next_node);
}
}

Change this:
list_node *the_head = NULL;
insert_node(the_head, next_char);
the_head->next_node = malloc(sizeof(list_node));
to:
list_node the_head = { '\0', NULL };
to initialize the_head to an empty node.

One problem is in this function:
void insert_node(list_node *the_head, char the_char){
list_node * current_node = the_head;
while (current_node->next_node != NULL) {
current_node = current_node->next_node;
}
current_node->next_node = malloc(sizeof(list_node));
current_node->next_node->the_char = the_char;
current_node->next_node->next_node = NULL;
}
When you call it in main you're basically passing in NULL because you're setting the_head to NULL. You're trying to access current_node->next_node in the while loop conditions, but because of what you're passing in, you're basically doing NULL->next_node.
You need to initialize your head to an empty list_node. Basically since you're using a char as your node element you could set the value of the char to 0x00, which would make it a zero byte. Then that way you know that when you're at that value, you're at the head.
I don't mean to self-promote, but if you want to look at some code for this have a look at this github repo for the Barry_CS-331 Data Structures class. There's C and C++ in there for the Data Structures. I think it might have a list but if not you can use the stack and the queue as an overall example.

I have modified you code, there has some bugs:
1)、the key bug is in this code.
for(the_count = 0; the_count < sizeof(argv); the_count++)
{
for(the_count2 = 0; argv[the_count][the_count2] != '\0'; the_count2++)
{
next_char = argv[the_count][the_count2];
insert_node(the_head, next_char);
}
}
there some bugs:
you cann't use the_count < sizeof(argv), because of the type of argv is char* []; so sizeof(argv) maybe 4 or 8, based on your os.
the right is:
for(the_count = 1; the_count < argc; the_count++){
for(the_count2 = 0; argv[the_count][the_count2] != '\0'; the_count2++){
next_char = argv[the_count][the_count2];
insert_node(the_head, next_char);
}
}
2、this code aose has some bugs:
list_node *the_head = NULL;
insert_node(the_head, next_char);
the_head->next_node = malloc(sizeof(list_node));
if(the_head == NULL){
return 1;
}
the_head->the_char = 1;
the_head->next_node == NULL;
insert_node(the_head, next_char); is no need, you'd better do the_head->the_char = '\0', because of char 1 is no printable character.

One way:
#include <stdio.h>
#include <stdlib.h>
typedef struct list_node_s{
char the_char;
struct list_node_s *next_node;
}list_node;
void insert_node(list_node *the_head, char the_char);
void print_list(list_node *the_head);
int main(int argc, char *argv[]){
list_node *the_head = NULL;
int the_count, the_count2;
for(the_count = 0; the_count < argc; the_count++)
{
for(the_count2 = 0; the_count2 < strlen(argv[the_count]); the_count2++)
insert_node(&the_head, argv[the_count][the_count2]);
}
print_list(the_head);
return (0);
}
void insert_node(list_node **the_head, char the_char){
list_node *new_node;
list_node *tail_node;
/* Allocate and populate a new node. */
new_node = malloc(sizeof(list_node));
new_node->the_char = the_char;
new_node->next_node = NULL;
/* Is the_head already initialized? */
if(*the_head)
{
/* Yes... find the tail_node. */
tail_node = *the_head;
while(tail_node->next)
tail_node = tail_node->next;
/* Append the new_node to the end of the list. */
tail_node->next = new_node;
return;
}
/* the_head was not initialized. The new_node will be the head node. */
*the_head = new_node;
return;
}
void print_list(list_node *the_head){
if(the_head == NULL){
printf("\n");
}else{
printf("%c", the_head->the_char);
print_list(the_head->next_node);
}
}

Related

Creating a singly linked list from a .txt file and reversing odd numbers of each line in C

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(&current, line);
//convert new->string to integers, place in new->array
parseIntArray(&current);
//reverse 'odd' contents of each array
reverse_odd(&current, 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;
}

Pointer disappeared after passing to some functions (even with malloc)

My problem is that I created a pointer at the bottom Main.
Main will call load() to read input from a dictionary and insert the words in a inputfile into a TRIE *dict by calling insert() and getnode(). However, after load() return true, the *dict lost all of the value and I cannot get what I expected(i.e. showing cat is present as it is in my dictionary input file).
I have read from other websites that pointers can retain its value after doing malloc. So I have malloced for the *dict. Please kindly let me know why the value disappeared.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#define CHAR_TO_INDEX(c) ((int)c - (int)'a')
#define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])
struct dict
{
char words[46];
struct dict* dictPath[26];
bool isEndOfWord;
};
// Returns new trie node (initialized to NULLs)
struct dict *getNode(void)
{
struct dict *pNode = NULL;
pNode = (struct dict *)malloc(sizeof(struct dict));
if (pNode)
{
int i;
for (i = 0; i < 26; i++)
pNode->dictPath[i] = NULL;
}
return pNode;
}
void insert(struct dict *root, const char *key)
{
int level;
int length = strlen(key);
int index;
struct dict *pCrawl = root;
for (level = 0; level < length; level++)
{
index = CHAR_TO_INDEX(key[level]);
if (!pCrawl->dictPath[index])
{
pCrawl = malloc(sizeof(struct dict));
pCrawl->dictPath[index] = getNode();
}
printf("%i\n",index);
pCrawl = pCrawl->dictPath[index];
}
// mark last node as leaf
pCrawl->isEndOfWord = true;
}
// Returns true if key presents in trie, else false
bool search(struct dict *root, const char *key)
{
int level;
int length = strlen(key);
int index;
struct dict *pCrawl = root;
for (level = 0; level < length; level++)
{
index = CHAR_TO_INDEX(key[level]);
if (!pCrawl->dictPath[index])
{
return false;
}
pCrawl = pCrawl->dictPath[index];
}
return (pCrawl != NULL && pCrawl->isEndOfWord);
}
bool load(struct dict *root, char *inputfile){
// open the dictionary file
FILE *infile = fopen(inputfile,"r");
int dictchar;
char tmpword[46];
int cnt = 0;
root = getNode();
// start iterating to read char
do
{
// read the character
dictchar = fgetc(infile);
if (dictchar != '\n')
{
// assign the dictionary character to a tmpword. tmpword will be used to fit into TRIES later
tmpword[cnt] = dictchar;
cnt ++;
}
// if the character is '\n', fit tmpword into TRIES
else
{
tmpword[cnt] = '\0';
cnt = 0;
for (int i = 0; i < ARRAY_SIZE(tmpword); i++)
insert(root, tmpword);
}
} while (dictchar != EOF);
return true;
}
int main (int argc, char *argv[]){
if (argc != 2)
{
return 1;
}
struct dict *root = malloc(sizeof(struct dict));
load(root, argv[1]);
char output[][32] = {"Not present in trie", "Present in trie"};
printf("%s --- %s\n", "cat", output[search(root, "cat")] );
return 0;
}
p.s. I took reference from https://www.geeksforgeeks.org/trie-insert-and-search/
In you function,
bool load(struct dict *root, char *inputfile)
you pass a root pointer, but then replace it with the result of getNode.
The calling code will not see this change.
You need to pass a pointer to the root pointer,
bool load(struct dict **root, char *inputfile)
for the calling code to see the change.
More simply, since you throw away the root with
root = getNode();
right near the top of the function, you could change the load signature:
struct dict * load(char *inputfile)
Instead of return true; at the end, return root; instead.
You don't have a path returning flase anyway.
Change the calling code too.
Instead of
struct dict *root = malloc(sizeof(struct dict));
load(root, argv[1]);
try this:
struct dict *root = load(argv[1]);

C Linked List Head Pointer is changing data value [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I am writing a custom shell for class. I have the shell working but now I need to keep track of which commands are called by the user in a linked list, and then be able to print out these commands in a similar fashion to the history() command. The program seems to build the linked list fine however upon printing out with history(list) I begin to see errors. After several commands are entered the command and string data values for the nodes begin to change. I have checked to make sure that the addresses the pointers are pointing to stay the same, but somehow the data values are being effected.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct Node{
char* command;
char* string;
struct Node *next;
};
struct List{
struct Node* front;
struct Node* rear;
};
void shell_loop(void);
char *read_input(void);
char **split_input(char *input);
struct Node* createNode(char* command, char* string);
struct List* createList();
struct List* add_to_end(struct List *Q, char* command, char* string);
void history(struct List* Q);
const int TOKEN_BUFSIZE = 64;
const char* DELIMITER = " \t\r\n\a";
//#define EXIT_FAILURE
int main(int argc, char **argv)
{
shell_loop();
}
void shell_loop(void)
{
char *input;
char **arguments;
char* command;
char* string;
struct List* list = createList();
for(int i =0; i < 20; i++)
{
printf("User> ");
input = read_input();
arguments = split_input(input);
command = arguments[0];
string = arguments[1];
list = add_to_end(list, command, string);
printf("\n");
history(list);
printf("\n");
free(input);
free(arguments);
}
}
char *read_input(void)
{
char* input;
size_t bufsize = 1000;
getline(&input, &bufsize, stdin);
return input;
}
char **split_input(char *input)
{
int size_of_buffer = TOKEN_BUFSIZE, position = 0;
char **tokens = malloc(size_of_buffer * sizeof(char*));
char *token;
if(!tokens)
{
fprintf(stderr, "shell: allocation error\n");
exit(1); // fix later
}
token = strtok(input, DELIMITER);
while (token != NULL)
{
tokens[position] = token;
position ++;
if(position >= size_of_buffer)
{
size_of_buffer += TOKEN_BUFSIZE;
tokens = realloc(tokens, size_of_buffer * sizeof(char*));
if(!tokens)
{
fprintf(stderr, "shell: allocation error \n");
exit(EXIT_FAILURE); // fix later
}
}
token = strtok(NULL, DELIMITER);
}
tokens[position] = NULL;
return tokens;
}
struct Node* createNode(char* c, char* s)
{
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
temp->command = c;
temp->string = s;
temp->next = NULL;
return temp;
}
struct List* createList()
{
struct List* Q = (struct List*)malloc(sizeof(struct List));
Q->front = NULL;
Q->rear = NULL;
return Q;
}
struct List* add_to_end(struct List *Q, char* c, char* s)
{
struct Node* temp = createNode(c, s);
if(Q->front == NULL)
{
Q->front = temp;
Q->rear = temp;
temp = NULL;
return Q;
}
Q->rear->next = temp;
Q->rear = temp;
temp = NULL;
return Q;
}
void history(struct List* Q)
{
struct Node* current;
if (Q->front == NULL)
{
printf("Command List is empty!\n");
return;
}
current = Q->front;
while(current !=NULL)
{
printf("Command: %s\nString: %s\n", current->command, current->string);
current = current->next;
}
}
I have attached an output file of the history command to highlight how the first entered command eventually changes:
you are just shuffling pointer to stack data around, you need to copy the actual strings
command = strdup(arguments[0]);
string = strdup(arguments[1]);
I think you want temp->string = strdup(s) in createNode(...) instead of temp->string = s
Your call to getline is wrong.
If *lineptr is set to NULL and *n is set 0 before the call, then
getline() will allocate a buffer for storing the line. This buffer
should be freed by the user program. ... Alternatively, before calling getline(), *lineptr can contain a
pointer to a malloc(3)-allocated buffer *n bytes in size
Since *n is 1000 and input is uninitialized (points nowhere), getline assumes there is a buffer of 1000 chars available...which isn't.
Your call should be:
char *read_input(void)
{
char* input= 0;
size_t bufsize = 0;
getline(&input, &bufsize, stdin);
return input;
}
See the comments and other solutions for the other problems of your program.

Linked List program error? In C

Trying to study linked list and tried my program on gcc 4.1.2 on terminal and Xcode.
xcode Error: Thread 1: Exe_BAD_ACCESS(Code=1)
Terminal Error; Segmentation fault
and i have no clue what the xcode error is. for some reason it gives me that same error for some programs that work on other gcc?
Code :
#include <stdio.h>
#include <stdlib.h>
typedef struct node *link;
struct node {int item; link next;};
int main(int argc, const char * argv[]) {
int i;
link t = malloc(sizeof *t);
while ( t != NULL)
{
for ( i = 0; i < 10;i++)
{
t->item = i;
t = t->next;
}
}
int count = 0;
while ( t != NULL)
{
for ( i = 0; i < 10; i++)
{
if (count == 3)
{
printf("%d\n", t->item);
continue;
}
t = t->next;
count++;
}
}
}
You dereferenced t->next, which is allocated via malloc() and not assigned some value, and invoked undefined behavior. You have to allocate buffer for second node and later.
Also you should get the pointer t back before dealing with the list.
#include <stdio.h>
#include <stdlib.h>
typedef struct node *link;
struct node {int item; link next;};
int main(int argc, const char * argv[]) {
int i;
link t = malloc(sizeof *t);
link head = t; /* add this line to get the pointer back */
while ( t != NULL)
{
for ( i = 0; i < 10;i++)
{
t->item = i;
t->next = malloc(sizeof *t); /* add this line */
t = t->next;
}
}
int count = 0;
t = head; /* add this line to get the pointer back */
while ( t != NULL) /* convinated with inner loop, this will lead to infinite loop */
{
for ( i = 0; i < 10; i++) /* you may want to check if t != NULL here for safety */
{
/* not invalid but odd program that print the 4th element again and again */
if (count == 3)
{
printf("%d\n", t->item);
continue;
}
t = t->next;
count++;
}
}
}

Make a tree grow horizontally applying modifications to current node

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(&current, inputAlloc);
int counter = 0;
while(current) { // = while not empty
char* cur = pop(&current);
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;
}

Resources