closedir() causes changes in existing list's nodes - c

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.

Related

C recursively build tree using structure pointer

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.

List node not being freed, still disappears

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?

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.

compiling with a .h file with gcc and a self-sorting list

I've got a little problem with an exercise I have to finish. We have to implement a recurisve "ls" program which prints out the "n" biggest files. But there are some problems.
1)
I have three files, main.c, list.c and list.h. In list.h I have included string.h ,stdio.h,stdlib.h,declared a struct (char* filename,long long filesize and struct element* next) and two methods (append,printlist). In list.c I have included list.h and implemented the two methods append and printlist. In main.c I have included unistd.h,dirent.h, sys/stat.h and list.h.
When I try to compile it with "gcc main.c" I get the error "used of undeclared methods append and printlist" but if I'm using Eclipse it builds just fine. How can I solve this?
Exact errors
/tmp/ccLbHnqR.o: In function `main':
main.c:(.text+0x189): undefined reference to `printliste'
/tmp/ccLbHnqR.o: In function `ftop':
main.c:(.text+0x1f6): undefined reference to `append'
2)
To implement the functionality I tried to use a self-sorting list, i.e. go through the list until the last value that is bigger than the new value, then set the pointer of the new value to the pointer of the last value and the pointer of the last value is the new value.
In theory it should work, but in practice it isn't.
The append methods looks like this
void append(struct element **lst, char* filename, long long filesize){
struct element *newElement;
struct element *lst_iter = *lst;
newElement = malloc(sizeof(*newElement)); // create new element
newElement->filename = filename;
newElement->filesize = filesize;
newElement->next = NULL; // important to find the end of the list
if ( lst_iter != NULL ) { // if elements are existing
//if our element is bigger than the first element
if(lst_iter->filesize < newElement->filesize){
newElement->next = lst_iter;
*lst = newElement;
} else {
while(lst_iter->next != NULL){
if(lst_iter->filesize > newElement->filesize) lst_iter = lst_iter->next;
else break;
}
newElement->next = lst_iter->next;
lst_iter->next = newElement;
}
}
else // if the list is empty our value is the new value
*lst=newElement;
}
I'm using this method from my "ftop" method, which gets a directory, adds every file in this directory to the list and for each directory it calls "ftop" again.
void ftop(char* path){
DIR *dir;
struct dirent *ent;
//open the directory
dir = opendir(path);
if (dir != NULL) {
//for each file/directory in it
while ((ent = readdir(dir)) != NULL) {
struct stat st;
//if it is a file, append it to the list
if(S_ISREG(st.st_mode)){
append(&list, ent->d_name, st.st_size);
} else {
//if it is a directory, use recursion
ftop(ent->d_name);
}
}
}
}
But I don't get it why it isn't working. I know you don't want to do the homework of others, but I would be thankful for every hint you could give me.
P.s.: If you want the full code
main.c
list.c
You want
gcc -o main main.c list.c
that is — specify both files.

How to use free on a handle inside a list?-> C -> windows API

I have a list in C that is something like this:
typedef struct _node
{
int number;
DWORD threadID;
HANDLE threadH;
struct *_node next;
} *node;
And you have somthing like this:
node new_node = malloc(sizeof(node));
As you may have guessed out, this list will store information for threads, including their handlers and Id's. Still I am having trouble when I try to do this:
free(new_node);
Everytime I try to do this I encounter an unexpected error, VS saying that there was a data corruption. I've pinned down as much as possible and I found that the problem resides when I try to use free the handle.
I've searched on MSDN how to do this but the only thing I can find is the function that closes the thread (which is not intended here, since I want the thread to run, just deleting it's record from the list).
The question is: how I am supposed to free an handle from the memory? (Considering that this is only a copy of the value of the handle, the active handle is not being deleted).
EDIT: This is the function to insert nodes from the list:
int insereVisitanteLista(node* lista, DWORD threadID, HANDLE threadH, int num_visitante)
{
node visitanteAnterior;
node novoVisitante = (node)malloc(sizeof(node));
if(novoVisitante == NULL)
return 0;
novoVisitante->threadID = threadID;
novoVisitante->threadH = threadH;
novoVisitante->number = num_visitante;
novoVisitante->next = NULL;
if(*lista == NULL)
{
*lista = novoVisitante;
return 1;
}
visitanteAnterior = *lista;
while(visitanteAnterior->next != NULL)
visitanteAnterior = visitanteAnterior->next;
visitanteAnterior->next =novoVisitante;
return 1;
}
And this is the function to delete nodes:
int removeVisitanteLista(node * lista, DWORD threadID)
{
node visitanteAnterior = NULL, visitanteActual;
if(*lista == NULL)
return 0;
visitanteActual = *lista;
if((*lista)->threadID == threadID)
{
*lista = visitanteActual->next;
visitanteActual->next = NULL;
free(visitanteActual);
return 1;
}
while(visitanteActual != NULL && visitanteActual->threadID != threadID)
{
visitanteAnterior = visitanteActual;
visitanteActual = visitanteActual->next;
}
if (visitanteActual == NULL)
return 0;
visitanteAnterior->next = visitanteActual->next;
free(visitanteActual);
return 1;
}
What exactly is a node that you are trying to free? Is this a pointer to a struct _node? If yes, have you allocated it previously? If no, free is not needed, otherwise you have to check if node is not NULL and make sure you do not free it multiple times. It is hard to guess what you are doing and where is an error without a minimal working example reproducing the problem. The only thing I can suggest is to read about memory management in C. This resource might help.
UPDATE:
node in your code is a pointer to _node. So sizeof (node) is a size of a pointer, which is either 4 or 8 bytes (depending on architecture). So you allocate 8 bytes, for example, but assume you have a pointer to the structure which is much larger. As a result, you corrupt memory, and behavior of the program becomes undefined. So changing node novoVisitante = (node)malloc(sizeof(node)) to node novoVisitante = (node)malloc(sizeof(_node)) should fix the problem.
You haven't shown us the context of your call to free() so I need to speculate a little but my first concern is that you didn't mention removing the node from the list before deleting it.
Start by unlinking the node by modifying the next field of the previous (or head) node. If you still get the error, then you have corrupted memory somehow by writing past the end of one of your allocated memory structures or something similar.
Also, I assume node is a pointer. You really haven't provided much information about what you're doing.

Resources