Objective
|
LessonMemorySo far, you probably haven't given much thought about how a program works or how it runs. Well, most of us know that a program is a file that is loaded into memory at some undefined point. So given the following code below, where are int main(void) {
int a = 10;
int b = 1;
a -= 2;
int c = 21;
return c + (a/b);
}
Although this is a great way to allocate memory, it was mentioned that the stack is usually small, meaning you don't want to put large variables onto the stack; mainly large arrays and large structures. If you don't want to waste your precious stack space, where and how can you allocate large amounts of memory? Luckily, there's a large memory region reserved for just that. This area is called the heap. Essentially, the heap is a very large memory pool where certain parts of it may be used or unused. Thankfully, the operating system takes care of the complex task of managing it; all we need to know is how to allocate the memory and release it. Unfortunately, if you don't release the allocated memory, it will remain allocated until you do. This could lead to a memory leak, in which you lose the location of the allocated memory and you'll never be able to release it. This could impact performance and eventually could cause your program to run out of memory, thereby crashing it. One needs to be extra cautious when working with dynamic memory allocation. All in all, allocating memory in the heap is great for large variables, while using the stack is best suited for small variables. Allocating MemoryBefore we get started with some examples, it's important to know that all of the memory allocation functions are kept in the header file Now that we know how to allocate memory, let's try it. #include <stdlib.h> /* malloc */
int main(void) {
char *array = malloc(10);
return 0;
}
We just made a ten byte dynamic array, but to avoid errors you should always multiply the number of variables you want by the
size of the variable's data type. Take a look at the next example and notice the use of the #include <stdlib.h> /* malloc */
int main(void) {
int *array = malloc(sizeof(int) * 10);
return 0;
}
Sometimes there just isn't enough memory, meaning that #include <stdlib.h> /* malloc, NULL */
#include <stdio.h> /* fprintf, stderr */
int main(void) {
int *array = malloc(sizeof(int) * 10);
if (array == NULL) {
fprintf(stderr, "Unable to allocate enough memory for array!\n");
return -1;
}
return 0;
}
Still, this code needs one final touch-up. #include <stdlib.h> /* malloc, NULL */
#include <stdio.h> /* fprintf, stderr */
int main(void) {
int *array = (int*) malloc(sizeof(int) * 10);
if (array == NULL) {
fprintf(stderr, "Unable to allocate enough memory for array!\n");
return -1;
}
return 0;
}
Releasing Allocated MemoryNow that you've allocated memory, your program will keep it as long as it lives. That means allocating large chunks of memory can drain your computer's resources. At some point you're going to want to give back that memory. The #include <stdlib.h> /* malloc, free, NULL */
#include <stdio.h> /* fprintf, stderr */
int main(void) {
int *array = (int*) malloc(sizeof(int) * 10);
if (array == NULL) {
fprintf(stderr, "Unable to allocate enough memory for array!\n");
return -1;
}
/* I have no use for array, I better free it. */
free(array);
return 0;
}
Resizing Allocated MemoryWell, it's great that we can allocate and deallocate memory, but what if we want to change the size of the allocated memory? It's possible to do this via the #include <stdlib.h> /* malloc, realloc, free, NULL */
#include <stdio.h> /* fprintf, stderr */
int main(void) {
/* Let's allocate memory for array. */
int *array = (int*) malloc(sizeof(int) * 2);
/* Check to make sure that we got the allocated memory. */
if (array == NULL) {
fprintf(stderr, "Unable to allocate enough memory for array!\n");
return -1;
}
/* Let's actually use array. */
*array = 10;
*(array + 1) = 20;
/* Oh no! array doesn't have any more space, We better get more! */
int *array = (int*) realloc(array, sizeof(int) * 4);
/* Check to make sure that we got the allocated memory. */
if (array == NULL) {
fprintf(stderr, "Unable to allocate enough memory for array!\n");
return -1;
}
/* Let's use array a little more. */
*(array + 2) = 30;
*(array + 3) = 40;
/* We have no more use for array, we better free it. */
free(array);
/* Everything went fine! */
return 0;
}
As you probably noticed Allocating Clean MemoryUsing #include <stdlib.h> /* malloc, calloc, free, NULL */
#include <stdio.h> /* printf, fprintf, stderr */
int main(void) {
/* Let's allocate memory for array. */
int *array = (int*) calloc(5, sizeof(int));
/* Check to make sure that we got the allocated memory. */
if (array == NULL) {
fprintf(stderr, "Unable to allocate enough memory for array!\n");
return -1;
}
/* Let's use some parts of array. */
*array = 15;
*(array + 1) = 7;
*(array + 3) = 23;
for (int i = 0; i < 5; i++) printf("%d: %d\n", i, *(array+i));
/* We have no more use for array, we better free it. */
free(array);
/* Everything went fine! */
return 0;
}
The output should be: 0: 15 1: 7 2: 0 3: 23 4: 0 Memory Management ProblemsUnlike some newer languages, C requires you to manually allocate and deallocate memory. Thus, the task of managing your program's memory falls solely on you, the programmer. No matter how much experience you have with memory management, you'll still make mistakes when working with dynamic memory. The important thing is to realise the types of problems you may encounter and understand how to correct and prevent them. Luckily, a good number of these problems will be discussed in this section.
|
Assignments
|
|