How to recursively create a string? - c

I'm trying to build a string from a recursive routine, but the program stops when I call my function.
I'm using a dynamic structure to simulate a file manager. I want to show the actual working directory by going back (recursively) in the tree until I find the top and then return the actual name, and then concatenate it with the previous answer.
This is my code:
char *
getPath(lnodo *root, lnodo *actual)
{
char resp[400];
if (actual->pPA) {
strcat(resp, getPath(root, actual));
strcat(resp, "/");
return resp;
}
else {
strcpy(resp, actual->Nom);
strcat(resp, "/");
return resp;
}
}
void
path(lnodo *root, lnodo *actual)
{
printf("%s", getPath(root, actual));
}
The pointer root is the top of the tree. The pointer actual is the working directory. The member Nom of the struct is the name of the actual node, and the member pPA is the pointer to the parent of the actual node.

Related

How do I send the linked list as a function argument

<DBDLinkedList.h>
...
typedef struct _dbDLinkedList
{
Node * head;
Node * tail;
Node * cur;
int numOfData;
} DBDLinkedList;
typedef DBDLinkedList List;
...
<mysourcecode.c>
int main(void)
{
...
List list;
int data;
ListInit(&list);
for(i=0; i<ID_LEN; i++)
LInsert(&list, new_id[i]);
solution(list, data);
...
}
int solution(List list, int data)
{
...
if(LFirst(&list, &data))
{
int i=1;
if(data==46)
LRemove(&list);
i++;
while(LNext(&list, &data))
{
if(i==numOfData)
if(data==46)
LRemove(&list);
i++;
}
}
...
}
I used dummy node doubly linked list.
When I complied this project, error occurred :
‘numOfData’ undeclared (first use in this function).
I'm not used to using Linked list.
How do I send the linked list as a function argument(for solution())?
from what I could see, the problem might not be in sending the linked list as a function argument. In "if(i==numOfData)", you are trying to access the numOfData, which is a part of a 'List' structure, so you need to access it through 'List' variable.... Perhaps replacing that line of code with something like "if(i == list.numOfData)" will do the trick
numOfData is not a variable. You most probably intended to access the current node's numOfData member.
But you really don't need to access that member directly. It seems likely (without seeing the code) that LNext will put that value in your data variable -- it is the reason why you pass &data as argument to LNext.
This brings us to another issue in your code. You call solution with data, but you never gave data a value. If the intention is to remove the node with value 46, then the main program should call solution as follows:
solution(list, 46);
And solution should be implemented as follows:
int solution(List list, int dataToRemove) {
if (!LFirst(&list, &data)) {
return 0; // to indicate that value to delete was not found
}
while (data != dataToRemove) {
if (!LNext(&list, &data)) {
return 0; // to indicate that value to delete was not found
}
}
LRemove(&list);
return 1; // to indicate success
}

Adding one Item to linked list creates two Items?

I'm trying to develop a device to copy files from one USB-drive to another, with both using the FAT-Filesystem. Therefor I use the "Vinculum II" microcontroller by FTDI. The Code is written in C.
To be able to copy all files, I need to know the names of the (sub-)directories on the drive because each of them has to be treated separately. There is a on-chip function to scan the current directory for files and sub-directories ('fat_dirTableFindFirst()' and 'fat_dirTableFindNext()').
I need to store the names of all directories (data type char *) which I received from the scan dynamically. I decided to use a linked-list. I use it like a stack (LIFO).
It's important for understanding the code, so I'll stress it again, that I have to scan each directory separately. So at first, I scan the root directory for its entries. Those ones that are further sub-directorys get pushed onto the stack.
After finishing the scan in the first directory, I grab the upper sub-directory off the stack (pop()). Then, I push the place marker "space" onto the stack, to be able to identify later, that I went into a deeper level/layer of that "directory-tree". If I don't find further directories during a scan, I move back to the last level and so on. Hence the scanning procedure should be similar to preorder traversing of a tree.
It works perfectly if there is max. one sub-directory in each directory. But if there are more than one, I get a confusing error: The first directory is pushed correctly, but all following entries appear twice on the stack! Because of that, the controller copies the same files again and again.
Single stepping through the program doesn't clearify why it happens. The code also writes the content of the stack before and after every push or pop into a .txt file with the same confusing results. It looks a bit like a push()-operation creates two Items, but only if it's called during that do...while loop.
Here's the interesting part of the code. vos_free() und vos_malloc() is equivalent to the usual free() an malloc() calls (ordner is the German word for directory or folder):
struct ordner {
char* data;
struct ordner* next;
};
void push(struct ordner** headRef, char* dirName)
{
struct ordner* newOrdner;
if (newOrdner = vos_malloc(sizeof(struct ordner)) != NULL)
{
newOrdner->data = dirName;
newOrdner->next = *headRef;
*headRef = newOrdner;
}
}
char* pop(struct ordner** headRef)
{
struct ordner* temp;
char* value = " ";
temp = *headRef;
value = *headRef->data; // "save" last element to return it
*headRef = temp->next;
vos_free(temp);
return (value);
}
while(1)
{
file_context_t fileToCopy; // File-Handle
struct ordner dummy;
struct ordner* head = &dummy;
dummy.next = NULL;
dummy.data = begin;
newScan: fat_dirTableFindFirst(fatContext1, &fileToCopy); if(firstRun == 0) // First filename in first scan is the name of the disk, and has to be ignored
{
fat_dirTableFindNext(fatContext1, &fileToCopy);
firstRun = 1;
}
do
{
// if the entry is a Directory, add it to the stack
if (fat_dirEntryIsDirectory(&fileToCopy) == 1)
{
strncpy(nextDir, (char*) &fileToCopy, 11);
push(&head, nextDir);
// The next if-statement usually cannot be true, because there can't be
// two files with the same name in one directory and the different levels/layers
// of sub-directories are separated by a place marker, but actually it becomes
// true (LEDs are flashing because of blink(3))
if (head->data == head->next->data) blink(3);
}
else
{
strncpy(nextFile, (char*) &fileToCopy, 11);
copyFile(fatContext1,fatContext2, nextFile); }
} while (fat_dirTableFindNext(fatContext1, &fileToCopy) == FAT_OK); // perform scan, until all items of the directory were scanned
// then the next (sub-)directory has to be opened to scan it
// there are two possibilities to proceed:
// (1) no directory found ("space" on stack) --> go back to last layer and open & scan the next directory there (if there is another one)
// (2) a new sub-directory was found --> open & scan it
change_layer: if (head != NULL)
{
nextDir = pop(&head); // get next Directory from stack
// Possibility (1)
if (nextDir == space)
{
// move back to last Directory
goto change_layer;
}
// Possibility (2): neue Unterordner gefunden
else
{
push(&head, space); // sign for entering next layer
//...
// open next directory
//...
goto newScan;
}
}
}
} // End while(1)
Can you tell me why it happens that one item appears twice on the stack? Is my Algorithm wrong?
After hours and hours of reasearching and coding I couldn't solve that problem.
Please forgive me my bad programming style with those assembler-like loops and my bad English (I'm from Germany :) )
Thanks in advance
Chris
Here is the declaration of a node for the linked list:
struct ordner {
char* data;
struct ordner* next;
};
So, the data has no storage associated with it. It is simply a pointer.
Then in your loop I do not see you call strdup() to allocate memory for a copy of the filename. You seem to be passing some buffer address directly to push() which saves a copy. This is a mistake.
I recommend that you change push() to call strdup() and save the filename. Then when you free an instance of ordner you must free data, the duplicate string, before you free the ordner instance.
Since in your design pop() also frees memory, you should change pop() so that the caller provides a buffer, and pop() copies the filename to the buffer before freeing the memory of the popped ordner instance.
You don't show where nextDir is declared, but at first glance, this seems likely:
You strncpy a directory name into nextDir. Then, you push this onto the stack. You now have for example an entry with data "dir1" on the stack.
If there is another directory within the same directory, you strncpy the next directory name into the same nextDir buffer, effectively overwriting it. You push it onto the stack. Its data pointer becomes the same nextDir buffer.
Now, both entries have the same data pointer, and the value is the value of the second entry, so the stack looks like "dir2","dir2".
If you want to have a string in each entry on the stack, you need to allocate the memory for each one (make sure you free it eventually though!)
I don't think you can declare variable like this within a while loop. The compiler might give you the same pointer over and over again.
while(1)
{
file_context_t fileToCopy; // File-Handle
struct ordner dummy;
struct ordner* head = &dummy;

Assignment of a pointer within a struct NOT WORKING, why is the value not changing?

For a school project I am supposed to implement a simplified version of the UNIX filesystem using only linked list structures. I am currently having a problem with my mkfs() function, which is supposed to simply initialize a filesystem.
My header file that creates the structures I am using is here:
typedef struct Lines {
char line[82];
struct Lines *next;
} Lines;
typedef struct Node {
char *name;
int id;
struct Node *parent;
struct Node *next;
union {
char line[82];
struct Node *children;
} contents;
} Node;
typedef struct Filesystem {
char *name;
struct Node *root;
struct Node *current;
} Filesystem;
Here is the method in my separate file which #includes this header file:
void mkfs(Filesystem *files) {
Node *root = NULL; /* Creates a pointer to the directory we will use as
* the root directory for this filesystem*/
files = (Filesystem *)malloc(sizeof(*files)); /* Allocates space for the the
* filesystem structure */
if(files == NULL){ /* If there is no memory available, prints error message
* and does nothing else */
printf("Memory allocation failed!\n");
} else {
root = (Node *)malloc(sizeof(*root)); /* Allocates space for the root
* directory of the filesystem. */
if(root == NULL) { /* If there is no memory available, prints error
* message and frees memory obtained thus far, but then
* does nothing else */
printf("Memory allocation failed!\n");
free(files);
} else {
/* Allocates space for the root directory's name string */
root->name= (char *)malloc(sizeof(char)*(strlen("/")+1));
if(root->name == NULL) { /* If there is no memory available, prints error
* message and frees memory obtained thus far,
* but then does nothing else */
printf("Memory allocation failed!\n");
free(files);
free(root);
} else {
root->name = "/"; /* Defines the root directory as being named by the
* forward slash */ /* DO STR CPY HERE ITS CHANGING THE ADDRESS */
root->contents.children = NULL;
root->next = NULL;
root->parent = NULL; /* UHH CHECK ON THIS NOOO CLUE IF ITS RIGHT FUUU*/
files->root = root; /* The filesystems pointer to a directory is set
* to point to the root directory we just allocated
* space for and set up */
files->current = root; /* Sets the filesystems current directory to
* point to the root directory as well, because
* it is the only directory in existence for this
* filesystem at this point. */
}
}
}
}
The problem I am having is that when I run gdb and step through each line, the last two assignment lines ARE NOT CHANGING the contents of file->root and file->current.
For example, here I print the contents of files->root, run the line files->root = root, and then print again, and you can see the address has not changed. However if I just print root, the thing I am trying to assign it to, it clearly has a different value that files->root SHOULD have been set to:
(gdb) print files->root
$12 = (struct Node *) 0x400660
(gdb) step
(gdb) print files->root
$13 = (struct Node *) 0x400660
(gdb) print root
$14 = (Node *) 0x602030
Does anyone have any idea as to why an assignment might not work in this case? This is currently ruining my whole project, so any insight would be greatly appreciated. Thank you!!!
It looks like your mkfs function is accepting a pointer to an already-existing Filesystem and then you are trying to allocate memory for a new Filesystem at a new memory location. There are two common conventions for a function like this: either it accepts no parameters and returns a pointer to a struct, or it accepts a pointer to an already-allocated struct and populates that struct. The reason it appears like the data isn't changing is that you're actually creating and populating a second struct, and leaving the caller's struct unchanged.
Here's an example of the first case, simplifying the function to just the memory allocation part:
Filesystem * mkfs() {
Filesystem *files = (Filesystem *)malloc(sizeof(Filesystem));
// (error handing omitted for brevity)
// populate the files struct as appropriate...
Node *root = (Node *)malloc(sizeof(Node));
files->root = root;
// etc, etc as you currently have
return files;
}
// In this case you should also provide a way for the caller to free a filesystem,
// which will free everything you allocated during mkfs:
void freefs(Filessystem *files) {
// first free any buffers you allocated inside the struct. For example:
free(files->root);
// then free the main filesystem struct
free(files);
}
The caller then deals with this object using these two functions. For example:
int main() {
Filesystem *files = mkfs();
// now "files" is ready to use
freefs(files); // free the objects when we're done with them.
}
Here's an example of the second case, which assumes that the caller already allocated an appropriate buffer, and it just needs to be populated:
void mkfs(Filesystem *files) {
// populate the files struct as appropriate...
Node *root = (Node *)malloc(sizeof(Node));
files->root = root;
// etc, etc as you currently have
}
void freefs(Filesystem *files) {
// still need to clean up all of the ancillary objects
free(files->root);
// etc, etc
}
In this case the calling function has some more work to do. For example:
int main() {
Filesystem *files = (Filesystem *)malloc(sizeof(Filesystem));
mkfs(files);
// now "files" is ready to use
freefs(files); // free the objects when we're done with them.
}
Both patterns are valid; the former is useful if you expect that the caller will need to be able to control how memory is allocated. For example, the caller might decide to allocate the filesystem on the stack rather than the heap:
int main() {
Filesystem files;
mkfs(&files);
// now "files" is ready to use
freefs(&files); // free the ancillary objects when we're done with them.
// "files" is still allocated here, but it's no longer valid
}
The latter takes care of the allocation on behalf of the caller. Since your function allocates further structures on the heap it's necessary to include a cleanup function in both cases.

C standard binary trees

I'm pretty much of a noob in regards to C programming.
Been trying for a few days to create a binary tree from expressions of the form:
A(B,C(D,$))
Where each letters are nodes.
'(' goes down a level in my tree (to the right).
',' goes to the left-side branch of my tree
'$' inserts a NULL node.
')' means going up a level.
This is what I came up with after 2-3 days of coding:
#define SUCCESS 0
typedef struct BinaryTree
{
char info;
BinaryTree *left,*right,*father;
}BinaryTree;
int create(BinaryTree*nodeBT, const char *expression)
{
nodeBT *aux;
nodeBT *root;
nodeBT *parent;
nodeBT=(BinaryTree*) malloc (sizeof(BinaryTree));
nodeBT->info=*expression;
nodeBT->right=nodeBT->left=NULL;
nodeBT->father = NULL;
++expression;
parent=nodeBT;
root=nodeBT;
while (*expression)
{if (isalpha (*expression))
{aux=(BinaryTree*) malloc (sizeof(BinaryTree));
aux->info=*expression;
aux->dr=nodeBT->st=NULL;
aux->father= parent;
nodeBT=aux;}
if (*expression== '(')
{parent=nodeBT;
nodeBT=nodeBT->dr;}
if (*expression== ',')
{nodeBT=nodeBT->father;
nodeBT=nodeBT->dr;}
if (*expression== ')')
{nodeBT=nodeBT->father;
parent= nodeBT->nodeBT;}
if (*expression== '$')
++expression;
++expression;
}
nodeBT=root;
return SUCCESS;
}
At the end, while trying to access the newly created tree, I keep getting "memory unreadable 0xCCCCCC". And I haven't got the slightest hint where I'm getting it wrong.
Any idea ?
Several problems:
You haven't shown us the definition of type nodeBT, but you've declared aux, root, and parent to be pointers to that type.
You then assign aux to point to a BinaryTree even though it's declared to point to a nodeBT.
You assign to aux->dr, which isn't part of BinaryTree, so I can't just assume you typed nodeBT where you meant BinaryTree. You assign to nodeBT->st, that is not a part of BinaryTree either.
You try to return the parsed tree by assigning nodeBT=root. The problem is that C is a “call-by-value” language. This implies that when your create function assigns to nodeBT, it is only changing its local variable's value. The caller of create doesn't see that change. So the caller doesn't receive the root node. That's probably why you're getting your “memory unreadable” error; the caller is accessing some random memory, not the memory containing the root node.
Your code will actually be much easier to understand if you write your parser using a standard technique called “recursive descent”. Here's how.
Let's write a function that parses one node from the expression string. Naively, it should have a signature like this:
BinaryTree *nodeFromExpression(char const *expression) {
To parse a node, we first need to get the node's info:
char info = expression[0];
Next, we need to see if the node should have children.
BinaryTree *leftChild = NULL;
BinaryTree *rightChild = NULL;
if (expression[1] == '(') {
If it should have children, we need to parse them. This is where we put the “recursive” in “recursive descent”: we just call nodeFromExpression again to parse each child. To parse the left child, we need to skip the first two characters in expression, since those were the info and the ( of the current node:
leftChild = nodeFromExpression(expression + 2);
But how much do we skip to parse the right child? We need to skip all the characters that we used while parsing the left child…
rightChild = nodeFromExpression(expression + ???
We don't know how many characters that was! It turns out we need to make nodeFromExpression return not just the node it parsed, but also some indication of how many characters it consumed. So we need to change the signature of nodeFromExpression to allow that. And what if we run into an error while parsing? Let's define a structure that nodeFromExpression can use to return the node it parsed, the number of characters it consumed, and the error it encountered (if there was one):
typedef struct {
BinaryTree *node;
char const *error;
int offset;
} ParseResult;
We'll say that if error is non-null, then node is null and offset is the offset in the string where we found the error. Otherwise, offset is just past the last character consumed to parse node.
So, starting over, we'll make nodeFromExpression return a ParseResult. It will take the entire expression string as input, and it will take the offset in that string at which to start parsing:
ParseResult nodeFromExpression(char const *expression, int offset) {
Now that we have a way to report errors, let's do some error checking:
if (!expression[offset]) {
return (ParseResult){
.error = "end of string where info expected",
.offset = offset
};
}
char info = expression[offset++];
I didn't mention this the first time through, but we should handle your $ token for NULL here:
if (info == '$') {
return (ParseResult){
.node = NULL,
.offset = offset
};
}
Now we can get back to parsing the children.
BinaryTree *leftChild = NULL;
BinaryTree *rightChild = NULL;
if (expression[offset] == '(') {
So, to parse the left child, we just call ourselves recursively again. If the recursive call gets an error, we return the same result:
ParseResult leftResult = nodeFromExpression(expression, offset);
if (leftResult->error)
return leftResult;
OK, we parsed the left child successfully. Now we need to check for, and consume, the comma between the children:
offset = leftResult.offset;
if (expression[offset] != ',') {
return (ParseResult){
.error = "comma expected",
.offset = offset
};
}
++offset;
Now we can recursively call nodeFromExpression to parse the right child:
ParseResult rightResult = nodeFromExpression(expression, offset);
The error case now is a bit more complex if we don't want to leak memory. We need to free the left child before returning the error:
if (rightResult.error) {
free(leftResult.node);
return rightResult;
}
Note that free does nothing if you pass it NULL, so we don't need to check for that explicitly.
Now we need to check for, and consume, the ) after the children:
offset = rightResult.offset;
if (expression[offset] != ')') {
free(leftResult.node);
free(rightResult.node);
return (ParseResult){
.error = "right parenthesis expected",
.offset = offset
};
}
++offset;
We need to set our local leftChild and rightChild variables while the leftResult and rightResult variables are still in scope:
leftChild = leftResult.node;
rightChild = rightResult.node;
}
We've parsed both children, if we needed to, so now we're ready to construct the node we need to return:
BinaryTree *node = (BinaryTree *)calloc(1, sizeof *node);
node->info = info;
node->left = leftChild;
node->right = rightChild;
We have one last thing to do: we need to set the father pointers of the children:
if (leftChild) {
leftChild->father = node;
}
if (rightChild) {
rightChild->father = node;
}
Finally, we can return a successful ParseResult:
return (ParseResult){
.node = node,
.offset = offset
};
}
I've put all the code in this gist for easy copy'n'paste.
UPDATE
If your compiler doesn't like the (ParseResult){ ... } syntax, you should look for a better compiler. That syntax has been standard since 1999 (§6.5.2.5 Compound Literals). While you're looking for a better compiler, you can work around it like this.
First, add two static functions:
static ParseResult ParseResultMakeWithNode(BinaryTree *node, int offset) {
ParseResult result;
memset(&result, 0, sizeof result);
result.node = node;
result.offset = offset;
return result;
}
static ParseResult ParseResultMakeWithError(char const *error, int offset) {
ParseResult result;
memset(&result, 0, sizeof result);
result.error = error;
result.offset = offset;
return result;
}
Then, replace the problematic syntax with calls to these functions. Examples:
if (!expression[offset]) {
return ParseResultMakeWithError("end of string where info expected",
offset);
}
if (info == '$') {
return ParseResultMakeWithNode(NULL, offset);
}

Binary Tree of Strings returning wrong order

I am fairly new to C and have been learning from K&R's book The C Programming Language.
After doing the exercises on Binary trees I wanted to make a header for binary trees for
char*, long and double.
There is a function in the following code that has been giving me grief - it should fill an array of character pointers with the values stored in the tree in lexicographical order however it has a bug somewhere. Here's the code for the String Tree Header btree.h:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/************** TYPES **************/
typedef struct ctree
{
char *name;
ctree *left;
ctree *right;
};
/************** Globals **************/
static int c_inc = 0;
/************** Function Prototypes **************/
ctree *add_to_c_tree (ctree *cnode, char *name);
void print_c_tree (ctree *cnode);
ctree *c_tree_alloc (void);
void c_tree_free (ctree *cnode);
void return_c_tree (ctree *cnode, char **array);
/************** Function Definitions **************/
/* add_to_c_tree() : Adds a new node to a *character binary tree */
ctree *add_to_c_tree (ctree *cnode, char *name){
/* If the node is null, allocate memory for it,
* copy the name and set the internal nodes to null*/
if(cnode == NULL){
cnode = c_tree_alloc();
cnode->name = strdup(name);
cnode->left = cnode->right = NULL;
}
/* If initialised then add to the left node if it is lexographically
* less that the node above it else add it to the right node */
else{
if(strcmp(name, cnode->name) < 0)
cnode->left = add_to_c_tree(cnode->left,name);
else if(strcmp(name, cnode->name) > 0)
cnode->right = add_to_c_tree(cnode->right,name);
}
return cnode;
}
/* print_c_tree() : Print out binary tree */
void print_c_tree(ctree *cnode){
if (cnode != NULL) {
print_c_tree(cnode->left);
printf("%s\n",cnode->name);
print_c_tree(cnode->right);
}
}
/* return_c_tree() : return array of strings containing all values in binary tree */
void return_c_tree (ctree *cnode, char **array){
if (cnode != NULL) {
return_c_tree (cnode->left,array+c_inc);
c_tree_free(cnode->left);
*(array+c_inc++) = strdup(cnode->name);
// printf("arr+%d:%s\n", c_inc-1,*(array+(c_inc-1)));
return_c_tree (cnode->right,array+c_inc);
c_tree_free(cnode->right);
}
}
/* c_tree_alloc() : Allocates space for a tree node */
ctree *c_tree_alloc(void){
return (ctree *) malloc(sizeof(ctree));
}
/* c_tree_free() : Free's Memory */
void c_tree_free (ctree *cnode){
free(cnode);
}
Which I have been testing with bt.c:
#include "btree.h"
int main(void){
ctree *node = NULL; char *arr[100];
node = add_to_c_tree(node, "foo");
node = add_to_c_tree(node, "yoo");
node = add_to_c_tree(node, "doo");
node = add_to_c_tree(node, "woo");
node = add_to_c_tree(node, "aoo");
node = add_to_c_tree(node, "boo");
node = add_to_c_tree(node, "coo");
print_c_tree(node);
return_c_tree(node,arr);
for (int i = 0; i < 7; ++i)
{
printf("%d:%s ..\n",i, arr[i]);
}
return 0;
}
The reason for this question is that I have been having issues with the return_c_tree() function, which is meant to mimic the behaviour of K&R's print_c_tree() function except instead of recursively calling itself until a NULL ptr and printing out the name of the nodes in lexicographical order it is meant to add their names to an array of character ptrs and free the nodes memory.
However the output I get when run as above is:
aoo
boo
coo
doo
foo
woo
yoo
0:aoo ..
1:(null) ..
2:boo ..
3:doo ..
4:foo ..
5:coo ..
6:(null) ..
Which shows that the print function works fine but the return function obviously isn't.
The confusing thing is that if the call to printf() in return_c_tree() is uncommented this is the result:
aoo
boo
coo
doo
foo
woo
yoo
arr+0:aoo
arr+1:boo
arr+2:coo
arr+3:doo
arr+4:foo
arr+5:woo
arr+6:yoo
0:aoo ..
1:(null) ..
2:boo ..
3:doo ..
4:foo ..
5:coo ..
6:(null) ..
Which implies that it actually does add the strings in the right order.
Also I have tried it without the c_inc variable -> ie just incrementing array
before passing it to the right node which the produces the same results from the printf
in return_c_tree() but different from main:
arr+-1:aoo
arr+-1:boo
arr+-1:coo
arr+-1:doo
arr+-1:foo
arr+-1:woo
arr+-1:yoo
0:foo ..
1:yoo ..
2:coo ..
3:(null) ..
4:(null) ..
5:(null) ..
6:(null) ..
I'm rather confused, so If anyone can help I would appreciate it greatly. I'm sure I'm just incrementing it in the wrong place but I can't work out where.
I thought I had finally understood pointers but apparently not.
Best
P
Your problem is how you handle your pointer to array when you recursively call. This will fix your return_c_tree function:
void return_c_tree (ctree *cnode, char **array)
{
if (cnode != NULL) {
return_c_tree (cnode->left,array); // <--- CHANGED 2ND PARAM
c_tree_free(cnode->left);
*(array+c_inc++) = strdup(cnode->name);
return_c_tree (cnode->right,array); // <--- AGAIN, CHANGED 2ND PARAM
c_tree_free(cnode->right);
}
}
You're using a global variable c_inc to keep track of the current index into the array. However, when you recursively called return_c_tree, you passed in array+c_inc, but you did not offset c_inc to account for this. Basically, you double-counted c_inc each time.
While this solves your particular problem, there are some other problems with your code.
In general, using global variables is asking for trouble. There's no need to do it here. Pass c_inc as a parameter to return_c_tree.
Also, mixing global variables with recursion is especially prone to problems. You really want recursive routines to keep their state on the stack.
As a commenter pointed out, all of your code in btree.h should really be in btree.c. The point of header files is to define an interface, not for code.
(This is more stylistic) Your return_c_tree function is really two distinct functions: copy the elements of the tree (in order) into the array, and free the memory used by the tree. These two operations are conceptually distinct: there are times that you'll want to do one and not both. There can be compelling performance (or other) reasons to mix the two, but wait until you have some hard evidence.

Resources