I seem to have created a selfish function which refuses to pass control back to my main function. I've inserted into my code several output statements to ease debugging, and to prove that the program is resting at the end of my 'add_node()' function. I have included the entire program because I am genuinely perplexed as to where the problem may lie.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
/* All-purpose error function */
void kill(char *error)
{
if(errno != 0) {
perror("Error: ");
} else {
printf("%s", error);
}
exit(1);
}
// A link with string data type
typedef struct slink
{
char value[20];
struct node* prev;
struct node* next;
}slink;
// A link with double data type
typedef struct dlink
{
double value;
struct node* prev;
struct node* next;
}dlink;
// Node structure, contains several links
typedef struct node
{
slink name;
dlink weight;
dlink height;
dlink spins; //Place forhead on bat, count spins until fall.
dlink chug; //Open beer, chug. Record time.
}node;
// Creates a new node and populates it with given data arguments
void add_node(char* n, double w, double h, double s, double c)
{
node* this = malloc(sizeof(node));
bzero(this, sizeof(node));
if(!this) kill("Failed to create node.\n");
strncpy(this->name.value, n, 20);
this->weight.value = w;
this->height.value = h;
this->spins.value = s;
this->chug.value = c;
sort_node(this);
printf("returned flow to add_node\n");
}
/*Compares values of this node to the values of all other nodes
and assigns appropriate ptr values to the links*/
int sort_node(node* this)
{
static bool first_sort = true;
static node* head;
if(first_sort){
this->name.prev = NULL;
this->name.next = NULL;
this->weight.prev = NULL;
this->weight.next = NULL;
this->spins.prev = NULL;
this->spins.next = NULL;
this->chug.prev = NULL;
this->chug.prev = NULL;
first_sort = false;
head = this;
printf("first node sorted successfully\n");
} else {
node* current = head;
//Traverse list searching for logical alphabetical neighbors
while(current->name.value < this->name.value) {
if(current->name.next) {
current = current->name.next;
}
}
this->name.next = current;
this->name.prev = current->name.prev;
current->name.prev = this;
}
return 0;
}
int main(void)
{
add_node("Chiis Manly", 195, 66.5, 39, 23);
printf("chiis added");
add_node("Harrie Malaria", 253, 48, 210, 4);
return 0;
}
The output of this program is as follows:
first node sorted successfully
returned flow to add_node
note that 'printf("chiis added");' in my 'main' function is never run. Thank you all greatly for any assistance!
If the following if statement condition is false:
if(current->name.next) {
Then how will your while loop ever terminate? That's your problem.
See this on debugging small programs.
If you add a fflush(stdout); after printf("chiis added"); you'll see that printf is indeed executed and your program gets stuck somewhere else (see #i_am_jorf's answer).
Whatever you pass to printf() is buffered by the standard library to improve the performance of writing to the terminal. You can manually flush the buffer with fflush().
Related
My sort algorithm does not seem to work in some cases. I'm acting on a doubly linked list (with pointer on the previous and next ones). I submit the definition of my structure and the essential. I find myself with a infinite loop, with specific cases like this one. I use strcmp() function, to sort.
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
typedef struct s_file {
char *name;
struct s_file *next;
struct s_file *previous;
} t_file;
void swap_files(t_file *file, t_file *next)
{
t_file *previous;
previous = file->previous;
if (previous)
previous->next = next;
file->next = next->next;
file->previous = next;
if (next->next)
next->next->previous = file;
next->next = file;
next->previous = previous;
}
static t_file *sort_files(t_file *files)
{
t_file *file;
t_file *next;
file = files;
while ((next = file->next))
{
if (strcmp(file->name, next->name) > 0)
{
swap_files(file, next);
if (!next->previous)
files = next;
file = files;
continue;
}
file = file->next;
}
return (files);
}
void debug(t_file *files)
{
while (files)
{
printf("=> %s\n", files->name);
files = files->next;
}
}
int main(void)
{
t_file second;
t_file first;
t_file third;
first.name = "Poire";
first.previous = NULL;
first.next = &second;
second.name = "Banane";
second.previous = &first;
second.next = &third;
third.name = "Fraise";
third.previous = &second;
third.next = NULL;
first = *(sort_files(&first));
debug(&first);
return (0);
}
The swap_files is overly complicated. It's perfectly adequate to just swap the data:
void swap_files(t_file *file, t_file *next)
{
char *tmp = file->name;
file->name = next->name;
next->name = tmp;
}
And guess what? It solved the problem.
It was mentioned two issues with this solution in comments below, and I'd like to address them. First, this code could be less efficient if there are many data fields and second, chances are that you forget a field.
It's very unlikely that this would be the bottleneck, and if it is, deal with it then and not before. And when there is only one field, this code is much more effective. Arguing against a certain method because it would be slower if the circumstances were different is not a good argument.
Forgetting a field is a strong case against this. I have no objections there.
A solution to both above is to create a second struct for the data, like this:
struct data {
char * name;
int age;
char * address;
/* More fields */
}
struct s_file {
struct data *data;
struct s_file *next;
struct s_file *previous;
}
You could argue for or against this. In a way it doesn't "feel like C", but on the other hand you get a nice separation on responsibilities.
You should definitely not overwrite first with the new head node of the list, because doing this causes the list to be corrupted. Just define a pointer to hold it:
t_file *head = sort_files(&first);
debug(head);
Also do not use " for standard header files:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
Finally, even with these fixes, your bubble sort algorithm seems incorrect: when you swap the nodes at file and next, you should backtrack to the previous node just in case the next node was smaller than the previous node too.
Here is a corrected version:
static t_file *sort_files(t_file *head) {
t_file *file;
t_file *next;
file = head;
while ((next = file->next) != NULL) {
if (strcmp(file->name, next->name) > 0) {
swap_files(file, next); // swap the nodes linkage
file = next; // next is now before file
if (file->previous) {
file = file->previous; // backtrack to the previous node
} else {
head = file; // save the new head of list
}
} else {
file = file->next;
}
}
return head;
}
here's my code in C for making of linked list. Its giving runtime error after the while loop gets executed for one time. Plz help me in correcting my code. (totally confused that where's the error.) I am making a head node first and then adding child nodes to it.
#include <stdio.h>
#include <stdlib.h>
typedef struct node nd;
typedef nd *link;
struct node{
int data;
link next;
};
typedef struct {
int size;
link head;
}list;
void create(link temp)
{
link new;
new=(link)malloc(sizeof(nd));
printf("enter data: ");
scanf("%d",new->data);
temp->next=new;
temp=temp->next;
}
list createlist()
{
list sl;
sl.size=0;
sl.head=0;
return sl;
}
int main()
{
list sl;
sl=createlist();
link temp;
temp=sl.head;
char c;
while (1)
{
printf("Add node?: ");
scanf(" %c",&c);
if (c=='y')
{
create(temp);
sl.size++;
}
else
break;
}
return 0;
}
your createlist() function is returning a reference to a local variable that goes out of scope after it returns. You should instead return a heap based value:
list* createlist() {
list* sl = (list*)malloc(sizeof(list));
sl->size=0;
sl->head=0;
return sl;
}
Initially temp points to NULL. temp = sl.head;
In create(temp) temp->next = new;
You are dereferencing a NULL, address 0x0. I get a segmentation fault when I do that.
Need to change the algorithm.
A debugger shows this problem immediately.
You could use a pointer to pointer for temp. It would be easier to read if you didn't use a typedef for a pointer to node. I haven't tested this, but it should be close:
nd ** create(nd **temp)
{
nd *new;
new=(nd *)malloc(sizeof(nd)); /* this cast shouldn't be needed */
printf("enter data: ");
scanf("%d",&(new->data));
new->next = NULL;
*temp = new;
return &(new->next);
}
/* ... */
int main()
{
nd **temp;
temp = &(sl.head);
/* ... */
temp = create(temp);
/* ... */
}
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define n 5
struct node
{
int num;
char *symbol;
char *code;
struct node *left;
struct node *right;
}*root_ptr, *current, *previous;
void form_bst_of_dividing_positions();
void inorderTraversal(struct node *);
int dividing_positions[n], counter = 0;
int main(int argc, char *argv[])
{
//code to populate dividing_positions
//tree structure formation
counter = 0;
root_ptr = malloc(sizeof(struct node));
root_ptr->num = dividing_positions[0];
root_ptr->code = root_ptr->symbol = NULL;
root_ptr->left = root_ptr->right = NULL;
form_bst_of_dividing_positions();
inorderTraversal(root_ptr);
return 0;
}
void form_bst_of_dividing_positions()
{
for(i=1;i<n;i++)
{
if(dividing_positions[i]==-1)
break;
else
{
struct node nodeToAdd;
nodeToAdd.num = dividing_positions[i];
nodeToAdd.code = nodeToAdd.symbol = NULL;
nodeToAdd.left = nodeToAdd.right = NULL;
current = previous = root_ptr;
while(current!=NULL)
{
previous = current;
current = (dividing_positions[i]<(current->num))? current->left : current->right;
}
if(nodeToAdd.num<(previous->num))
previous->left = &nodeToAdd;
else
previous->right = &nodeToAdd;
}
}
}
void inorderTraversal(struct node *no)
{
if(no!=NULL)
{
inorderTraversal(no->left);
printf("%d ", no->num);
inorderTraversal(no->right);
}
}
Above code gives me Segmentation fault .. in Codeblocks the output window prints 4 infinitely. 2, 3, 1, 4 = to be inserted into BST. Ive converted my Java code to C, are there any specifics to be handled in my above code?
Thanks..
Your nodeToAdd is a local variable, its address becomes invalid once you leave that code block. You should use malloc to create new nodes (and free them with free eventually).
Use malloc everytime you add a new node.
The problem is somewhere in here....
char buffer[80];
char *name;
while (1) {
fgets(buffer, 80, inf); //reads in at most 80 char from a line
if (feof(inf)) //this checks to see if the special EOF was read
break; //if so, break out of while and continue with your main
name = (char *) malloc(sizeof(char)*20);
....
name = strtok(buffer, " ");//get first token up to space
stock = newStock(name,...)
....
}
I'm working in C with generic linked lists. I made a list implementation that I've tested and know works with chars. I'm trying to add stocks (I created a stock struct) to the linked list, with each node of the linked list holding a stock struct, but when I finish reading in the stocks all of the nodes point to the same struct and I can't figure out why. Here's some snippets of my code
list *list = malloc(sizeof(list));
newList(list, sizeof(stock_t));
while(1) {
...
(read from file)
...
stock_t *stock;
stock = newStock(name, closes, opens, numshares, getPriceF, getTotalDollarAmountF,getPercentChangeF,toStringF);
addToBack(list, stock);
}
Here's the newStock function:
stock_t *newStock(char *name, float closingSharePrice, float openingSharePrice, int numberOfShares, getPrice getP, getTotalDollarAmount getTotal, getPercentChange getPercent, toString toStr) {
stock_t *stock = malloc(sizeof(stock));
stock->stockSymbol = name;
stock->closingSharePrice = closingSharePrice;
stock->openingSharePrice = openingSharePrice;
stock->numberOfShares = numberOfShares;
stock->getP = getP;
stock->getTotal = getTotal;
stock->getPercent = getPercent;
stock->toStr = toStr;
return stock;
}
In a way I see what's wrong. newStock returns a new pointer every time, but it always gets stored in the variable 'stock' which is what every node points to, so it's going to be equal to whatever the last pointer newStock returned was...but I don't see the way around this. I tried having newStock return just a stock_t, and doing addToBack(list, &stock), but that didn't solve the problem either.
Any help would be appreciated!
Here is some code from the list:
typedef struct node {
void *data;
struct node *next;
}node_t;
typedef struct {
int length;
int elementSize;
node_t *head;
node_t *tail;
} list;
void newList(list *list, int elementSize) {
assert(elementSize > 0);
list->length = 0;
list->elementSize = elementSize;
list->head = list->tail = NULL;
}
void addToBack(list *list, void *element) {
node_t *node = malloc(sizeof(node_t));
node->data = malloc(list->elementSize);
node->next = NULL; //back node
memcpy(node->data, element, list->elementSize);
if (list->length == 0) { //if first node added
list->head = list->tail = node;
}
else {
list->tail->next = node;
list->tail = node;
}
list->length++;
}
Here's code from the stock struct:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef float (*getPrice)(void *S);
typedef float (*getTotalDollarAmount)(void *S);
typedef float (*getPercentChange)(void *S);
typedef char *(*toString)(void *S);
typedef struct stock{
char *stockSymbol;
float closingSharePrice;
float openingSharePrice;
int numberOfShares;
getPrice getP;
getTotalDollarAmount getTotal;
getPercentChange getPercent;
toString toStr;
}stock_t;
The generic functions probably seem like overkill but this is for homework (if you couldn't tell already) so we were asked to specifically use them. I don't think that has anything to do with the problem though.
Here are the definitions for those functions anyway
float getPriceF(void *S) {
stock_t *stock = (stock_t*)S;
return stock->closingSharePrice;
}
float getTotalDollarAmountF(void *S) {
stock_t *stock = (stock_t*)S;
return ((stock->closingSharePrice) * (stock->numberOfShares));
}
float getPercentChangeF(void *S) {
stock_t *stock = (stock_t*)S;
return ((stock->closingSharePrice - stock->openingSharePrice)/(stock->openingSharePrice));
}
char *toStringF(void *S) {
stock_t* stock = (stock_t*)S;
char *name = malloc(20*sizeof(char));
//sprintf(name, "Symbol is: %s. ", (stock->stockSymbol));
return stock->stockSymbol;
}
void printStock(void *S) {
char *str = toStringF(S);
printf("%s \n", str);
}
And this is how I'm traversing the list:
typedef void (*iterate)(void *); //this is in the list.h file, just putting it here to avoid confusion
void traverse(list *list, iterate iterator) {
assert(iterator != NULL);
node_t *current = list->head;
while (current != NULL) {
iterator(current->data);
current = current->next;
}
}
And then in my main I just called
traverse(list, printStock);
I can't find any problems with your code (that would cause your problem, anyway - there are places where you don't check the return from malloc() and stuff like that, but those are not relevant to this question). You don't supply the definition of stock_t, so I made a new data struct, and a new couple of functions, otherwise I just copied and pasted the code you provided:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* Your code starts here */
typedef struct node {
void *data;
struct node *next;
}node_t;
typedef struct {
int length;
int elementSize;
node_t *head;
node_t *tail;
} list;
void newList(list *list, int elementSize) {
assert(elementSize > 0);
list->length = 0;
list->elementSize = elementSize;
list->head = list->tail = NULL;
}
void addToBack(list *list, void *element) {
node_t *node = malloc(sizeof(node_t));
node->data = malloc(list->elementSize);
node->next = NULL; //back node
memcpy(node->data, element, list->elementSize);
if (list->length == 0) { //if first node added
list->head = list->tail = node;
}
else {
list->tail->next = node;
list->tail = node;
}
list->length++;
}
/* Your code ends here */
/* I made a new struct, rather than stock, since you didn't supply it */
struct mydata {
int num1;
int num2;
};
/* I use this instead of newStock(), but it works the same way */
struct mydata * newNode(const int a, const int b) {
struct mydata * newdata = malloc(sizeof *newdata);
if ( newdata == NULL ) {
fputs("Error allocating memory", stderr);
exit(EXIT_FAILURE);
}
newdata->num1 = a;
newdata->num2 = b;
return newdata;
}
/* I added this function to check the list is good */
void printList(list * list) {
struct node * node = list->head;
int n = 1;
while ( node ) {
struct mydata * data = node->data;
printf("%d: %d %d\n", n++, data->num1, data->num2);
node = node->next;
}
}
/* Main function */
int main(void) {
list *list = malloc(sizeof(list));
newList(list, sizeof(struct mydata));
struct mydata * data;
data = newNode(1, 2);
addToBack(list, data);
data = newNode(3, 4);
addToBack(list, data);
data = newNode(5, 6);
addToBack(list, data);
printList(list);
return 0;
}
which outputs this:
paul#MacBook:~/Documents/src$ ./list
1: 1 2
2: 3 4
3: 5 6
paul#MacBook:~/Documents/src$
demonstrating that you have a 3 node list, with all nodes different and where you'd expect them to be.
Either there is some other problem in code you're not showing, or for some reason you are thinking each node points to the same struct when it actually doesn't.
One possibility is that you have a char * data member in your stock struct. It's impossible to tell from the code you provided, but it's possible that you really are creating different nodes, but they all end up pointing to the same name, so they just look like they're the same. If you're assigning a pointer to name, you should make sure it's freshly allocated memory each time, and that you're not just, for instance, strcpy()ing into the same memory and assigning the same address to each stock struct.
EDIT: Looks like that was your problem. This:
name = (char *) malloc(sizeof(char)*20);
....
name = strtok(buffer, " ");
should be:
name = (char *) malloc(sizeof(char)*20);
....
strcpy(name, strtok(buffer, " "));
Right now, you malloc() new memory and store a reference to it in name, but then you lose that reference and your memory when you overwrite it with the address returned from strtok(). Instead, you need to copy that token into your newly allocated memory, as shown.
I have a C program for an exercise and it has a strange issue
The program runs just fine on VS 2005 but it crashes on DEV-C++ and the problem that the problem is that the exercise is always evaluated against DEV-C++
The program is about inserting nodes to a BST and this is where the problem lies...
Well i would really appreciate some help.
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef struct tree_node
{
int value;
int weight;
struct tree_node *left;
struct tree_node *right;
} TREE_NODE;
TREE_NODE *create_tree(int list[], int size);
TREE_NODE *search_pos_to_insert(TREE_NODE *root, int value, int *left_or_right);
// this is the problematic function */
void inorder(TREE_NODE *root); /* Inorder Traversing */
TREE_NODE *temp;
int main()
{
TREE_NODE *root; /* Pointer to the root of the BST */
int values[] = {10, 5, 3, 4, 1, 9, 6, 7, 8, 2}; /* Values for BST */
int size = 10, tree_weight;
root = create_tree(values, 10);
printf("\n");
inorder(root); /* Inorder BST*/
system("PAUSE");
}
TREE_NODE *search_pos_to_insert(TREE_NODE *root, int value, int *left_or_right)
{
if(root !=NULL)
{
temp = root;
if(value >root->value)
{
*left_or_right=1;
*search_pos_to_insert(root->right, value, left_or_right);
}
else
{
*left_or_right=0;
*search_pos_to_insert(root->left, value, left_or_right);
}
}
else
return temp;/* THIS IS THE PROBLEM (1) */
}
TREE_NODE *create_tree(int list[], int size)
{
TREE_NODE *new_node_pntr, *insert_point, *root = NULL;
int i, left_or_right;
/* First Value of the Array is the root of the BST */
new_node_pntr = (TREE_NODE *) malloc(sizeof(TREE_NODE));
new_node_pntr->value = list[0];
new_node_pntr->weight = 0;
new_node_pntr->left = NULL;
new_node_pntr->right = NULL;
root = new_node_pntr;
/* Now the rest of the arrat. */
for (i = 1; i < size; i++)
{
/* THIS IS THE PROBLEM (2) */
insert_point = search_pos_to_insert(root, list[i], &left_or_right);
/* insert_point just won't get the return from temp */
new_node_pntr = (TREE_NODE *) malloc(sizeof(TREE_NODE));
new_node_pntr->value = list[i];
new_node_pntr->weight = 0;
new_node_pntr->left = NULL;
new_node_pntr->right = NULL;
if (left_or_right == 0)
insert_point->left = new_node_pntr;
else
insert_point->right = new_node_pntr;
}
return(root);
}
void inorder(TREE_NODE *root)
{
if (root == NULL)
return;
inorder(root->left);
printf("Value: %d, Weight: %d.\n", root->value, root->weight);
inorder(root->right);
}
Your search_pos_to_insert isn't returning anything in the first section, where root is not NULL. It is recursively calling the function, but not gathering the result. You need to return whatever your recursive calls return to ensure correctness.
You should change the calls
*search_pos_to_insert(root->right, value, left_or_right);
...
*search_pos_to_insert(root->left, value, left_or_right);
to
return search_pos_to_insert(root->right, value, left_or_right);
...
return search_pos_to_insert(root->left, value, left_or_right);
While I haven't delved deep into many issues, are you sure your use of "temp" as a global is correct here? Should it not be local to the search function, so the function is reentrant?
In your function TREE_NODE *search_pos_to_insert() you have code pathes, that don't return a value. Your compiler should issue a warning about it.
The line:
return temp;/* THIS IS THE PROBLEM (1) */
is reached only if the if(root != NULL) evaluates to true.
Replace the recursive calls with:
return search_pos_to_insert(root->right, value, left_or_right);
return search_pos_to_insert(root->left, value, left_or_right);
to make it work.
Frank your the man ..
In some moment i thought that maybe i could return the function itself but i was almost sure it wouldn't work and also i took a different road (to left_or_right) and i was completely lost
Well u saved from a lot of anger and u really saved my day(probably a lot more)