Passing a struct to multiple other functions - c

I'm relatively new to programming and I am having some issues passing my struct to other functions. Here is what my actual code looks like:
typedef struct Memcheck {
char *memoryAdd;
char *file;
int line;
struct Memcheck_struct *next;
} Memcheck;
char *strdup2( char *str )
{
char *new;
new = malloc( strlen(str)+1 );
if (new)
strcpy( new, str );
return new;
}
/*Allocate memory for a ptr, and add it to the top of the linked list*/
void *memcheck_malloc(size_t size, char *file, int line){
Memcheck * new_memoryCheck = NULL;
Memcheck * head = NULL;
head = malloc(sizeof(Memcheck));
new_memoryCheck = malloc(sizeof(Memcheck));
new_memoryCheck->memoryAdd = malloc(sizeof(new_memoryCheck->memoryAdd));
new_memoryCheck->file = malloc(sizeof(new_memoryCheck->file));
new_memoryCheck->file = strdup2(file);
new_memoryCheck->line = line;
new_memoryCheck->next = head;
return new_memoryCheck;
}
/*Prints the error messages*/
void printList(Memcheck *new_memoryCheck) {
Memcheck * head = NULL;
Memcheck * current = head;
head = malloc(sizeof(Memcheck));
current = malloc(sizeof(Memcheck));
printf("new_mem file: %s\n", new_memoryCheck->file);
printf("current file: %s\n", current->file);
while (current != NULL) {
printf("in loop\n");
printf("memcheck error: memory address %p which was allocated in file \"%s\", line %d, was never freed\n", current, current->file, current->line);
current = current->next;
}
}
int memcheck_main(Memcheck new_memoryCheck){
printf("newmem file: %s\n", new_memoryCheck.file);
printf("Entering printList\n");
printList(&new_memoryCheck);
return 0;
}
I have strdup2 because apparently ansi doesn't have stdrup.
I know to use pass by reference to some degree but I'm not exactly sure where to use the * and & operators

Since it appears that you are writing a surrogate for malloc() that records which memory was allocated where, you probably need code similar to:
typedef struct Memcheck Memcheck;
struct Memcheck
{
void *data;
size_t size;
const char *file;
int line;
Memcheck *next;
};
static Memcheck *memcheck_list = 0;
/* Allocate memory and record the allocation in the linked list */
void *memcheck_malloc(size_t size, const char *file, int line)
{
Memcheck *node = malloc(sizeof(*node));
void *data = malloc(size);
if (node == 0 || data == 0)
{
free(node);
free(data);
return 0;
}
node->data = data;
node->size = size;
node->file = file;
node->line = line;
node->next = memcheck_list;
memcheck_list = node;
return data;
}
Note that if either (or both) memory allocations fails, the memory is all freed before returning. Using free() on a null (0) pointer is a no-op. Thus the clean-up is safe. The information can simply be copied into the structure as shown; no need for extra memory allocations for the file name, for example, as long as you pass __FILE__ to the function (which is a string literal, and therefore has a lifetime as long as the rest of the program).

Related

Memory Leak with Copying a Character Pointer

Since strsep is a destructive operation, I want to preserve the contents of the line array, so I make a copy of line and assign it to the variable newline. I then do the destructive operation on newline. I then try to free newline but I am getting a memory leak. I'm not 100% sure, but the memory leak is likely due to newline not being entirely freed. Before, when I performed the strsep operation destructively on line, I did not get the memory leak. I am compiling my C code with fsanitize=address to uncover the memory leak.
struct Item {
char* line;
struct Item *next;
};
struct Item* getArguments(char *line) {
struct Item *current = NULL;
struct Item *next = NULL;
struct Item *first = NULL;
char *found = NULL;
char *newline = strdup(line);
char blank[] = "";
while ((found = strsep(&newline," \n")) != NULL) {
if (strcmp(found, blank) != 0) {
next = malloc(sizeof(struct Item));
next->next = NULL;
next->line = malloc((strlen(found)+1) * sizeof(char));
strcpy(next->line, found);
if (current) {
current->next = next;
}
current = next;
if (first == NULL) {
first = current;
}
}
}
free(found);
free(newline);
newline = NULL;
return first;
}
Changed argument to const char *line as you explicitly don't modify it.
Retain a copy of address returned by strdup(line) for use with free() as strsep() modifies that pointer. Made it a const pointer to be really explicit about it.
Don't free(found).
Minimized scope of variables.
Assignments in a condition is a little hard to read so I changed the loop early return loop construct.
if(!*found) is the same as char blank[] = "": strcmp(found, blank) to check for empty string.
Check the return value of malloc() and strdup() and handle clean-up on failure. This change adds a lot of noisy error handling.
if(current) and if(first == NULL is really just a special case around the first iteration so collapsed those into if-else.
(not fixed) You could replace the malloc() with a calloc() to eliminate the line next->next = NULL.
(not fixed) Consider tweaking the interface to allow caller to differentiate between memory allocation errors and no strings found.
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Item {
char *line;
struct Item *next;
};
void freeArguments(struct Item *first) {
while (first) {
struct Item *tmp = first->next;
free(first->line);
free(first);
first = tmp;
}
}
struct Item *getArguments(const char *line) {
struct Item *first = NULL;
char *const newline = strdup(line);
if(!newline)
goto err;
char *newline2 = newline;
for (struct Item *current = NULL;;) {
char *found = strsep(&newline2," \n");
if(!found)
break;
if (!*found)
continue;
struct Item *next = malloc(sizeof *next);
if(!next)
goto err;
next->line = strdup(found);
if(!next->line)
goto err;
next->next = NULL;
if (first)
current->next = next;
else
first = next;
current = next;
}
free(newline);
return first;
err:
freeArguments(first);
free(newline);
return NULL;
}
int main() {
const char *s = "hello\nworld again";
struct Item *first = getArguments(s);
for (struct Item *current = first; current; current = current->next)
printf("%s\n", current->line);
freeArguments(first);
}
and valgrind seems happy:
==1734409== HEAP SUMMARY:
==1734409== in use at exit: 0 bytes in 0 blocks
==1734409== total heap usage: 8 allocs, 8 frees, 1,108 bytes allocated
==1734409==
==1734409== All heap blocks were freed -- no leaks are possible

How can I free all instances of dynamically allocated memory in this C code

I've written this C code. In the beginning, I used file handing to read a text file and insert every line as a string in a linked list. I need to free all cases of memory allocation in the program in a separate void function. How do I do that? I only included the parts of the code that are relevant because it's a pretty long program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#include <ctype.h>
/*Node of linked list*/
typedef struct node {
char *data;
struct node *next;
} node;
node *start = NULL;
node *current;
typedef enum {
not_tested, found, missed
} state;
/*Appending nodes to linked list*/
void add(char *line) {
node *temp = (node *)malloc(sizeof(node));
temp->data = strdup(line);
temp->next = NULL;
current = start;
if (start == NULL) {
start = temp;
}
else {
while (current->next != NULL) {
current = current->next;
}
current->next = temp;
}
}
/*read text file*/
void readfile(char *filename) {
FILE *file = fopen(filename, "r");
if (file == NULL) {
exit(1);
}
char buffer[512];
while (fgets(buffer, sizeof(buffer), file) != NULL) {
add(buffer);
}
fclose(file);
}
This is not exactly what you're asking for, but I show you how to build a little class that allocates chunks of memory that can bee freed in a single call. This is especially useful when you have lots of small pieces of memory to allocate and therefore to free after usage.
It could seem too many codes for your usage, but note that such a class can be saved in a independent file and reused each time it's needed :
struct Allocator {
void * buffer;
size_t capacity;
size_t usedSize;
};
struct Allocator * newAllocator(size_t initialSize) {
struct Allocator * allocator = malloc(sizeof(*allocator));
if (! allocator) return NULL;
allocator->buffer = malloc(initialSize);
if (! allocator->buffer) { free(allocator); return NULL; }
allocator->capacity = initialSize;
allocator->usedSize = 0;
return allocator;
}
void freeAllocator(struct Allocator * allocator) {
if (!allocator) return;
if (allocator->buffer) free(allocator->buffer);
free(allocator);
}
void * allocate(struct Allocator * allocator, size_t size) {
if (size + allocator->usedSize > allocator->capacity) {
while (size + allocator->usedSize > allocator->capacity) allocator->capacity *= 2;
allocator->buffer = realloc(allocator->buffer, allocator->capacity);
}
void * ptr = allocator->buffer + allocator->usedSize;
allocator->usedSize += size;
return ptr;
}
//-------- END ALLOCATOR
struct node {
//...
};
// How to replace a call to malloc to allocate a node :
void add(struct Allocator *allocator, char *line) {
struct node *temp = allocate(allocator, sizeof(*temp));
//...
}
int main()
{
FILE *file = fopen("myfileName", "r");
if (file == NULL) exit(1);
// Allocates the buffer and as many nodes as needed
struct Allocator *allocator = newAllocator(1024);
char * buffer = allocate(allocator, 512);
while (fgets(buffer, 512, file) != NULL) {
add(allocator, buffer);
}
// Free all allocated memory in a single call
freeAllocator(allocator);
return 0;
}

How to store values with same memory location in c?

If I have a file stream with content
123 1234
1223 124235
21432 325
In my program I read line by line of the file and store the first target of each line into my list. These line with same location and when I run the program it will keep pointing to the most recent data and place it in to list. Which means If I have a function called printL() in while loop. It will print
123/
1223/1223/
21432/21432/21432/
instead of
123/
123/1223/
123/1223/21432
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct n{
char *value;
struct n *next;
} Node;
void printList(Node *head){
Node *cur = head;
while(cur!=NULL){
printf("%s/", cur->value);
cur = cur->next;
}
printf("\n");
}
void insertIntoList(Node **head, char *data){
Node *newNode = malloc(sizeof(Node));
if (newNode == NULL){
perror("Failed to allocate a new node for the linked list");
exit(1);
}
newNode->value = data;
newNode->next = NULL;
Node *currentList = *head;
if(*head == NULL){ //if the linked list head is null, then add the target into linked list
*head = newNode;
}
else{
while(currentList->next!=NULL){
currentList = currentList->next;
}
currentList->next = newNode;
}
}
int main(int argc, char**argv){
FILE *fileStream;
size_t len = 0;
char *line = NULL;
Node *head = NULL;
int j;
for(j=1; j<argc-2;j++){
fileStream = fopen(argv[j], "r");
if(fileStream == NULL){
fprintf(stderr, "could not open");
continue;
}
insertIntoList(&head,"a"); /////////////Line 95
insertIntoList(&head,"b");
insertIntoList(&head,"c");
insertIntoList(&head,"d");
printf("here is a try\n");
printList(head);
while(getline(&line, &len, fileStream)!=EOF){ /////////////Line 101
char *targetNum = strtok(line, " \t\r\n");
printf("*****%s\n", targetNum);
insertIntoList(&head, targetNum);
printf("######print head here is##########\n");
printList(head);
printf("######print head here is##########->\n");
}
//printList(head);
}
return 0;
}
In order to keep the content of each loaded field returned from strtok(), just add a strdup() before calling insertIntoList() after checking if not a null-pointer.
In your code, if you compare the value of both line and targetNum
are the same. If fact, the strtok() function returns a pointer to
the input string and keep the pointer for the next argument.
Replace the following code:
char *targetNum = strtok(line, " \t\r\n");
printf("*****%s\n", targetNum);
insertIntoList(&head, targetNum);
By that one:
char *targetNum = strtok(line, " \t\r\n");
if (targetNum != NULL) {
printf("*****%s\n", targetNum);
insertIntoList(&head, strdup(targetNum));
}
You don't store the contents of the string in your list nodes; you store a pointer to the buffer used for the contents of the string.
Consider changing your list node structure to
typedef struct node Node;
struct node {
Node *next;
char data[];
};
where the contents of the string are stored in the C99 flexible array member.
Your node constructor is then something like
Node *new_node(const char *data)
{
const size_t datalen = (data) ? strlen(data) : 0;
Node *result;
result = malloc(sizeof (Node) + datalen + 1);
if (!result) {
fprintf(stderr, "Out of memory!\n");
exit(EXIT_FAILURE);
}
if (datalen > 0)
memcpy(result->data, data, datalen);
result->next = NULL;
result->data[datalen] = '\0';
return result;
}
See how the function allocates memory for the copy of the data?
Personally, I prefer something like
typedef struct node Node;
struct node {
Node *next;
size_t hash;
size_t size;
char data[];
};
where the size member is basically strlen(data) (except that you can also use the nodes to hold binary data that includes nul bytes \0), and hash is a simple hash computed from data. hash is useful if you intend to compare the entire contents of nodes; if two nodes' lengths or hashes differ, then it is certain their contents differ; if they are the same, then you compare them character by character (memcmp(node1->data, node2->data, node1->length) == 0 if they are the same).
The constructor for the above is something like (using DJB2 hash):
Node *new_node(Node *next, const void *data, const size_t size)
{
Node *result;
result = malloc(sizeof (Node) + size + 1);
if (!result) {
fprintf(stderr, "new_node(): Out of memory (%zu bytes)\n", size);
exit(EXIT_FAILURE);
}
/* Copy and hash data using DJB2 hash (not that good, but fast) */
{
unsigned char *src = (unsigned char *)data;
unsigned char *const end = (unsigned char *)data + size;
unsigned char *dst = result->data;
size_t hash = 5381;
while (src < end) {
hash = hash * 33 + (size_t)(*src);
*(dst++) = *(src++);
}
/* Add terminator */
*dst = '\0';
}
result->next = next;
result->hash = hash;
result->size = size;
return result;
}
These Nodes can also be used in e.g. hash tables, which makes the type quite versatile.

Creating Dynamically Allocated Strings from a file in C

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 */
}

Allocating recently freed memory

I have a struct that I use to build a linked list as below;
struct my_struct{
char a[16];
struct my_struct *next;
}
I free that linked list by below function;
void free_my_list(struct my_struct* recv) {
if (recv->next != NULL)
free_my_list(recv->next);
free(recv);
recv = NULL;
}
In my program, I use a struct _my_list over and over but free and malloc it every time as below:
struct my_struct *_my_list;
free_my_list(_my_list);
_my_list = (my_list *) malloc(sizeof(my_list));
_my_list->next = NULL;
Every time I fill the list, I print char arrays and then reset _my_struct by above code.
Above code works fine on Ubuntu pc, but on Cent OS after printing first list(after first malloc _my_struct) correctly, following list are printed as corrupted data.
When I don't free and malloc memory during whole program execution it works fine in Cent OS too but I should reset list _my_list between printf() calls.
_my_list is filled and printed via below functions;
/*prints every item in my_list*/
void print_my_list(struct my_struct *recv, FILE *fd) {
my_list *tmp;
tmp = recv;
while (tmp != NULL) {
if (fwrite(tmp->a, 1, strlen(tmp->a), fd) == -1) {
pritnf("error\n");
}
tmp = tmp->next;
}
}
/*Add 'a' string to _my_list*/
void add_recv_to_list(struct my_struct **recv_list, char *recv) {
struct my_struct *tmp;
tmp = *recv_list;
if (*recv_list == NULL) {
*recv_list = (struct my_struct *) malloc(sizeof(struct my_struct));
tmp = *recv_list;
} else {
while ((tmp->next) != NULL) {
tmp = tmp->next;
}
tmp->next = (struct my_struct *) malloc(sizeof(struct my_struct));
tmp = tmp->next;
}
strncpy(tmp->a, recv, MAX_NAME_LEN);
tmp->next = NULL;
}
What can be the reason, any ideas?
I think that your problem may start here:
struct my_struct *_my_list;
free_my_list(_my_list);
_my_list = (my_list *) malloc(sizeof(my_list));
_my_list->next = NULL;
When you initialize the struc: struct my_struct *_my_list; you don't assign it any value, so it holds whatever garbage data was in memory beforehand. When you free() that in free_my_list, the behavior is undefined (you are freeing something that you never malloc()ed - so the result may very well be corruption of something or other later on. Try changing your declaration to: struct my_struct *_my_list = NULL; (always a good practice to initialize pointers to NULL, anyway) and changing your free_my_list function to:
void free_my_list(struct my_struct* recv) {
if (recv == NULL)
return;
if (recv->next != NULL)
free_my_list(recv->next);
free(recv);
recv = NULL;
}

Resources