I have a C linked list that looks like this:
typedef struct Node {
struct Node *child;
void *value;
} Node;
typedef struct LinkedList {
Node *head;
} LinkedList;
To test that everything is working properly, I have a main program that reads from a file, line by line, and stores each line in the following Node. Then, once the file reaches its end, I run through the linked list and print all of the lines.
However, when I test it, it only prints blank lines, except for the last line in the file, which gets printed normally. In addition, despite the fact that all the strings are malloc'd before they are stored in the nodes, I get a "pointer being free was not allocated error." I've gone through this pretty extensively in gdb and can't seem to figure out what I'm doing wrong. Perhaps somebody else can help me out here? Here's the rest of my code:
int main(int argc, char **argv) {
if (argc>1) {
FILE *mfile = fopen(argv[1], "r");
if (mfile!=NULL) {
char c;
char *s = (char*) malloc(1);
s[0] = '\0';
LinkedList *lines = (LinkedList*) malloc(sizeof(LinkedList));
while ((c=fgetc(mfile))!=EOF) {
if (c=='\n') {
setNextLine(lines, s);
free(s);
s = (char*) malloc(1);
s[0] = '\0';
}
else s = append(s, c);
}
if (strlen(s)>0) {
setNextLine(lines, s);
free(s);
}
fclose(mfile);
printList(lines);
LLfree(lines);
} else perror("Invalid filepath specified");
} else perror("No input file specified");
return 0;
}
void setNextLine(LinkedList *lines, char *line) {
struct Node **root = &(lines->head);
while (*root!=NULL) root = &((*root)->child);
*root = (Node*) malloc(sizeof(Node));
(*root)->child = NULL;
(*root)->value = line;
}
char *append(char *s, char c) {
int nl = strlen(s)+2;
char *retval = (char*) malloc(nl);
strcpy(retval, s);
retval[nl-2] = c;
retval[nl-1] = '\0';
free(s);
return retval;
}
void printList(LinkedList *lines) {
Node *root = lines->head;
while (root!=NULL) {
char *s = (char*) root->value;
printf("%s \n", s);
root = root->child;
}
}
void LLfree(LinkedList *list) {
if (list->head!=NULL) NodeFree(list->head);
free(list);
return;
}
void NodeFree(Node *head) {
if (head->child!=NULL) NodeFree(head->child);
free(head->value);
free(head);
return;
}
It appears that there are several things that could be changed in the code.
Perhaps the one that is most likely to help would be that memory improperly freed.
Change:
setNextLine(lines, s);
free(s);
s = (char*) malloc(1);
to:
setNextLine(lines, s);
// free(s);
s = (char*) malloc(1);
The pointer 's' is still pointing to what was just assigned to the previous node's 'value'. Hence, calling 'free(s)' is actually freeing the node's 'value'.
Try doing this
void NodeFree(Node *head)
if (head->child!=NULL)
NodeFree(head->child);
free(head->value);
free(head->child);
free(head);
head->value = NULL;
head->child = NULL;
head = NULL;
return;
}
The setNextLine() function is appending the 's' poitner to the node value, and then that same pointer is getting freed after that call in the while loop.
That's why you'll get a double free fault when NodeFree() tries to free head->value.
And the fact that you get the last line could be just because the address pointed by 's' for the last line (which got freed like all the previous lines) is still unused although its not allocated to your pointer anymore.
You should make a copy of the line pointed by 's' in setNextLine() so you can work with the 's' pointer for the rest of lines.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I am writing a custom shell for class. I have the shell working but now I need to keep track of which commands are called by the user in a linked list, and then be able to print out these commands in a similar fashion to the history() command. The program seems to build the linked list fine however upon printing out with history(list) I begin to see errors. After several commands are entered the command and string data values for the nodes begin to change. I have checked to make sure that the addresses the pointers are pointing to stay the same, but somehow the data values are being effected.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct Node{
char* command;
char* string;
struct Node *next;
};
struct List{
struct Node* front;
struct Node* rear;
};
void shell_loop(void);
char *read_input(void);
char **split_input(char *input);
struct Node* createNode(char* command, char* string);
struct List* createList();
struct List* add_to_end(struct List *Q, char* command, char* string);
void history(struct List* Q);
const int TOKEN_BUFSIZE = 64;
const char* DELIMITER = " \t\r\n\a";
//#define EXIT_FAILURE
int main(int argc, char **argv)
{
shell_loop();
}
void shell_loop(void)
{
char *input;
char **arguments;
char* command;
char* string;
struct List* list = createList();
for(int i =0; i < 20; i++)
{
printf("User> ");
input = read_input();
arguments = split_input(input);
command = arguments[0];
string = arguments[1];
list = add_to_end(list, command, string);
printf("\n");
history(list);
printf("\n");
free(input);
free(arguments);
}
}
char *read_input(void)
{
char* input;
size_t bufsize = 1000;
getline(&input, &bufsize, stdin);
return input;
}
char **split_input(char *input)
{
int size_of_buffer = TOKEN_BUFSIZE, position = 0;
char **tokens = malloc(size_of_buffer * sizeof(char*));
char *token;
if(!tokens)
{
fprintf(stderr, "shell: allocation error\n");
exit(1); // fix later
}
token = strtok(input, DELIMITER);
while (token != NULL)
{
tokens[position] = token;
position ++;
if(position >= size_of_buffer)
{
size_of_buffer += TOKEN_BUFSIZE;
tokens = realloc(tokens, size_of_buffer * sizeof(char*));
if(!tokens)
{
fprintf(stderr, "shell: allocation error \n");
exit(EXIT_FAILURE); // fix later
}
}
token = strtok(NULL, DELIMITER);
}
tokens[position] = NULL;
return tokens;
}
struct Node* createNode(char* c, char* s)
{
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
temp->command = c;
temp->string = s;
temp->next = NULL;
return temp;
}
struct List* createList()
{
struct List* Q = (struct List*)malloc(sizeof(struct List));
Q->front = NULL;
Q->rear = NULL;
return Q;
}
struct List* add_to_end(struct List *Q, char* c, char* s)
{
struct Node* temp = createNode(c, s);
if(Q->front == NULL)
{
Q->front = temp;
Q->rear = temp;
temp = NULL;
return Q;
}
Q->rear->next = temp;
Q->rear = temp;
temp = NULL;
return Q;
}
void history(struct List* Q)
{
struct Node* current;
if (Q->front == NULL)
{
printf("Command List is empty!\n");
return;
}
current = Q->front;
while(current !=NULL)
{
printf("Command: %s\nString: %s\n", current->command, current->string);
current = current->next;
}
}
I have attached an output file of the history command to highlight how the first entered command eventually changes:
you are just shuffling pointer to stack data around, you need to copy the actual strings
command = strdup(arguments[0]);
string = strdup(arguments[1]);
I think you want temp->string = strdup(s) in createNode(...) instead of temp->string = s
Your call to getline is wrong.
If *lineptr is set to NULL and *n is set 0 before the call, then
getline() will allocate a buffer for storing the line. This buffer
should be freed by the user program. ... Alternatively, before calling getline(), *lineptr can contain a
pointer to a malloc(3)-allocated buffer *n bytes in size
Since *n is 1000 and input is uninitialized (points nowhere), getline assumes there is a buffer of 1000 chars available...which isn't.
Your call should be:
char *read_input(void)
{
char* input= 0;
size_t bufsize = 0;
getline(&input, &bufsize, stdin);
return input;
}
See the comments and other solutions for the other problems of your program.
I am having some issues with dynamically allocating a string for a node in a tree. I have included my node structure below for reference.
struct node
{
char *string;
struct node *left;
struct node *right;
};
typedef struct node node;
I am supposed to read words from a text file and then store those words into a tree. I am able to store char arrays that have been defined, such as char string[20] without problems, but not strings that are supposed to be dynamically allocated.
I am only going to post the code I am using to read my file and try to create the dynamically allocated array. I have already created the file pointer and checked that it is not NULL. Every time I try to run the program, it simply crashes, do I need to try and read the words character by character?
//IN MAIN
node *p, *root ;
int i;
int u;
root = NULL;
char input[100];
while(fscanf(fp, "%s", &input) != EOF)
{
//Create the node to insert into the tree
p = (node *)malloc(sizeof(node));
p->left = p->right = NULL;
int p = strlen(input); //get the length of the read string
char *temp = (char*) malloc(sizeof(char)*p);
//malloc a dynamic string of only the length needed
strcpy(local, input);
strcpy(p->word,local);
insert(&root, p);
}
To be completely clear, I only want advice regarding the logic of my code, and only would like someone to help point me in the right direction.
You are invoking many undefined behaviors by
passing pointer to object having wrong type to scanf(). i.e. In fscanf(ifp, "%s", &input), char(*)[100] is passed where char* is expected
accessing out-of-range of allocated buffer when storeing terminating null-character in strcpy(local, input);
using value of buffer allocated via malloc() and not initialized in strcpy(curr->word,local);
Your code should be like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef struct node_t {
struct node_t* left, *right;
int count;
char* word;
} node;
void insert(node ** tree, node * item);
int main(void) {
FILE* ifp = stdin;
node * curr, * root;
int i;
int u;
root = NULL;
char input[100];
/* you should specify the maximum length to read in order to avoid buffer overrun */
while(fscanf(ifp, "%99s", input) != EOF)
{
//Create the node to insert into the tree
curr = malloc(sizeof(node));
if(curr == NULL) /* add error check */
{
perror("malloc 1");
return 1;
}
curr->left = curr->right = NULL;
curr->count = 1;
int p = strlen(input); //get the length of the read string
char *local = malloc(sizeof(char)*(p + 1)); /* make room for terminating null-character */
if (local == NULL) /* add error check again */
{
perror("malloc 2");
return 1;
}
//malloc a dynamic string of only the length needed
//To lowercase, so Job and job is considered the same word
/* using strlen() in loop condition is not a good idea.
* you have already calculated it, so use it. */
for(u = 0; u < p; u++)
{
/* cast to unsigned char in order to avoid undefined behavior
* for passing out-of-range value */
input[u] = tolower((unsigned char)input[u]);
}
strcpy(local, input);
curr->word = local; /* do not use strcpy, just assign */
insert(&root, curr);
}
/* code to free what is allocated will be here */
return 0;
}
//Separate insert function
void insert(node ** tree, node * item)
{
if(!(*tree))
{
*tree = item;
return;
}
if(strcmp(item->word,(*tree)->word) < 0)
insert(&(*tree)->left, item);
else if(strcmp(item->word,(*tree)->word) > 0)
insert(&(*tree)->right, item);
/* note: memory leak may occur if the word read is same as what is previously read */
}
I'm trying to improve my knowledge of C.
As an exercise I wrote a stack data structure. Everything works fine if I push N items and then pop N items. The problem occurs when I try to push an item again as the last removed item is still in memory (I think this is a problem).
When I allocate memory for the new path struct, the last removed string is still at the address which was freed after popping a data.
So when a new string is pushed, the last removed and new string are joined.
Can someone please check the following code and tell me what I'm doing wrong. Other comments are also welcome. Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 1000
struct path {
char curPath[N];
struct path *Next;
};
struct MyStack {
struct path *head;
int size;
};
int push(struct MyStack *, char *);
char * pop(struct MyStack *, char *);
int main() {
char path[N];
struct MyStack stack;
stack.head = NULL;
stack.size = 0;
push(&stack, "aaaaaaaaaaaa");
push(&stack, "bbbbbbbbbbbb");
pop(&stack, path);
printf("%s\n", path);
// output is:
// bbbbbbbbbbbb
path[0] = '\0';
push(&stack, "cccccccccccc");
pop(&stack, path);
printf("%s\n", path);
// output should be:
// cccccccccccc
// but it is not
// it is:
// bbbbbbbbbbbbcccccccccccc
return 0;
}
int push(struct MyStack *stack, char *path) {
if (strlen(path) > N) {
return -1;
}
struct path *p = (struct path*)malloc(sizeof(struct path));
if (p == NULL) {
return -1;
}
strcat((*p).curPath, path);
(*p).Next = (*stack).head;
(*stack).head = p;
(*stack).size++;
return 0;
}
char * pop(struct MyStack *stack, char *path) {
if ((*stack).size == 0) {
printf("can't pop from empty stack");
return NULL;
}
struct path *p;
p = (*stack).head;
(*stack).head = (*p).Next;
strcat(path, (*p).curPath);
free(p);
p = NULL;
(*stack).size--;
return path;
}
You are using strcat() in your pop() function. That appends the string that is at stack->head to your char path[]. If you want to replace the string, use strcpy() rather than strcat().
Besides that, though, there are other oddities in your code. You are returning an int from push() and a char* from pop() but you're not assigning those variables to anything in main(), so why are they not void functions?
malloc() does not fill the allocated memory with zeros, so here
struct path *p = (struct path*)malloc(sizeof(struct path));
// ...
strcat((*p).curPath, path);
you append the given string to whatever happens to be in (*p).curPath.
(This could cause a segmentation violation easily.)
Using strcpy() or (perhaps better strlcpy()) should solve the problem.
I'm getting a segmentation fault when I do free() in the delete function of the following linked list implementation. Please take a look and tell me where I am going wrong. When I run this program with valgrind, there is no seg. fault, it runs fine. So I am not able to figure out the problem.
typedef struct node {
char name[100];
int id;
struct node* next;
} Node;
void insert(Node** p, char* _name, int _id)
{
Node *temp, *prev;
temp = malloc(sizeof(struct node));
temp->next = NULL;
strcpy(temp->name,_name);
temp->id = _id;
if(*p == NULL) {
*p = temp;
}
else {
for(prev = *p; prev->next!=NULL; prev=prev->next);
prev->next=temp;
}
}
/* Delete entry
#params p first element
_id ID to delete
*/
void delete_by_id(Node** p, int _id) {
Node *temp, *prev;
prev = NULL;
for(temp = *p; temp!= NULL; prev = temp, temp=temp->next) {
if(temp->id == _id) {
printf("Deleting entry with id: %d\n", temp->id);
if(prev == NULL)
*p = temp->next;
else
prev->next= temp->next;
free(temp);
return;
}
}
}
Here is part of the code from the main program:
Node* p;
int main() {
...
...
buf[rval]=0;
char* tokens = strtok(buf, "+");
char* strArray[5]; /* up-to 5 words can be stored */
int n = 0;
while (tokens)
{
strArray[n] = malloc(strlen(tokens) + 1);
strcpy(strArray[n++], tokens);
tokens = strtok(NULL, "+");
}
int type = 0;
if(strcmp(strArray[0], "1") == 0)
type = 1;
else
type = 2;
char* name = "";
if(type == 1) {
name = strArray[1];
insert(&p, name, clients[i]);
display(&p);
} else {
name = strArray[1];
rval = search(&p, name);
if(rval) {
delete_by_id(&p, rval);
display(&p);
}
}
for (i = 0; i < 5; i++)
{
if (strArray[i]) // check for null data
free(strArray[i]);
}
...
...
}
int search(Node** p, char* _name) {
Node *temp;
for (temp = *p; temp!= NULL; temp = temp->next) {
if (strcmp((char *)temp->name, _name)==0) {
printf("Name matched: %s\n", temp->name);
return temp->id;
}
}
return 0;
}
Valgrind is complaining about the malloc and free used for strArray but not for the linked list.
Print out the addresses returned by malloc(), and also print out the value of temp immediately before the call to free(). Make sure that what's being passed to free() matches what you expect. If somehow you are passing a pointer to free() that didn't come from malloc(), you can encounter problems like you are seeing.
There's also a possibility that the function delete_by_id() is using an invalid pointer. The p parameter is dereferenced before it's checked for NULL. I recommend walking through the function in your debugger and making sure that all of the pointers look as you expect them to look.
Let your program dump core and analyze the core in GDB:
gdb -c yourprog.core yourprog
then do a full backtrace:
(gdb) bt full
This will show you where exactly the reason for your segfault is and what values were passed to the function.
(edit) Oh, and compile your program with the GCC -g switch to have debugging information.
Run your program through valgrind. Segfaults on free are usually due to writes outside of the allocated memory (which overwrites/corrupts the wrappers that the system places before/after allocated memory). Valgrind is usually the easiest way to find out when the writes in question happens.
The folowing program is intended to store words alphabetically in the Binary Search Tree using the strcmp function. The issue, detailed under the program, is that no pointer is passed in the recursive call of the function in the last part of the function.
typedef struct NodT{
char word[30];
struct NodT *left, *right;
} NOD;
void reset_field(NOD *nod){
int i;
for(i=0; i<30; i++){
nod->word[i]='\0';
}
}
void enter_recursively(NOD *nod, char *word){
if(nod==NULL){
nod= (NOD *) malloc(sizeof(NOD));
nod->left=NULL;
nod->right=NULL;
reset_field(nod);
strcpy(nod->word, word);
return;
}
if(nod->word[0]=='\0'){
strcpy(nod->word, word);
return;
}
if(strcmp(nod->word, word)==0) return;
if(strcmp(nod->word, word)<0){
enter_recursively(nod->right, word);//the problem seems to be here
printf("right\n");
}
else{
enter_recursively(nod->left, word);//...and here
printf("left\n");
}
//the NULL pointer is being sent over, which is peculiar
}
The thing is that, when I pass the pointers(left, right) from the structure to the recursive function in the if-else conditions, it takes a NULL value on the other side, which it shouldn't do because they are not NULL after alocating the first word in the root and the second in the right or left depending on strcmp, alocation when malloc is used to create the new storage space for the word.
UPDATE: The new script using double pointers:
typedef struct NodT{
int key;
char word[30];
struct NodT *left, *right;
} NOD;
void enter_recursively(NOD **nod, char *word){
printf("N: %p\n", nod);
printf("NL: %p\n", (**nod).left);
printf("NR: %p\n", (**nod).right);
if(nod==NULL){
nod=malloc(sizeof(NOD));
(**nod).left=NULL;
(**nod).right=NULL;
strcpy((**nod).word, word);
return;
}
if((**nod).word[0]=='\0'){
strcpy((**nod).word, word);
return;
}
if(strcmp((**nod).word, word)==0) return;
if(strcmp((**nod).word, word)<0){
enter_recursively((**nod).right, word);
}
else{
enter_recursively((**nod).left, word);
}
I get segmentation fault and I don't know why.
The problem is that *nod is modified but not returned: Change
void enter_recursively(NOD *nod, char *word)
by
void enter_recursively(NOD **nod, char *word)
in order to return legal pointer. Inside the function, use *nod instead nod, this is the correct way.
When you pass only NOD * to the function, the allocated memory is not stored properly. Is like when you want to modify a int value inside a function, you pass its address, instead the value.
Besides, verify always null pointers before use them. You can obtain a core.
The final code seams like:
void enter_recursively(NOD **nod, char *word){
if (*nod==NULL){
*nod=malloc(sizeof(NOD));
(*nod)->left=NULL;
(*nod)->right=NULL;
strcpy((*nod)->word, word);
return;
}
if((*nod)->word[0]=='\0'){
strcpy((*nod)->word, word);
return;
}
if(strcmp((*nod)->word, word)==0) return;
if(strcmp((*nod)->word, word)<0){
enter_recursively(&(*nod)->right, word);
}
else{
enter_recursively(&(*nod)->left, word);
}
Your enter_recursively() function allocates a node, maybe even assigns to it, but has no way to pass it back to the caller. Find a way to return something useful to the caller.
UPDATE:
for completeness: this is the other way of communicating information from the child back to to its parent: (via the return value)
NOD * enter_recursively(NOD *ptr, char *word){
int rc;
if (ptr==NULL){
ptr = malloc(sizeof *ptr);
ptr->left = NULL;
ptr->right = NULL;
strcpy(ptr->word, word);
return ptr;
}
rc = strcmp(ptr->word, word);
if (rc==0) return ptr;
if (rc < 0){
ptr->right = enter_recursively(ptr->right, word);
fprintf(stderr, "right\n");
}
else {
ptr->left = enter_recursively(ptr->left, word);
fprintf(stderr, "left\n");
}
return ptr; /* not reached */
}