Let’s take a look at one of the craziest concepts we have in our toolkit to date: dynamically-allocated memory.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int integer_boi = malloc(sizeof(int));
*integer_boi = 123456789;
printf("integer_boi = %d\n", *integer_boi);
return 0;
}
Answer: This program does not manage memory
correctly! Notice that integer_boi
declared on line 6 is
just an integer, not an integer pointer. To properly utilize
malloc()
, its return value should be assigned to a pointer.
The following shows this fixed:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *integer_boi = malloc(sizeof(int));
*integer_boi = 123456789;
("integer_boi = %d\n", *integer_boi);
printf
(integer_boi);
free
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
double *pointy_pointer;
pointy_pointer = malloc(sizeof(double));
*pointy_pointer = 3.14159;
printf("*pointy_pointer = %lf\n", *pointy_pointer);
return 0;
}
Answer: This program is not managing memory
correctly and has a memory leak. After the printf()
statement on line 10, you must make sure to call
free(pointy_pointer);
to ensure all memory allocated is
freed.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *letter = NULL;
malloc(sizeof(char));
*letter = 'M';
printf("The letter of the day is: %c\n", *letter);
free(letter);
return 0;
}
Answer: This program has a memory leak and
dereferences a null pointer. On line 7, memory for a char
is allocated, but it is not assigned to the variable
letter
, so this allocation is effectively wasted. The
following lines that dereference letter
thus will fail, and
the wasted malloc()
call will cause a memory leak.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
float *pi;
pi = malloc(sizeof(float) * 5);
*pi = 3.14;
printf("pi = %.2lf\n", *pi);
free(pi);
return 0;
}
Answer: This program does manage memory correctly! While more memory than necessary was allocated on line 8 for this program, this is considered valid.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *stringy;
= malloc(sizeof(char) * 30);
stringy (stringy, "goober");
strcpy
for (int i = 0; i < 30; i++)
{
(stringy[i]);
free}
return 0;
}
Answer: This program does not manage memory
correctly. This code attempts to free each individual character of the
array, which is not correct. Since there was only one call to
malloc()
, there should only be one call to
free()
. Instead, the for loop should be replaced with the
following:
(stringy); free
[1, 2, 3, 4, ..., 20]
.#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *array;
// Allocate the array
= malloc(sizeof(int) * 20);
array
// Initialize the array
for (int i = 0; i < 20; i++)
{
[i] = i + 1;
array}
// Free the array
(array);
free
return 0;
}
Editor’s Note: Your solution for the array initialization may look slightly different. This is a sample solution. The following is an example of a different (also correct) version of that for loop:
for (int i = 1; i <= 20; i++)
{
[i - 1] = i;
array}
typedef struct Computer
{
int memory;
int processes;
float power;
} Computer;
int main(void)
{
*my_PC = malloc(sizeof(Computer));
Computer
("Hello, world!\n");
printf
return 0;
}
Answer: Nope, we’re missing free(my_PC)
so memory is getting leaked!
true
? What will print out in this
program?typedef struct Computer
{
int memory;
int processes;
float power;
} Computer;
*copy_struct(Computer *pc)
Computer {
*temp = malloc(sizeof(Computer));
Computer ->memory = pc->memory;
temp->processes = pc->processes;
temp->power = pc->power;
temp
return temp;
}
int main(void)
{
*my_PC = malloc(sizeof(Computer));
Computer *my_other_PC;
Computer
->memory = 10000;
my_PC->processes = 29;
my_PC->power = 79.81;
my_PC= copy_struct(my_PC);
my_other_PC
if (my_PC == my_other_PC)
{
("Now my PC and my other PC are equal!\n");
printf}
else
{
("MEM: %d vs %d\n", my_PC->memory, my_other_PC->memory);
printf("PRO: %d vs %d\n", my_PC->processes, my_other_PC->processes);
printf("POW: %.2f vs %.2f\n", my_PC->power, my_other_PC->power);
printf}
(my_PC);
free(my_other_PC);
free
return 0;
}
Answer: The structs are equal, but the conditional
is false since they are NOT pointing to the same address. You will see
that the values that print out will be the same for my_PC
and my_other_PC
, since they are equal but independent -
this is why we free
twice.
true
? Also, what is missing from this
program regarding memory management?typedef struct Computer
{
int memory;
int processes;
float power;
} Computer;
*copy_struct(Computer *pc)
Computer {
*temp = pc;
Computer
return temp;
}
int main(void)
{
*my_PC = malloc(sizeof(Computer));
Computer *my_other_PC = copy_struct(my_PC);
Computer
if (my_PC == my_other_PC)
("Now my PC and my other PC are equal!\n");
printf
return 0;
}
Answer: Notice how the copy_struct
function, different from the previous exercise, is setting one pointer
to be my_PC
. Therefore, both pointers will be pointing to
the same address and the conditional is true. Notice also that we are
missing the free
… oh no!
typedef struct Computer
{
int memory;
int processes;
float power;
} Computer;
*copy_struct(Computer *pc)
Computer {
*temp = pc;
Computer
return temp;
}
int main(void)
{
*my_PC = malloc(sizeof(Computer));
Computer *my_other_PC = copy_struct(my_PC);
Computer
(my_PC);
free(my_other_PC);
free
return 0;
}
Answer: Similar to the previous exercise,
my_PC
and my_other_PC
are pointing to the same
address (they are equal to each other). This means that when we free one
of the pointers, we freed the memory they were pointing to and it would
be incorrect to try to free
again, since it had been
free
d before.
power
for both my_PC
and my_other_PC
?typedef struct Computer
{
int memory;
int processes;
float power;
} Computer;
*copy_struct(Computer *pc)
Computer {
*temp = pc;
Computer ->power = 100;
temp
return temp;
}
int main(void)
{
*my_PC = malloc(sizeof(Computer));
Computer ->power = 79.81;
my_PC*my_other_PC = copy_struct(my_PC);
Computer
(my_PC);
free(my_other_PC);
free
return 0;
}
Answer: Once again, copy_struct
is
setting the pointers equal to each other so that they are pointing to
the same address. This means that any changes to one pointer will also
be reflected on the other pointer, so the value of power
is
100 for both. Notice also that we should not be using
free()
twice. Can you see why?
Pixel
struct with the red, green, and
blue components. (1) Create an array of 1024
pixels
dynamically, (2) assign values to each pixel, and (3)
free the memory associated with the array.Answer:
typedef struct Pixel
{
int r;
int g;
int b;
} Pixel;
int main(void)
{
*scan_line;
Pixel int n = 1024;
(time(NULL));
srand
// Create an array of pixels. Your code goes here
= malloc(sizeof(Pixel) * n);
scan_line
for (int i = 0; i < n; i++)
{
// Your code goes here
[i].r = rand() % 256;
scan_line[i].g = rand() % 256;
scan_line[i].b = rand() % 256;
scan_line}
// Time to free. Your code goes here
(scan_line);
free
return 0;
}
Answer:
typedef struct Birthday
{
int day;
int year;
char month[10];
} Birthday;
typedef struct Person
{
char *name;
int age;
;
Birthday birthday} Person;
int main(void)
{
*human = malloc(sizeof(Person));
Person int name_length = 14; // or better yet: strlen("Adele Goldberg")
->name = malloc(sizeof(char) * (name_length + 1));
human
// Your code goes here
(human->name, "Adele Goldberg");
strcpy->age = 75;
human
->birthday.day = 22;
human->birthday.year = 1945;
human(human->birthday.month, "July");
strcpy
("Hello, I am %s, a %d-year-old.\n", human->name, human->age);
printf("I was born in %s, %d, %d\n", human->birthday.month, human->birthday.day, human->birthday.year);
printf
(human);
free
return 0;
}
Crazy advanced answer using user input and more pointers:
typedef struct Birthday
{
int day;
int year;
char month[10];
} Birthday;
typedef struct Person
{
char *name;
int age;
*birthday;
Birthday } Person;
*create_person(char *name, int name_length)
Person {
*person = malloc(sizeof(Person));
Person
->name = malloc(sizeof(char) * (name_length + 1));
person(person->name, name);
strcpy->age = 100;
person
->birthday = malloc(sizeof(Birthday));
person->birthday->day = 1;
person->birthday->year = 1900;
person(person->birthday->month, "January");
strcpy
return person;
}
void free_person(Person *person)
{
if (person == NULL)
return;
(person->name);
free(person->birthday);
free(person);
free}
int main(void)
{
*human = NULL;
Person int name_length;
char buffer[1024];
("What is your name? ");
printf("%s", buffer);
scanf
= strlen(buffer);
name_length = create_person(buffer, name_length);
human
("Hello, I am %s, a %d-year-old.\n", human->name, human->age);
printf("I was born in %s, %d, %d\n", human->birthday->month, human->birthday->day, human->birthday->year);
printf
(human);
free_person
return 0;
}
calloc()
typedef struct Computer
{
int memory;
int processes;
float power;
} Computer;
int main(void)
{
Computer *my_PC = calloc(1, sizeof(Computer));
Computer *my_other_PC = malloc(sizeof(Computer));
printf("%d\n", my_PC->memory + my_PC->processes + my_PC->power);
printf("%d\n", my_other_PC->memory + my_other_PC->processes + my_other_PC->power);
free(my_PC);
free(my_other_PC);
return 0;
}
Answer: Because calloc
sets initial
values to the struct, my_PC members are all 0. malloc
doesn’t do anything to do values and can can be garbage values. So, line
13 prints 0 and line 14 prints garbage values.