CS50’s Introduction to Computer Memory Management in C

This is 5th blog in my ongoing CS50 Series. Readers are suggested to go through 0th, 1st ,2nd & 3rd article for a better understanding of subject matter. In this blog, we will learn about memory management in C.

Computer Memory (Credit: www.pandasecurity.com)

In the last blog, we studied different searching & sorting algorithms. In this blog, we will be studying

  • Hexadecimal Numbers

Hexadecimal Numbers

In our daily life, we use Decimal System (base 10) having 10 digits (0 to 9) to represent the data where each digit has place values like 1, 10, 100 and so on. The computer use Binary System (base 10) having 2digits (0 &1) to represent the data where each digit has place values like 1, 2, 4 and so on. Similarly we there is Hexadecimal System (base 16) having 16 digits (0 to F), each digit has a place value of 1, 16, 256 and so on.

Decimal vs Binary vs Hexadecimal

Each hexadecimal number corresponds to a unique arrangement of 4 binary digits or bits and hence we can express very long, complex binary numbers in a very concise way without losing any data. We use the prefix “0x” before any hexadecimal to represent that it is a hexadecimal number. Each byte in the computer memory is identified by a unique hexadecimal address.

Computer Memory Addressing

Pointers

The pointer, as its name suggests, stores the address of another variable i.e. points toward the other variable. The pointer is nothing more than an address.
For any pointer,
• Its value is a memory address
• Its datatype describes the data located at that memory address.

There are two operators which have been used in the pointer syntax & example above

  • Extraction Operator (&)
    The extraction operator(&) extracts the address of a variable. We use the extraction operator to initialize the pointer. If var is variable of int type then &var is a pointer to the int and its value is the address of variable var.

Remember the following things about pointers.

  • The pointer must have the same data type as that of data at the memory address which is stored in a pointer.

Memory Layout

The computer memory consists of millions and billions of bytes and during a program when we request the memory to the computer, the requested memory is allocated to you from these bytes. The computer (specifically OS) doesn't allocate the memory arbitrarily but follows a certain methodology. The computer uses different sections of memory for different types of data. If we imagine computer memory as a rectangle with three sections then the data will be stored as follows

Memory Layout
  1. Upper Section
    The compiled machine code is stored in the uppermost section of memory. Below machine code, global variables are stored.

Dynamic Memory Allocation

Till this time in CS50, we were allocating memory statically where we would specify how much memory we need in a program. What if we don't know the amount of memory we need? This problem is solved by using Dynamic Memory Allocation.

We can use pointers to get access to a block of dynamically allocated memory at runtime. Dynamically allocated memory comes from the heap section whereas statically allocated memory comes from the stack section.

malloc( )

We can get dynamically allocated memory by making a call to malloc() function, passing as it parameter the number of bytes required. If it can obtain memory for you, it will return a pointer to the obtained memory. if it can’t obtain memory for you, it will return NULL pointer. Hence it is important to check whether pointer returned by malloc() is NULL or not and if t is then you need to end the program. If you try to dereference the NULL pointer then you will suffer a segmentation error.

free( )

The problem with dynamically allocated memory is that the memory you are allocated is not automatically returned to the system for further use when a function in which it is created finishes execution. Thus it results in memory leak which can compromise the performance of your system. Hence it is standard practice to free the dynamically allocated memory you have used using the free() function.

Three Golden Rules of Dynamic Memory Allocation:

  1. Every block of memory that you malloc() must subsequently be free()d.

You can understand the Dynamic Memory Allocation from the following visualization.

Credit: CS50

Call Stack

When you call a function, the system set aside a chunk of memory on the stack section for that function to do its necessary work. Such a chunk of memory is called Stack frames or function frames.

  • In the case of nested functions, more than one functions stack frames can exist in memory at a given time, although only one stack frame can be active at a given time.

You can understand the above process from the following visualization.

Credit: CS50

File Pointers

Up to this point in C, we don't have any means by which we can store any persistent data, i.e. the information that exists even after the program has stopped running. Fortunately, C provides you with this ability using FILE. It is a data structure that represents a file. We will be working with FILE*, a pointer to files. All of the file manipulation functions are defined in header file stdio.h and all of them accept FILE* as their parameter except fopen() function which is used to get file pointer in the first place. Following are some of the most common file input/output (I/O) functions.

  • fopen()
File I/O Functions

You should take care of following things while using these functions

  • fopen(): Always check it’s return value to making sure that you don't get back NULL.

Conclusion

I hope this blog was helpful to you. This series of blogs on CS50 will continue. Thank you very much for your patient reading. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above. You can connect with me on LinkedIn or by visiting my website on Medium. Happy Learning.

Aspiring Web Developer & CS Enthusiast. I write about CS stuff that I learn. https://www.linkedin.com/in/sachin-bhutekar-cs/