The following code is an example from the NCURSES menu library. I'm not sure what could be wrong with the code, but valgrind reports some problems. Any ideas...
==4803== 1,049 (72 direct, 977 indirect) bytes in 1 blocks are definitely lost in loss record 25 of 36
==4803== at 0x4C24477: calloc (vg_replace_malloc.c:418)
==4803== by 0x400E93: main (in /home/gerardoj/a.out)
==4803==
==4803== LEAK SUMMARY:
==4803== definitely lost: 72 bytes in 1 blocks
==4803== indirectly lost: 977 bytes in 10 blocks
==4803== possibly lost: 0 bytes in 0 blocks
==4803== still reachable: 64,942 bytes in 262 blocks
Source code:
#include <curses.h>
#include <menu.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define CTRLD 4
char *choices[] = {
"Choice 1",
"Choice 2",
"Choice 3",
"Choice 4",
"Choice 5",
"Choice 6",
"Choice 7",
"Exit",
}
;
int main()
{
ITEM **my_items;
int c;
MENU *my_menu;
int n_choices, i;
ITEM *cur_item;
/* Initialize curses */
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
/* Initialize items */
n_choices = ARRAY_SIZE(choices);
my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
for (i = 0; i < n_choices; ++i) {
my_items[i] = new_item(choices[i], choices[i]);
}
my_items[n_choices] = (ITEM *)NULL;
my_menu = new_menu((ITEM **)my_items);
/* Make the menu multi valued */
menu_opts_off(my_menu, O_ONEVALUE);
mvprintw(LINES - 3, 0, "Use <SPACE> to select or unselect an item.");
mvprintw(LINES - 2, 0, "<ENTER> to see presently selected items(F1 to Exit)");
post_menu(my_menu);
refresh();
while ((c = getch()) != KEY_F(1)) {
switch (c) {
case KEY_DOWN:
menu_driver(my_menu, REQ_DOWN_ITEM);
break;
case KEY_UP:
menu_driver(my_menu, REQ_UP_ITEM);
break;
case ' ':
menu_driver(my_menu, REQ_TOGGLE_ITEM);
break;
case 10:
{
char temp[200];
ITEM **items;
items = menu_items(my_menu);
temp[0] = '\0';
for (i = 0; i < item_count(my_menu); ++i)
if(item_value(items[i]) == TRUE) {
strcat(temp, item_name(items[i]));
strcat(temp, " ");
}
move(20, 0);
clrtoeol();
mvprintw(20, 0, temp);
refresh();
}
break;
}
}
unpost_menu(menu);
free_item(my_items[0]);
free_item(my_items[1]);
free_item(my_items[2]);
free_item(my_items[3]);
free_item(my_items[4]);
free_item(my_items[5]);
free_item(my_items[6]);
free_item(my_items[7]);
free_menu(my_menu);
endwin();
}
According to the NCURSES Programming Howto, using the menus library requires the following steps:
Initialize curses
Create items using new_item(). You can specify a name and description for the items.
Create the menu with new_menu() by specifying the items to be attached with.
Post the menu with menu_post() and refresh the screen.
Process the user requests with a loop and do necessary updates to menu with menu_driver.
Unpost the menu with menu_unpost()
Free the memory allocated to menu by free_menu()
Free the memory allocated to the items with free_item()
End curses
From what I can tell from your code:
You don't unpost the menu (which might cause a leak, or it might just risk garbling the screen).
The menu is freed after the items are freed (which I guess may or may not be a problem depending on how ncurses is implemented).
Only items 0 and 1 of the 8-element array of items are freed. This is probably a leak.
The my_items array of pointers is never freed. This is certainly a leak.
As #lh3 said, compiling with the -g option will let Valgrind give the line number of lost memory.
Edit (in response to your comment): my_items is a dynamically allocated array of pointers to dynamically created menu items. In other words, you have one block of dynamic memory, and it contains a bunch of pointers to a bunch of dynamically allocated ncurses structures (menu items). So, to clean up once you're done, you need to free each of the dynamically allocated ncurses structures, and then you need to free the block of memory that held the pointers to those structures.
In other words, every calloc or malloc needs a free, every new_item needs a free_item, and so on.
for (i = 0; i < n_choices; ++i) {
free_item(my_items[i]);
}
free(my_items);
Something to note with Valgrind (this comes up on the Valgrind user's mailing list often):
still reachable: 64,942 bytes in 262 blocks
This is just referencing blocks that were still reachable in main() at exit, which (under any modern kernel) would just be reclaimed by the OS anyway.
While its good practice to explicitly free() every single allocated block before exit is called, this is not technically leaked memory, since it still could be reached at the time of exit.
Focus on directly, indirectly and possibly lost blocks as Josh Kelly has suggested. This is just a supplement to the answers that have already pointed out the likely sources of leaks.
try running valgrind with --leak-check=full maybe?
free_item(my_items[7]);
free(my_items);
Related
Update:
Removing the print statement (line 52) entirely with all else the same as in the code below gave me 0 errors. The errors exist within my functions when printing (using philo[i]) and in this print statement (added for debugging), but do not exist if I run the entire program with no prints. Any ideas what I'm doing wrong???
Thank you for the help so far. I have made a couple of changes based on comments received so far.
***** Original (Edited) Question *****
I can't figure out why I have been getting this error, "Uninitialised value was created by a stack allocation". I started with a completed program that works fine, but gives me a ton of uninitialized value errors. I have traced the problem down to a few lines of code by excluding all functions and adding additional print statements. This code is to solve the dining philosopher's problem using threads (homework), so I don't want to post too much. My code is now:
#include <all needed header files>
#define NUM_PHIL 5
#define MIN_EAT_TIME 10
pthread_t philosopher[NUM_PHIL]; // array to hold IDs for philosopher threads
pthread_mutex_t chopstick[NUM_PHIL]; // array to hold IDs for chopstick mutexes (locks)
// function definitions here:
int philosopherFun(int *philo);
// All others have been bypassed at the time of my current problem
int main(int argc, char *argv[]) {
int phil[NUM_PHIL]; // Philosopher numbers ("names")
for(int i = 0; i < NUM_PHIL; i++) {
phil[i] = i + 1;
}
for(int i = 0; i < NUM_PHIL; i++) {
// Print statement causes valgrind error to exist (as does calling a function using phil)
printf("Value phil[%d] = %d\n", i, phil[i]);
}
// Initilize mutexes for chopsticks, report error as needed
for(int i = 0; i < NUM_PHIL; i++) {
if(pthread_mutex_init( stuff here) < 0) {
// error reporting
// print statement uses i
}
}
for(int i = 0; i < NUM_PHIL; i++) {
if(pthread_create(&philosopher[i], NULL, (void*) philosopherFun, (void*) &phil[i] ) != 0) {
// error reporting
// print statement uses phil[i]
}
}
/* Code omitted as this is Homework */
// Join threads created for philosophers (using pthread_join)
// error reporting
// print statement uses phil[i]
// Destroy chopstick mutexes when done. (using pthread_mutex_destroy)
// error reporting
// print statement uses i
printf("The philosophers have all finished eating and its time for bed. Goodnight...\n");
return 0;
}
int philosopherFun(int *philo) {
return 0;
}
Program output:
Value phil[0] = 1
Value phil[1] = 2
Value phil[2] = 3
Value phil[3] = 4
Value phil[4] = 5
The philosophers have all finished eating and its time for bed. Goodnight...
My Valgrind errors are:
==46556== HEAP SUMMARY:
==46556== in use at exit: 0 bytes in 0 blocks
==46556== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==46556==
==46556== All heap blocks were freed -- no leaks are possible
==46556==
==46556== ERROR SUMMARY: 10 errors from 1 contexts (suppressed: 0 from 0)
==46556==
==46556== 10 errors in context 1 of 1:
==46556== Conditional jump or move depends on uninitialised value(s)
==46556== at 0x7FFF205A395F: ??? (in /dev/ttys000)
==46556== by 0x7FFF2046FFFA: ??? (in /dev/ttys000)
==46556== by 0x7FFF20478CF0: ??? (in /dev/ttys000)
==46556== by 0x7FFF2049D8B8: ??? (in /dev/ttys000)
==46556== by 0x7FFF20475EF5: ??? (in /dev/ttys000)
==46556== by 0x7FFF20474061: ??? (in /dev/ttys000)
==46556== by 0x1000038CD: main (philo.c:52)
==46556== Uninitialised value was created by a stack allocation
==46556== at 0x7FFF20475FDF: ??? (in /dev/ttys000)
==46556==
==46556== ERROR SUMMARY: 10 errors from 1 contexts (suppressed: 0 from 0)
line 52 is my print statement:
printf("Value phil[%d] = %d\n", i, phil[i]);
which I believe accounts for 5 errors (phil[0] - phil[4]) and I call philosopherFun in my pthread_create on line 68 (this line of code included), again accounting for 5 errors (1 for each thread). This function is currently only returning on the first line, so none of the rest of my program is involved (though I started with 50-250 errors depending on my parameters and which functions I excluded).
I feel like my int array (int phil[]) is causing the problem, but it is immediately initialized, so I'm not sure how this is happening. Please help!
Thanks,
Kristine
Edited... Added some comments from omitted code- Threads are joined and mutexes destroyed
I also tried making int phil[NUM_PHIL] global by declaring it outside of my main function, but this made no change to the errors returned by Valgrind. defining phil[5] = {1, 2, 3, 4, 5}; as a global also didn't help.
I believe this is where your problem comes from:
int phil[NUM_PHIL];
and here
if(pthread_create(&philosopher[i], NULL, (void*) philosopherFun, (void*) &phil[i] ) != 0) {
more code ...
}
You're referencing a stack-allocated object (you're getting a pointer to the elements of the philo array). When the main function returns, the memory will be deleted and the other threads will still be holding on to garbage. To be sure this is the problem, move your philo array to a global scope, or allocate the array on the heap instead.
I am working on a function which allocates memory into an array, and then I free it later. Oddly enough, valgrind is giving me this error:
==93== HEAP SUMMARY:
==93== in use at exit: 11,160 bytes in 2,232 blocks
==93== total heap usage: 44,310 allocs, 42,078 frees, 1,632,230 bytes allocated
==93==
==93== 11,160 bytes in 2,232 blocks are definitely lost in loss record 1 of 1
==93== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==93== by 0x10976F: FillHashMap (in /mnt/c/Users/Jordan/Documents/GitHub/flwg/flwp)
==93== by 0x1092F1: main (in /mnt/c/Users/Jordan/Documents/GitHub/flwg/flwp)
==93==
==93== LEAK SUMMARY:
==93== definitely lost: 11,160 bytes in 2,232 blocks
==93== indirectly lost: 0 bytes in 0 blocks
==93== possibly lost: 0 bytes in 0 blocks
==93== still reachable: 0 bytes in 0 blocks
==93== suppressed: 0 bytes in 0 blocks
==93==
==93== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Dr. Memory is giving me a similar error:
Error #1: UNADDRESSABLE ACCESS: reading 0x0000000000000000-0x0000000000000008 8 byte(s)
# 0 testing [C:/Users/Jordan/Documents/GitHub/flwg/FLWP-2.c:120]
# 1 main [C:/Users/Jordan/Documents/GitHub/flwg/FLWP-2.c:105]
Note: #0:00:01.195 in thread 14704
Note: instruction: mov (%rax) -> %rax
The strcmp line of code is what causes it to break with Dr. Memory, although valgrind says I have issues even if I don't call this particular method.
void testing(struct wordConnections *header){
header = header->nextRow;
while(strcmp(header->word, "berk") != 0){
header = header->nextRow;
if(header == NULL){
printf("Failed");
return;
}
}
}
The code that runs is (the value and significance of numLetters + 1 is it is the length of the char* stored in the wordStorage, the value of numLetters is 4):
char** FillHashMap(struct wordConnections **(*HashMap)){
int h = 0;
/* The Amount of words in each file, File 1, 2, 3 */
int totalWordQuantity[3] = {132, 7420, 19829};
/*the word that we test, we add by two because first 4: word, 5th: \n, 6th: \0*/
char word[numLetters + 1];
/*how many times we've changed the character*/
int letterSpot = 0;
/*the character that goes through the file*/
char c;
FILE *flwd = OpenFile();
/* is it the first word of the line */
int wordCount = 0;
int isFirst = 1;
char p = fgetc(flwd);
c = p;
/* So, this is a temporary word, who will store the row, so all of its category folks will be contained within it */
char* rowWord = malloc(sizeof(char) * (numLetters + 1));
/*This stores all of the words*/
char** wordStorage = (char**)calloc(totalWordQuantity[numLetters - 2], sizeof(char*) * (numLetters + 1));
int i = 0;
/* First, take the character */
while((c = p) != EOF){
p = fgetc(flwd);
/* Add the character to the word */
word[letterSpot] = c;
/* Allows the letter spot to find the next place into the word */
letterSpot++;
/* Determines if the character is the placement immediately after the word */
if((c == ' ' && p != '\n') || c == '\n'){
letterSpot = 0;
/* Throws in the \0, converting into a string */
word[numLetters] = '\0';
wordStorage[wordCount] = malloc(sizeof(char) * (numLetters + 1));
h++;
strcpy(wordStorage[wordCount], word);
/* Determine if it's the first word */
if(isFirst == 1){
strcpy(rowWord, word);
/* Throw it in as a row */
AddRow2DLL(wordStorage[wordCount],
HashMap[FirstHashFunction(word[0])/*First Letter*/]
[SecondHashFunction(word)]/*First Vowel*/);
}
/* If it's not the first word */
else {
AddColumn2DLL(wordStorage[wordCount],
HashMap[FirstHashFunction(rowWord[0])/*First Letter*/]
[SecondHashFunction(rowWord)]/*First Vowel*/);
}
if(c == ' '){
isFirst = 0;
}
if(c == '\n'){
isFirst = 1;
}
wordCount++;
}
c = p;
}
free(rowWord);
fclose(flwd);
return wordStorage;
}
The hash map works fine, this is the method that causes the issues, without it, there are no memory leaks.
Later in the code, I free the wordStorage array with this method:
void FreeWordStorage(char** wordStorage){
int f = 0;
/* The Amount of words in each file, File 1, 2, 3 */
int totalWordQuantity[3] = {132, 7420, 19829};
int i;
for(i = 0; i < totalWordQuantity[numLetters - 2]; i++){
free(wordStorage[i]);
f++;
}
free(wordStorage);
}
I've tried all sorts of things to fix it. Oddly enough, when I check it with integers, I'm allocating and freeing the same amount of data.
Any help would be greatly appreciated. Thank you!
Valgrind's analysis indicates that the leaked memory was allocated by a bunch of malloc() calls by function FillHashMap(), and the only plausible candidate for those is this:
wordStorage[wordCount] = malloc(sizeof(char) * (numLetters + 1));
Function FreeWordStorage() appears to be correct for freeing the data allocated by FillHashMap(), so if some allocations are going unfreed then there are two main possibilities:
The pointer value returned by FillHashMap() is not later passed to FreeWordStorage(). The latter function might not be called at all on the code path that is being exercised, or perhaps a modified or outright wrong pointer is being passed to it.
Or,
Some or all of the pointers recorded in the allocated block returned by FillHashMap() are modified after being recorded, so that when it is called, FreeWordStorage() is ineffective at freeing the allocated memory.
Either one of those could be consistent with Dr. Memory's diagnostic, but whichever scenario applies, it does not appear to play out in the code presented in the question. I am reasonably confident that your pointers are being mangled somewhere else in the program.
I have wrote a small example problem to learn about memory allocation and freeing this memory (to protect from memory leaks):
#include <stdlib.h>
long* foo(char str[]) {
long *nums;
nums = calloc(2,sizeof(long));
//something is happening depending on what's inside the char[]
nums[0] = 57347534;
nums[1] = 84757;
return nums;
}
int main() {
char str1[400] = "This is a test";
long* retValue = foo(str1);
//some lines of checking content of "retValue"
char str2[400] = "This is another test";
retValue = foo(str2);
//some more lines of checking content of "retValue"
char str3[400] = "This is a final test";
retValue = foo(str3);
//again some more lines of checking content of "retValue"
free(retValue);
}
So in my main function, I am using three char arrays which I will pass to my function. This function has a num pointer of long values where am callocing two of them. Then I am just calculating some numbers according to the content in str[] and return nums.
My questions about this are:
How do I free the memory I used for nums? Because I cannot free it before I use it for return.
Is it right to free the retValue in the last line there?
Am I right that I do not need to free my char arrays, because they are not dynamic?
Thanks for your answers, that would help me more safely use pointers!
You need to call free before every new assignment to retValue (if the previous assignment came from malloc, calloc or realloc). Otherwise you will have memory leaks.
Every allocation must be matched by a free, plain and simple.
A good way to answer questions about memory allocation and use is to use a memory checker - I'll use Valgrind:
gcc-8 -std=c11 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds 50627661.c -o 5062766
50627661.c: In function ‘foo’:
50627661.c:3:16: warning: unused parameter ‘str’ [-Wunused-parameter]
long* foo(char str[]) {
~~~~~^~~~~
valgrind -q --leak-check=full ./50627661
==14785== HEAP SUMMARY:
==14785== in use at exit: 32 bytes in 2 blocks
==14785== total heap usage: 3 allocs, 1 frees, 48 bytes allocated
==14785==
==14785== 16 bytes in 1 blocks are definitely lost in loss record 1 of 2
==14785== at 0x4C2EBA5: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14785== by 0x10867F: foo (50627661.c:5)
==14785== by 0x1086F6: main (50627661.c:18)
==14785==
==14785== 16 bytes in 1 blocks are definitely lost in loss record 2 of 2
==14785== at 0x4C2EBA5: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14785== by 0x10867F: foo (50627661.c:5)
==14785== by 0x108758: main (50627661.c:24)
This shows that of the three allocations we made, we only freed one of them - the other two leaked.
If you do not want to clutter your calling code with free, the alternative is to pass to the callee an array mangaged by the caller:
long foo(char str[], long *nums, int size) {
if (size < 2) { // passed array must be at least 2 long
return -1;
}
//something is happening depending on whats inside the char[]
nums[0] = 57347534;
nums[1] = 84757;
return 2; // returns used size (or -1 for error)
}
int main() {
long retValue[2];
char str1[400] = "This is a test";
if (-1 == foo(str1, retValue, 2)) {
// process error condition
}
//some lines of checking content of "retValue"
char str2[400] = "This is another test";
if (-1 == foo(str2, retValue, 2)) {
// process error condition
}
//some more lines of checking content of "retValue"
char str3[400] = "This is a final test";
if (-1 == foo(str3, retValue, 2)) {
// process error condition
}
//again some more lines of checking content of "retValue"
//free(retValue); no need for free since nothing was allocated...
return 0;
}
I have written a small implementation of a simple stack in C using a linked list. The application works after a bit of fussing with gdb and valgrind. However, I have noticed that valgrind reports a number of "still reachable" leaks at termination of the program.
After some googling, I have found that these type of leaks are not an issue and that I generally shouldn't worry about them. Well that's great news! The only thing is, I would REALLY like to understand why valgrind sees these leaks and where they appear. I went to great pains through my first pass at this application to diligently release any allocated memory. What did I miss? Where are these allocations that valgrind sees but I cannot?
I have been staring at this for awhile now, and despite fiddling with the code this way and that, have come up empty handed. Hopefully you all can help me in this endeavor.
I have stripped the app down to a minimal example that will present the leak I am observing. It just initializes the stack and then immediately destroys it and exits.
// simple stack implementation
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
/*--- data structure in a stack item ---*/
struct data {
char * message;
};
/*--- stack item structure ---*/
struct item {
struct data * my_data;
struct item * next;
};
/*--- stack data structure ---*/
struct stack {
int initialized;
int empty;
struct item * head;
};
struct stack * my_stack;
/*--- create a new stack data structure with provided initial data ---*/
int
create_stack(struct data ** initial_items, int num_items) {
//allocate memory for the stack structure itself
my_stack = (struct stack *) malloc(sizeof(struct stack));
if(!my_stack) return -1;
my_stack->empty = 1;
my_stack ->initialized = 0;
if(num_items) {
//allocate memory for the head of the list first
my_stack->head = (struct item *) malloc(sizeof(struct item));
if(!my_stack->head) return -1;
my_stack->head->my_data = initial_items[0];
my_stack->head->next = NULL;
struct item * tracker = my_stack->head;
//fill the stack with elements containing the provided data
int i = 1;
for(; i < (num_items); i++) {
tracker->next = (struct item *) malloc(sizeof(struct item));
tracker = tracker->next;
if(!tracker) return -1;
tracker->my_data = initial_items[i];
tracker->next = NULL;
}
//no longer empty
my_stack->empty = 0;
}
//set initialized flag & return
my_stack->initialized = 1;
return 0;
}
/*--- destroy the stack by recursively freeing nodes ---*/
int
destroy_stack(struct item * recurse) {
//if the starting node is valid, begin
if(recurse) {
//if the current node links to another
if(recurse->next)
//recurse on the next node
destroy_stack(recurse->next);
else
//otherwise we hit the end, free the node
free(recurse);
}
//the starting node is invalid, just free the stack itself
else {
free(my_stack);
}
return 0;
}
/*--- test wrapper ---*/
int
main(int argc, char **argv) {
//initialize 10 element list of data structures to fill the stack items with
int i = 0;
int length = 10;
struct data ** initial_values = (struct data **) malloc(length*sizeof(struct data *));
//set each data element's value to i
for(; i < length; i++) {
char temp[16];
sprintf(temp, "%d", i);
initial_values[i] = (struct data *) malloc(sizeof(struct data));
initial_values[i]->message = strdup(temp);
}
//simple test case
//create a stack with the generated initial data, then destroy it
assert( !create_stack(initial_values, length) );
assert( !destroy_stack(my_stack->head) );
//free the string data our stack nodes were pointing to
i = 0;
while(i < length) {
free(initial_values[i]->message);
free(initial_values[i]);
i += 1;
}
free(initial_values);
return 0;
}
Running this through valgrind produces the following identified, unreleased blocks:
(trusty)kin3tix#localhost:~/C Practice/Data Structures$ valgrind --leak-check=full --show-leak-kinds=all ./stack_leak_test
==19340== Memcheck, a memory error detector
==19340== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==19340== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==19340== Command: ./stack_leak_test
==19340==
==19340==
==19340== HEAP SUMMARY:
==19340== in use at exit: 168 bytes in 10 blocks
==19340== total heap usage: 32 allocs, 22 frees, 364 bytes allocated
==19340==
==19340== 16 bytes in 1 blocks are still reachable in loss record 1 of 3
==19340== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19340== by 0x400739: create_stack (stack_leak_test.c:40)
==19340== by 0x40093B: main (stack_leak_test.c:95)
==19340==
==19340== 24 bytes in 1 blocks are still reachable in loss record 2 of 3
==19340== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19340== by 0x4006E6: create_stack (stack_leak_test.c:33)
==19340== by 0x40093B: main (stack_leak_test.c:95)
==19340==
==19340== 128 bytes in 8 blocks are still reachable in loss record 3 of 3
==19340== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19340== by 0x4007A1: create_stack (stack_leak_test.c:48)
==19340== by 0x40093B: main (stack_leak_test.c:95)
==19340==
==19340== LEAK SUMMARY:
==19340== definitely lost: 0 bytes in 0 blocks
==19340== indirectly lost: 0 bytes in 0 blocks
==19340== possibly lost: 0 bytes in 0 blocks
==19340== still reachable: 168 bytes in 10 blocks
==19340== suppressed: 0 bytes in 0 blocks
==19340==
==19340== For counts of detected and suppressed errors, rerun with: -v
==19340== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
They all seem to stem from "create_stack" but as far as I can tell my destroy function should be catching everything I allocate. What am I missing here?
Your destruction logic is trying to recursively combine two tasks (deleting the stack object and its items) in a single function. Worse, the else state shouldn't be there at all. You already determined you're sitting on a dynamic node (recurse). It needs to be deleted. Whether it has a next or not is not for the current depth to decide; that will be taken care of in the next depth of recursion.
Honestly, this is much simpler if you create a helper to wipe out the linked list, and as separate wrapper to do said-same to the stack itself:
/*--- destroy linked list nodes recursively ---*/
static void destroy_stack_items(struct item *item)
{
if (item)
{
destroy_stack_items(item->next);
free(item);
}
}
/*--- destroy the stack by recursively freeing nodes ---*/
int destroy_stack(struct stack *s)
{
if (s)
{
destroy_stack_items(s->head);
free(s);
}
return 0
}
and simply invoked as:
destroy_stack(my_stack);
Personally I would do it iteratively (thus remove the helper in the process), but I'm sure you have your reasons for otherwise. For example:
/*--- destroy the stack by iteratively freeing nodes ---*/
int destroy_stack(struct stack *s)
{
if (s)
{
while (s->head)
{
struct item *tmp = s->head;
s->head = tmp->next;
free(tmp);
}
free(s);
}
return 0
}
Best of luck.
I have made a minimal-working example of how to add elements to an array with realloc. This will be expanded in a future program that has many more elements.
#include <stdio.h>//printf
#include <stdlib.h>//malloc, realloc
int main() {
//BEGIN REALLOCATE-ABLE ARRAY
unsigned int *array, loop_variable;
const unsigned int ORIGINAL_ARRAY_SIZE = 4, REALLOC_INDICES = 99;
array = malloc(ORIGINAL_ARRAY_SIZE*sizeof(unsigned int));
for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE; loop_variable++) {
array[loop_variable] = loop_variable;
}
//BEGIN REALLOCATION
for (loop_variable = 1; loop_variable < REALLOC_INDICES; loop_variable++) {
array = realloc(array,sizeof(unsigned int)*(ORIGINAL_ARRAY_SIZE+loop_variable));
array[ORIGINAL_ARRAY_SIZE+loop_variable-1] = 2*(ORIGINAL_ARRAY_SIZE+loop_variable-1);
printf("reallocate array[%d] = %d\n",ORIGINAL_ARRAY_SIZE+loop_variable-1,array[ORIGINAL_ARRAY_SIZE+loop_variable-1]);
}
//BEGIN PRINTING ARRAY VALUES
for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE+REALLOC_INDICES-1; loop_variable++) {
printf("array[%d] = %d\n",loop_variable,array[loop_variable]);
}
//BEGIN FREE ARRAY
free(array); array = NULL;
return 0;
}
This should compile on any computer with gcc or clang. I then run this program on valgrind to ensure there are no memory leaks, and I get this:
==10791== HEAP SUMMARY:
==10791== in use at exit: 0 bytes in 0 blocks
==10791== total heap usage: 99 allocs, 99 frees, 20,988 bytes allocated
==10791==
==10791== All heap blocks were freed -- no leaks are possible
==10791==
==10791== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==10791== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
However, what troubles me is that I'm using 20,988 bytes for a 101-element array. The memory use grows exponentially as the array gets bigger, instead of linearly by 4 bytes/element.
If I'm understanding Valgrind's output correctly, this array should have 4*101 elements = 404 bytes memory size, but appears to use about 50 times as much memory as it should. This is a trivial problem for such a small program, but more meaningful programs will run out of memory on this computer.
My question: is this array really using 20,988 bytes, or is Valgrind double-counting the memory?
Is there a more memory-efficient way to do this? I can't understand other examples of realloc, though I have tried to follow them as closely as I can and make this question relevant to as many users as possible.
==10791== in use at exit: 0 bytes in 0 blocks
==10791== total heap usage: 99 allocs, 99 frees, 20,988 bytes allocated
is this array really using 20,988 bytes
No, it's using 0 bytes.
“allocated” obviously means “ever allocated”, including bytes that have been freed, since the amount of memory “still allocated” is zero (and another line tells you that).
The answer, thanks to user Pascal Cuoq, is that Valgrind will sum the memory allocations for every allocation. This is why I was confused, and thought that realloc was using too much memory.
I thought that if you want to find the size of the array, you can comment out the line that says
free(array); array = NULL;
to intentionally introduce a memory bug, and Valgrind will output
==11699== LEAK SUMMARY:
==11699== definitely lost: 408 bytes in 1 blocks
==11699== indirectly lost: 0 bytes in 0 blocks
==11699== possibly lost: 0 bytes in 0 blocks
==11699== still reachable: 0 bytes in 0 blocks
==11699== suppressed: 0 bytes in 0 blocks
==11699==
==11699== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==11699== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
which gives you the true size of the array at its last iteration. There is probably a better way to do this, but my point is made.
I added improvements suggested by other users here. I had a very difficult time finding good, minimal working examples of realloc on search engines, and for future use of anyone finding this on a search engine, this is very basic minimal working example of a good, but probably not best, how to use realloc in C:
#include <stdio.h>//include printf function
#include <stdlib.h>//include malloc, realloc functions
int main() {
/*BEGIN REALLOCATE-ABLE ARRAY*/
unsigned int *array, loop_variable;
const unsigned int ORIGINAL_ARRAY_SIZE = 4, REALLOC_INDICES = 99999;
array = malloc(ORIGINAL_ARRAY_SIZE*sizeof(unsigned int));
for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE; loop_variable++) {
array[loop_variable] = loop_variable;
}
/*BEGIN REALLOCATION*/
for (loop_variable = 1; loop_variable < REALLOC_INDICES; loop_variable++) {
array = realloc(array,sizeof(unsigned int)*(ORIGINAL_ARRAY_SIZE+loop_variable));
if (array == NULL) {
printf("Array variable %d failed to reallocate :,-(\n",loop_variable);
exit(EXIT_FAILURE);
}
array[ORIGINAL_ARRAY_SIZE+loop_variable-1] = 2*(ORIGINAL_ARRAY_SIZE+loop_variable-1);
printf("reallocate array[%d] = %d\n",ORIGINAL_ARRAY_SIZE+loop_variable-1,array[ORIGINAL_ARRAY_SIZE+loop_variable-1]);
}
/*BEGIN PRINTING ARRAY VALUES*/
for (loop_variable = 0; loop_variable < ORIGINAL_ARRAY_SIZE+REALLOC_INDICES-1; loop_variable++) {
printf("array[%d] = %d\n",loop_variable,array[loop_variable]);
}
/*BEGIN FREE ARRAY*/
free(array); array = NULL;
return 0;
}