Learning memory allocation in C for beginners will be totally a pain. This post, distilled from course materials, will provide you a practice guide and example coding snippets to help you learning more and fast in C programming language. It is cherishable, at least to me :)
Introduction to malloc
- Variable defined in function will be stored in stack, so how to use that part of memory after function returns? we use
void * malloc(size_t size)will allocate memory in heap. This function will remain the memory for the variables until the function explicitly deallocate them. The argument for this function indicates how many bytes of memory should it allocate.
- In general,
size_tis unsigned_int. Notice the
void *type of the pointer, we know that in C, add 1 to a pointer will go to the next legal address, for
int*, it is the next integer, for
char*, it is next character.
- A void pointer is a pointer that represent a generic type. It just points to the memory specified, so it do not need to specify right now what type of that memory is, instead, we will declare the type when use pointer:
int * pt = malloc(sizeof(int));
the above code indicates that we will the allocated memory for integer.
Note that in the above code, there are several variables that are located in heap. They are, the address store inside the variable result, since it points to a integer that lies in heap, while the addresss of the variable result is not in the heap, it is in the stack. One quick trick is that those value in heap, their address is valid.
Explicitly deallocate the memory
Important issue here: when returned from the function, all variables will be freed from stack, which means that the
resultin the above code will be removed. It will cause a memory leak if we forget to link the memory from
mallocto other heap variables. Since there will be no way from elsewhere to access that part of memory.
- The danger of memory leak is that if it accumulates, it will finally cause a
out of memoryissue.
- what happens if we print out the value stored in that memory location after we free up that pointer? Address is still valid and the value can still be accessed, but this time, we are using the part of memory that does not belong to us. Note that using unallocated memory is OK in some cases, but it will be dangerous when that part of memory being reallocated. So, always use allocated memory!
- there are basically two ways to help to avoid memory leak, a) return value, if we define that function type to be a pointer type, so that we can return the pointer in order to assign the values in main function. b) argument, we pass the one we want to assign values to the function and do the assigning part inside that function, and this time, the function type can be void but still finish the task.
- However, it is much harder to use
argumentone since in C, the changes inside the function will not be preserved if we return nothing. Therefore, we need to the “address-value” relation in such scenario – That is we pass in pointer, we change value pointed at pointer, without returning anything, and we’re done. While problem comes when we want to change the pointer, say this line
*arr_matey = malloc(sizeof(int) * 3);, we want to change the pointer now, but such change will not be preserved after function. Therefore, we will need to pass in a “poiter of pointer” to deal with pointer assignment!
if we want to use a nested struture to represent an array, say in that array, each element points to another array, since we don’t know that array size at compilation time, we would use
malloc to allocate memory for those int array. The code is like
int ** pt = malloc(sizeof(int*)*2);
Say, now, I want the pt to hold up an array of one integer, the way to do that is to use:
pt = malloc(sizeof(int));
Similarly, if we want pt to hold up 3 integers, we would use:
pt = malloc(sizeof(int)*3);
Note that when we free those pointers, we need to free the innermost pointer first then outer one.
An complete code example:
- note that th variable in main function does not belong to global variable, indicating it should still go to the stack part. The “global data” part contains mainly three stuff: a) global variables, b) string literals Note that for the string literals, the code like this:
char* str = "Hello world!";can lie in a local function, it just means that the pointer str can be in the stack, while the string literal “Hello world!” is in global data part.
- And dynamic memory allocation lie in heap.
difference between a string and a character is that at the end of string, there is a
\0as an ending signal. Once the character array declared, the size is fixed. Note that the difference between these similar version of declaring character array:
char string = "cool shit", it is defining a string variable, with a
\0at the end of the array, note that there will be a lot of
\0following the valid words. It can be changed afterwards.
char string = "cool shit", defining a string variable the size will be fixed according to the first assignment. It can be changed afterwards.
char* string = "cool shit", defining a string constant. it is a string literal! cannot be changed!! If you change the string, it will give a “bus error”. Main point here: it makes string point to a read-only memory where string literal is stored, while the above two way are indeed allocating memory and copy string to them.
strlenwill return the valid number of characters before null character, while
sizeofwill just give you the size of whole char array including null characters.
strncpyas a stable counterpart of
strcpy, the usage is like:
strncpy(s1, s2, sizeof(s1));see the complete code below, s2 is a string literal.
Note that s1 is a character array, which means that there is no null characters at the end. if we want to do this way, we want to add null character at the end.
strncat(s1, s3, sizeof(s1)-strlen(s1)-1);is the stable version of using strcpy.
char * strchr(const char s, int c);return the index at the first occurence of the character
char * strstr(const char* s1, const char* s2);find sub string. see the code example below:
if the character specified in the second argument cannot find the right place, then it will assign NULL to p in this case. We can use pointer subtraction to get the index.
后记： 欢迎加入我的私人公众号， 和你分享我思考的观点和文章：