And yet another unexpected behaviour of my version of ls.
Context: I generate an output list for each directories opened, then add a node to show which directory will be displayed next, as does the original ls.
To handle the -a option, I simply remove all nodes starting with "." when there is no -a option given to my ls. To avoid removing the node showing the directory pathname, I check that the node content doesn't start with "./", nor ".:".
Here's the code :
t_list *ft_rem_hidden(t_list **output)
{
t_list *cursor;
t_list *tmp;
cursor = *output;
while (cursor)
{
tmp = cursor->next;
if (ft_strnequ((char const *)cursor->content, ".:", 2) == 0
&& ft_strnequ((char const *)cursor->content, ".", 1)
&& ft_strnequ((char const *)cursor->content, "./", 2) == 0)
ft_lstfreeone(output, cursor);
cursor = tmp;
}
return (*output);
}
Now the funny part. I checked the (whole) list before the loop, and the first node's content is, as expected ".:"
I checked that said node doesn't pass the if, and as expected, it doesn't.
I checked the list after the while loop, aaaaand the ".:" isn't there anymore.
Here's the code for ft_lstfreeone, although I've been using it for a while without issue, I can't see any other culprit. Well, except my ignorance.
void ft_lstfreeone(t_list **alst, t_list *to_free)
{
t_list *cursor;
t_list *tmp;
if (alst && *alst && to_free)
{
cursor = *alst;
if (cursor == to_free)
{
*alst = cursor->next;
ft_memdel((void **)&cursor->content);
ft_memdel((void **)cursor);
}
else
{
while (cursor && cursor->next && cursor->next != to_free)
cursor = cursor->next;
if (cursor->next == to_free)
{
tmp = cursor->next;
cursor->next = cursor->next->next;
ft_memdel((void **)&cursor->content);
ft_memdel((void **)tmp);
}
}
}
}
Where is my node? That's pretty much all that's keeping me from having a functional ls, and it's rather infuriating. Any hints welcome.
Edit : Some more testing shows that it's only the .: node which is concerned. If I ask my ls to display the content of any other dir, its name shows just fine on the first line.
Edit 2: I created a git repo with the sources for the whole thing, in case someone wants to take a closer look at that. https://github.com/pdecrat/ft_ls
Your code has multiple problems - you aren't actually deleting the nodes themselves because you didn't pass in the address of the pointer to the node.
The reason why ".:" is being deleted is because in ft_lstfreeone you need to ft_memdel tmp->content not cursor->content.
As coded you likely deleted ".:" when you deleted the node after it.
It's also likely why free() fails when you put the & in front of the tmp/cursor ft_memdel calls.
As #TonyLee comments, cursor may point to a freed node, making following cursor a crap-shoot. Why not save cursor->next before the if statement in the main code, and set cursor to it after the if, so that the loop can progress safely whether or not the node gets freed, and avoid taking a chance?
Related
This is a simplified code of my function:
myList* listFilesInDirectory(char* path) {
DIR* dir = opendir(path);
myList* list = createList();
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
myNode* node = createNode(entry->d_name);
addToList(list, node);
}
closedir(dir);
return list;
}
that I use in main function:
myList* sourceFiles = listFilesInDirectory("source/");
myList* destFiles = listFilesInDirectory("dest/");
The problem is that second invocation of function changes elements of list that was returned in first invocation. Elements of sourceFiles become changed after listFilesInDirectory("dest/"); is called.
But when I remove a closedir(dir) from function body, then everything works correctly and elements of sourceFiles are not changed.
I prepared a simple program https://pastebin.com/9pTYmpm2 so you can see what happens.
Example result:
As you see, SourceFiles content 1 and SourceFiles content 2 are different. The first was printed before listFilesInDirectory("dest/") was invoked, and the second was printed after. But if I remove closedir(dir) from function all works correctly:
What is going on here? Why does it happen? How to prevent it? Should I not use closedir() in my programs?
The problem seems to be that you are creating your node with the name straight from entry->d_name. But entry is stack allocated struct which will become invalid once your exit listFilesInDirectory.
An easy fix:
while ((entry = readdir(dir)) != NULL) {
myNode* node = createNode(strdup(entry->d_name));
addToList(list, node);
}
But I suggest you check the return values of everything: opendir, closedir, as well as strdup.
Now, I understand that code below works only for root and its children, but I don't know how to expand it. Every node must have children before passing on "grandchildren". Thank you.
void insert_node(IndexTree **root, Node *node) {
IndexTree *temp = (IndexTree*)malloc(sizeof(IndexTree));
memcpy(&temp->value.cs, node, sizeof(Node));
temp->left = NULL;
temp->right = NULL;
temp->tip=1;
if ((*root) == NULL) {
*root = temp;
(*root)->left = NULL;
(*root)->right = NULL;
}
else {
while (1) {
if ((*root)->right == NULL) {
(*root)->right = temp;
break;
}
else if ((*root)->left == NULL) {
(*root)->left = temp;
break;
}
}
}
Use recursive functions.
Trees are recursive data types (https://en.wikipedia.org/wiki/Recursive_data_type). In them, every node is the root of its own tree. Trying to work with them using nested ifs and whiles is simply going to limit you on the depth of the tree.
Consider the following function: void print_tree(IndexTree* root).
An implementation that goes over all values of the trees does the following:
void print_tree(IndexTree* root)
{
if (root == NULL) return; // do NOT try to display a non-existent tree
print_tree(root->right);
printf("%d\n", root->tip);
print_tree(root->left);
}
The function calls itself, which is a perfectly legal move, in order to ensure that you can parse an (almost) arbitrarily deep tree. Beware, however, of infinite recursion! If your tree has cycles (and is therefore not a tree), or if you forget to include an exit condition, you will get an error called... a Stack Overflow! Your program will effectively try to add infinite function calls on the stack, which your OS will almost certainly dislike.
As for inserting, the solution itself is similar to that of printing the tree:
void insert_value(IndexTree* root, int v)
{
if (v > root->tip) {
if (root->right != NULL) {
insert_value(root->right, v);
} else {
// create node at root->right
}
} else {
// same as above except with root->left
}
}
It may be an interesting programming question to create a Complete Binary Tree using linked representation. Here Linked mean a non-array representation where left and right pointers(or references) are used to refer left and right children respectively. How to write an insert function that always adds a new node in the last level and at the leftmost available position?
To create a linked complete binary tree, we need to keep track of the nodes in a level order fashion such that the next node to be inserted lies in the leftmost position. A queue data structure can be used to keep track of the inserted nodes.
Following are steps to insert a new node in Complete Binary Tree. (Right sckewed)
1. If the tree is empty, initialize the root with new node.
2. Else, get the front node of the queue.
……. if the right child of this front node doesn’t exist, set the right child as the new node. //as per your case
…….else If the left child of this front node doesn’t exist, set the left child as the new node.
3. If the front node has both the left child and right child, Dequeue() it.
4. Enqueue() the new node.
I'm now implementing Barnes-Hut Algorithms for simulating N-body problem. I only want to ask about the building-tree part.
There are two functions I made to build the tree for it.
I recursively build the tree, and print the data of each node while building and everything seems correct, but when the program is back to the main function only the root of the tree and the child of the root stores the value. Other nodes' values are not stored, which is weird since I printed them during the recursion and they should have been stored.
Here's some part of the code with modification, which I thought where the problem might be in:
#include<...>
typedef struct node{
int data;
struct node *child1,*child2;
}Node;
Node root; // a global variable
int main(){
.
set_root_and_build(); // is called not only once cuz it's actually in a loop
traverse(&root);
.
}
Here's the function set_root_and_build():
I've set the child pointers to NULL, but didn't show it at first.
void set_root_and_build(){
root.data = ...;
..// set child1 and child2 =NULL;
build(&root,...); // ... part are values of data for it's child
}
And build:
void build(Node *n,...){
Node *new1, *new2 ;
new1 = (Node*)malloc(sizeof(Node));
new2 = (Node*)malloc(sizeof(Node));
... // (set data of new1 and new2 **,also their children are set NULL**)
if(some condition holds for child1){ // else no link, so n->child1 should be NULL
build(new1,...);
n->child1 = new1;
//for debugging, print data of n->child1 & and->child2
}
if(some condition holds for child2){ // else no link, so n->child2 should be NULL
build(new2,...);
n->child1 = new2;
//for debugging, print data of n->child1 & and->child2
}
}
Nodes in the tree may have 1~2 children, not all have 2 children here.
The program prints out the correct data when it's in build() function recursion, but when it is back to main function and calls traverse(), it fails due to a segmentation fault.
I tried to print everything in traverse() and found that only the root, and root.child1, root.child2 stores the value just as what I've mentioned.
Since I have to called build() several times, and even in parallel, new1 and new2 can't be defined as global variables. (but I don't think they cause the problem here).
Does anyone know where it goes wrong?
The traverse part with debugging info:
void traverse(Node n){
...//print out data of n
if(n.child1!=NULL)
traverse(*(n.child1))
...//same for child2
}
You may not be properly setting the children of n when the condition does not hold. You might want this instead:
void set_root_and_build()
{
root.data = ...;
build(&root,...); // ... part are values of data for it's child
}
void build(Node *n,...)
{
n->child1 = n->child2 = NULL;
Node *new1, *new2;
new1 = (Node*) malloc(sizeof(Node));
new2 = (Node*) malloc(sizeof(Node));
// set data of new1 and new2 somehow (read from stdin?)
if (some condition holds for new1)
{
n->child1 = new1;
build(n->child1,...);
//for debugging, print data of n->child1
}
else
free(new1); // or whatever else you need to do to reclaim new1
if (some condition holds for new2)
{
n->child2 = new2;
build(n->child2,...);
//for debugging, print data of n->child2
}
else
free(new2); // or whatever else you need to do to reclaim new2
}
Of course, you should be checking the return values of malloc() and handling errors too.
Also, your traversal is a bit strange as it recurses by copy rather than reference. Do you have a good reason for doing that? If not, then maybe you want:
void traverse(Node *n)
{
...//print out data of n
if (n->child1 != NULL)
traverse(n->child1)
...//same for child2
}
The problem in your tree traversal is that you certainly process the tree until you find a node pointer which is NULL.
Unfortunately when you create the nodes, these are not initialized neither with malloc() nor with new (it would be initialized with calloc() but this practice in cpp code is as bad as malloc()). So your traversal continues to loop/recurse in the neverland of random pointers.
I propose you to take benefit of cpp and change slightly your structure to:
struct Node { // that's C++: no need for typedef
int data;
struct node *child1,*child2;
Node() : data(0), child1(nullptr), child2(nullptr) {} // Makes sure that every created are first initalized
};
And later get rid of your old mallocs. And structure the code to avoid unnecessary allocations:
if(some condition holds for child1){ // else no link, so n->child1 should be NULL
new1=new Node; // if you init it here, no need to free in an else !!
build(new1,...);
n->child1 = new1;
...
}
if (... child2) { ... }
Be aware however that poitners allocated with new should be released with delete and note with free().
Edit: There is a mismatch in your code snippet:
traverse(&root); // you send here a Node*
void traverse(Node n){ // but your function defines an argument by value !
...
}
Check that you didn't overllok some warnings from the compiler, and that you have no abusive cast in your code.
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;
I've been trying to implement a function in C that deletes a node in a binary tree that should (theoretically) take care of three all cases, i.e.:
Node is a leaf
Node has one child
Node has two children
Is there a way to handle the whole deletion function without checking separately each case? As a commenter below noted I do check for a lot of cases and perhaps the whole problem can be addressed recursively by checking for one fundamental case.
I'm particularly interested in the case where I delete a node within the tree that has a parent and itself is a parent of two children nodes.
Both answers below have been useful but I don't think they address the problem in its entirety.
Here's what I have:
typedef struct Node
{
int key;
int data;
struct Node *left;
struct Node *right;
struct Node *parent;
} Node;
/* functions that take care of inserting and finding a node and also traversing and freeing the tree */
...
void delete(Node *root, int key)
{
Node *target = find(root, key); // find will return the node to be deleted
Node *parent = target->parent; // parent of node to be deleted
// no children
if (target->left == NULL && target->right == NULL)
{
// is it a right child
if (target->key > parent->key)
parent->right = NULL;
// must be a left child
else
parent->left = NULL;
free(target);
}
// one child
else if ((target->left == NULL && target->right != NULL) || (target->left != NULL && target->right == NULL))
{
// here we swap the target and the child of that target, then delete the target
Node *child = (target->left == NULL) ? target->right : target->left;
child->parent = parent;
if (parent->left == target) parent->left = child;
else if (parent->right == target) parent->right = child;
free(target);
}
// two children
else
{
// find the largest node in the left subtree, this will be the node
// that will take the place of the node to be deleted
Node *toBeRepl = max(target->left);
// assign the data of the second largest node
target->key = toBeRepl->key;
target->data = toBeRepl->data;
// if new node immediately to the left of target
if (toBeRepl == target->left)
{
target->left = toBeRepl->left;
Node *newLeft = target->left;
if (newLeft != NULL) newLeft->parent = target;
}
else
{
delete(target->left, toBeRepl->key);
// Node *replParent = toBeRepl->parent;
// replParent->right = NULL;
}
}
I would greatly appreciate your feedback.
edit: Just to clarify, I'm trying to delete a particular node without touching its subtrees (if there are any). They should remain intact (which I've handled by swapping the values of the node to be deleted and (depending on the case) one of the nodes of its substrees).
edit: I've used as a reference the following wikipedia article:
http://en.wikipedia.org/wiki/Binary_search_tree#Deletion
Which is where I got the idea for swapping the nodes values in case of two children, particularly the quote:
Call the node to be deleted N. Do not delete N. Instead, choose either
its in-order successor node or its in-order predecessor node, R.
Replace the value of N with the value of R, then delete R.
There is some interesting code in C++ there for the above case, however I'm not sure how exactly the swap happens:
else //2 children
{
temp = ptr->RightChild;
Node<T> *parent = nullptr;
while(temp->LeftChild!=nullptr)
{
parent = temp;
temp = temp->LeftChild;
}
ptr->data = temp->data;
if (parent!=nullptr)
Delete(temp,temp->data);
else
Delete(ptr->rightChild,ptr->RightChild->data);
}
Could somebody please explain what's going on in that section? I'm assuming that the recursion is of a similar approach as to the users comments' here.
I don't see any "inelegance" in the code, such formatting and commented code is hard to come by. But yes, you could reduce the if-else constructs in your delete function to just one case. If you look at the most abstract idea of what deletion is doing you'll notice all the cases basically boil down to just the last case (of deleting a node with two children).
You'll just have to add a few lines in it. Like after toBeRepl = max(left-sub-tree), check if it's NULL and if it is then toBeRepl = min(right-sub-tree).
So, Case 1 (No children): Assuming your max() method is correctly implemented, it'll return NULL as the rightmost element on the left sub-tree, so will min() on the right sub-tree. Replace your target with the toBeRepl, and you'll have deleted your node.
Case 2 (One child): If max() does return NULL, min() won't, or vice-versa. So you'll have a non-NULL toBeRepl. Again replace your target with this new toBeRepl, and you're done.
Case 3 (Two children): Same as Case 2, only you can be sure max() won't return NULL.
Therefore your entire delete() function would boil down to just the last else statement (with a few changes). Something on the lines of:
Node *toBeRepl = max(target->left);
if toBeRepl is NULL
{
toBeRepl = min(target->right);
}
if toBeRepl is not NULL
{
target->key = tobeRepl->key;
target->data = toBeRepl->data;
deallocate(toBeRepl); // deallocate would be a free(ptr) followed by setting ptr to NULL
}
else
{
deallocate(target);
}
I would do it using recursion, assuming that you have null at the end of your tree, finding null would be the 'go back' or return condition.
One possible algorithm would be:
Node* delete(Node *aNode){
if(aNode->right != NULL)
delete(aNode->right);
if(aNode->left != NULL)
delete(aNode->left);
//Here you're sure that the actual node is the last one
//So free it!
free(aNode);
//and, for the father to know that you're now empty, must return null
return NULL;
}
It has some bugs, for sure, but is the main idea.
This implementation is dfs like.
Hope this helps.
[EDIT] Node *aNode fixed. Forgot the star, my bad.
I finished this a long time ago and I thought it would be good to add a sample answer for people coming here with the same problem (considering the 400+ views this question has accumulated):
/* two children */
else
{
/* find the largest node in the left subtree (the source), this will be the node
* that will take the place of the node to be deleted */
Node* source = max(target->left);
/* assign the data of that node to the one we originally intended to delete */
target->key = source->key;
target->data = source->data;
/* delete the source */
delete(target->left, source->key);
}
Wikipedia has an excellent article that inspired this code.