REN

Ph.D. in Computer Science at Rutgers University

Talking about C pointer - Dynamic memory allocation and Function Parameter passing

This is the third one of 'Talking about C pointer' series. In this article, I'll discuss some tricky topics relies on C pointers such as dynamic memory allocation, function argument passing.

Dynamic memory allocation

When writing a C program, if the size of an array is not deterministic at compiling time. We need to allocate memory for this array at runtime. C Library provides two functions for dynamic memory allocation: malloc and calloc.

/* test.c */
#include <stdio.h>

int main() {
	// how to use malloc() and calloc()
	int a;
	scanf("%d", &a);
	int *p = (int*)malloc(a*sizeof(int));
	int *q = (int*)calloc(a, sizeof(int));

	free(p);
	free(q);
	return 0;
}

malloc and calloc are very similar, the major difference between them is that the memory allocated by malloc maybe uninitialized while the memory allocated by calloc are all fill with bit 0. That is to say, calloc = malloc + memset. After using the dynamically allocated memory, remember to use free() to return memory chunck back.


Function Parameters Passing

When we need to call a function and pass parameters to this function, in the function we called, the actural parameters will be copied so that the actual parameters will not changed after function finished. As we know, if we want to change the value of an actural paramters in a function, we need to pass the address of this parameters to the function instead of it's value. Let's look at the well-known swap function:

/* test.c */
#include <stdio.h>

void swap_1(int a, int b) {
	int c = a;
	a = b;
	b = c;
}

void swap_2(int *u, int *v) {
	int c = *u;
	*u = *v;
	*v = c;
}

int main() {
	int x = 1, y = 2;
	swap_1(x, y);
	printf("x = %d, y = %d\n", x, y);
	swap_2(&x, &y);
	printf("x = %d, y = %d\n", x, y);
	return 0;
}

Let's compile this program in GCC:

gcc -m32 -o test test.c

The result of those codes are: (on x86_64 Linux using -m32 option when compiling)

x = 1, y = 2
x = 2, y = 1

When x and y are passed to swap_1, the local variable of swap_1 a get the value copy of x and b get the value copy of y. Thus, the swapping operation was done between local variable a and b instead of x and y. After swap_1 is finished, its activation record is destoryed, local variable a and b are nowhere to be found. x and y are remain unchanged.

When &x and &y are passed to swap_2, the local variable of swap_2 u get the value copy of &x and v get the value copy of &y. Here, local variable u itself is an integer pointer, storing the address of x, and pointing to x; local variable v itself is an integer pointer, storing the address of y, and pointing to y. Now, the swapping operation is between x and y because *u = x and *v = y. After swap_1 is finished, its activation record is destoryed, x and y are swapped.

   

There're many more tricky things on function call in C, if you're still interested in it, click here.


Dynamic Allocation in a Function

The code below use a function GetMemory to get dynamic memory:

/* test.c */
#include <stdio.h>

void GetMemory(char *p, int num)
{
    p = (char*)malloc(sizeof(char) * num);
}

int main() {
	char *s;
	GetMemory(s, 100);	// Get 100 byte for s
	s[0] = 'a';
	return 0;
}

Let's compile this program in GCC:

gcc -m32 -o test test.c

The result of those codes are: (on x86_64 Linux using -m32 option when compiling)

Segmentation fault (core dumped)

Function GetMemory failed to allocate memory for s. s is uninitialized, thus when passing s to GetMemory, p get the value of s. And it is p that get allocation of 100 byte instead of s. When GetMemory returned, p is gone. s stays unchanged. How could we modify function GetMemory to meet our requirement?

1. Change the parameter type of GetMemory

/* test.c */
#include <stdio.h>

void GetMemory(char **p, int num)
{
    *p = (char*)malloc(sizeof(char) * num);
}

int main() {
	char *s;
	GetMemory(&s, 100);	// Get 100 byte for s
	s[0] = 'a';
	return 0;
}

2. Change the return type of GetMemory

/* test.c */
#include <stdio.h>

char* GetMemory(char *p, int num)
{
	*p = (char*)malloc(sizeof(char) * num);
	return p;
}

int main() {
	char *s;
	s = GetMemory(s, 100);	// Get 100 byte for s
	s[0] = 'a';
	return 0;
}

Conclusion

This blog talks about dynamic memory allocation and function parameter passing, both of them have issues with pointers. Be very careful to use malloc/calloc/realloc and free. If we don't free a chunck of memory got by dynamically applying, memory leakage will occur.