C/C++ Frequent Pointer Mistakes


C/C++ is powerful because of pointers. The pointers are used to represent the address of some memory locations. Pointers can be involved in arithmetic operations, for example, int *p; p ++ means p is the pointer to integer and p moves to the next int (4 byte offset).

The pointers are so powerful that most mistakes will not be captured by compiler at compilation time. Instead, they will cause errors if pointers point to invalid memory locations (Access Read/Write error). Operating systems have a protected memory space for each application and if your application tries to access the memory that does not belong to you (some applications else) then this will be captured and warned.

Pass pointer as parameter

If the pointer is passed as parameter, use it to get memory is incorrect. For example,

1
2
3
4
5
6
7
8
9
void GetMemory(char *p, int num) {
  p = (char *)malloc(sizeof(char) * num);
}
 
void Test() {
  char *str = NULL;
  GetMemory(str, 100);  // str is still NULL
  strcpy(str, "Hello"); // error
}
void GetMemory(char *p, int num) {
  p = (char *)malloc(sizeof(char) * num);
}

void Test() {
  char *str = NULL;
  GetMemory(str, 100);  // str is still NULL
  strcpy(str, "Hello"); // error
}

The reason behind this is because when passing char *p to function, the compiler makes a copy of the pointer value, which is _p, the allocation inside the function is for the copy pointer _p, so when the function exits, the pointer _p is destroyed and there is always a memory leak because _p is not properly freed.

The easiest way to avoid this is to make char* &p as a reference (however, reference is not present in C). the Reference sign (&) can be treated as a read-only pointer, which is less error-prone but yet powerful enough.

The other method to allocate the memory using the pointer parameter is to declare the pointer as char **p which is essentially the same as the char* &p with only difference is that the char **p is the pointer to the pointer and the char* &p is the reference (read only pointer) to the pointer.

1
2
3
4
5
6
7
8
9
10
void GetMemory(char **p, int num) {
  *p = (char *)malloc(sizeof(char) * num); // allocate space on heap
}
 
void Test() {
  char *str = NULL;
  GetMemory(&str, 100); // passing as the address, which is type of char **
  strcpy(str, "Hello");
  free(str);   // remember to clean it up
}
void GetMemory(char **p, int num) {
  *p = (char *)malloc(sizeof(char) * num); // allocate space on heap
}

void Test() {
  char *str = NULL;
  GetMemory(&str, 100); // passing as the address, which is type of char **
  strcpy(str, "Hello");
  free(str);   // remember to clean it up
}

Return type is pointer

Allocate the memory in function and you can return the pointer. For example,

1
2
3
4
5
6
7
8
9
10
11
char* GetMemory(int num) {
  char *p = (char*)malloc(sizeof(char) * num); // allocate space on heap
  return p;
}
 
void Test() {
  char *str = NULL;
  str = GetMemory(100);
  strcpy(str, "Hello");
  free(str);
}
char* GetMemory(int num) {
  char *p = (char*)malloc(sizeof(char) * num); // allocate space on heap
  return p;
}

void Test() {
  char *str = NULL;
  str = GetMemory(100);
  strcpy(str, "Hello");
  free(str);
}

The above is straightforward and very simple way to allocate and return new memory inside a function. The memory allocated should be in the heap, which needs manual de-allocation (freed). If the memory resides in the stack, it will not work. For example,

1
2
3
4
5
6
7
8
9
10
char* GetMemory() {
  char p[] = "Hello, world!"; // variable in space destroyed when function exits
  return p;
}
 
void Test() {
  char *str = NULL;
  str = GetMemory();
  cout << str << endl; // the str contains random characters
}
char* GetMemory() {
  char p[] = "Hello, world!"; // variable in space destroyed when function exits
  return p;
}

void Test() {
  char *str = NULL;
  str = GetMemory();
  cout << str << endl; // the str contains random characters
}

The variables allocated on stack will be destroyed automatically when function exits, and that is why the str will contain random characters when accessed outside the function.

If we rewrite above into this,

1
2
3
4
5
6
7
8
9
10
char* GetMemory() {
  char *p = "Hello, world!"; // p points to the static constant string
  return p;
}
 
void Test() {
  char *str = NULL;
  str = GetMemory();
  cout << str << endl; // works!
}
char* GetMemory() {
  char *p = "Hello, world!"; // p points to the static constant string
  return p;
}

void Test() {
  char *str = NULL;
  str = GetMemory();
  cout << str << endl; // works!
}

It works, however the idea is wrong. The char *p will always point to the same location, i.e. the static constant string, which will never change during the application’s runtime.

–EOF (The Ultimate Computing & Technology Blog) —

GD Star Rating
loading...
694 words
Last Post: How to Evaluate Reverse Polish Notation using Stack?
Next Post: Easy Math Tip and LUA verification

The Permanent URL is: C/C++ Frequent Pointer Mistakes

Leave a Reply