I'm trying to debug code that - from my understanding - is equivalent to the following...
printf("outside function: %d %d\n", node->ns, node->ns[0]);
function(node->ns);
void function(int *ns) {
printf("inside function: %d %d\n", ns, ns[0]);
}
Output:
outside function: 11532860 1
inside function: 11532860 11532872
Is this expected, or must my interpretation of the code be incorrect? Something fishy with that "11532872".
I solved it! The problem was in the creation of the node structure.
Original version, where function() (from the snippet above) == _contains():
typedef struct TreeNode {
char *word;
int lines;
int *line_numbers;
struct TreeNode *left;
struct TreeNode *right;
} TreeNode;
TreeNode *allocate_tree_node(void) {
return (TreeNode *) malloc(sizeof(TreeNode));
}
TreeNode *create_tree_node(char *word, int line) {
int line_numbers[MAX_LINES_PER_WORD]; // <--- the problem
TreeNode *node = allocate_tree_node();
node->line_numbers = line_numbers; // <--- the problem
*node->line_numbers = line;
node->lines = 1;
node->word = duplicate_string(word);
node->left = node->right = NULL;
return node;
}
int _contains(int *ns, int n, int size) {
int i;
printf("contains: %d %d %d\n", ns, ns[0], *ns);
for (i = 0; i < size; i++) {
printf("line: %d, index: %d, val: %d\n", n, i, ns[i]);
if (ns[i] == n) {
return 1;
}
}
return 0;
}
TreeNode *add_tree(TreeNode *node, char *word, int line) {
int comparison;
if (node == NULL) {
return create_tree_node(word, line);
}
comparison = strcmp(word, node->word);
if (comparison == 0 && !_contains(node->line_numbers, line, node->lines)) {
printf("not contains: %d %d\n", node->line_numbers, node->line_numbers[0]);
node->line_numbers[node->lines] = line;
node->lines++;
}
else if (comparison < 0) {
node->left = add_tree(node->left, word, line);
}
else {
node->right = add_tree(node->right, word, line);
}
return node;
}
Fixed version, using malloc instead of array assignment:
TreeNode *create_tree_node(char *word, int line) {
TreeNode *node = allocate_tree_node();
node->line_numbers = malloc(MAX_LINES_PER_WORD * (sizeof node->line_numbers));
*node->line_numbers = line;
node->lines = 1;
node->word = duplicate_string(word);
node->left = node->right = NULL;
return node;
}
The output is now correct. Would someone mind explaining what happened?
(The code is based on K&R chapter 6, exercise 3).
The original form of your question had two problems:
%d for a pointer. Because of that, it's hard to know for sure what was wrong. Your subsequent edit,
Fixed version, using malloc instead
suggests a reasonable possibility: that you were using the an automatic array outside its scope. That's known in C as undefined behavior, and if that's what was going on, strange values are not surprising.
Further evidence is here:
TreeNode *create_tree_node(char *word, int line) {
int line_numbers[MAX_LINES_PER_WORD]; // <--- the problem
TreeNode *node = allocate_tree_node();
node->line_numbers = line_numbers; // <--- the problem
*node->line_numbers = line;
node->lines = 1;
node->word = duplicate_string(word);
node->left = node->right = NULL;
return node;
}
node->line_numbers is a pointer, and the local variable line_numbers has what's known as automatic storage. (C programmers often refer to automatic variables as being "on the stack", which they sometimes are, but "the stack" is not a C concept.) Like all variables, automatic variables are defined only within their scope. If you take the address of one, and try to use that address outside the variable's scope, the behavior is undefined, and almost always not what you want.
That's the soup you step in when you do this:
int line_numbers[MAX_LINES_PER_WORD];
node->line_numbers = line_numbers;
...
return node;
As you know, in C the name of an array is its address. Your array is line_numbers. You assign its address to a pointer, node->line_numbers.
Once create_tree_node returns, the automatic variable local to create_tree_node, i.e. line_numbers goes out of scope. The compiler at that point is free to re-use the storage it had allocated to to the variable. Yes, you still have its address in node, but sooner than later the compiler is apt to use that space for something else. Sure enough, when you print out the value at that address, you're apt to find something other than what you put there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With