Lovely Pointers

Environment: C++, VC++, MFC

Introduction

The topic of this article is pointers. Below, I describe some problems, bugs, and technique solutions that correspond to using pointers. This article would be useful for beginners and programmers who are using other programming languages and are starting to study C and C++ now.

1. Bad pointers

There are a lot of programmers who think that pointers are as bad a kind of construction as the "goto" operator. Pointers are so bad that you cannot find them in Basic, Java, or C#. But, really, it is not true. All applications that are executed under Windows or Unix use pointers! A lot of API functions receive pointers and return pointers; so, if you use API, you use pointers.

For example, if I declare in a VBasic program such an API function interface:

Private Declare Sub SetLocalTime Lib "kernel32"
        (localTime As SYSTEMTIME)

Basic instruction:

Call SetLocalTime(tmLocal)

will send to API function the pointer to the SYSTEMTIME structure.

Why don't many languages support pointers as a language construction? Because pointers are dangerous. It is easy to make an error that a compiler will not find. It is more possible to make an error that you will not find while debugging the program. If your program is alive, it is only because it has not been started by the right user. A good user will always find a way to crash your program.

Here is an example of a very common pointers-related error:

char * CloneName(char *pSomeName)
  {
    char *pTmpName = new char[strlen(pSomeName)];    // Error!
    strcpy(pTmpName, pSomeName);
    return pTmpName;
  }

This function must clone a string. In this example, one byte of memory will be destroyed behind the copy of the string. The right allocation instruction is new char[strlen(pSomeName) +1]. A string in C and C++ is finished by zero code. This error can crash your program immediately, once in a while, or never! Everything depends on a byte behind a string.

2. Good Pointers

A pointer is a language construction of C++. Historically, this language continues the C language tradition that was created as a good alternative to the assembler language. Pointers allow a programmer to manage memory allocation very efficiently. If you work accurately, everything will be OK.

3. What Is a Pointer?

A pointer is a special variable that is used for storing some memory address. So, sizeof(pointer) is small and depends on the operating system. For Win32, it equals 4 bytes. A pointer has a type "Pointer to some type." A pointer can be converted to an integer value and an integer value can be converted to a pointer. It is used widely in the Windows API functions.

Here is a title of "the main" windows function. It sends a message to a window.

LRESULT SendMessage(
    HWND hWnd,      // handle of destination window
    UINT Msg,       // message to send
    WPARAM wParam,  // first message parameter
    LPARAM lParam   // second message parameter
  );

WPARAM and LPARAM are integer types. But, many messages use them as pointers. For example, I want to print text in some window with handle hWnd. I do so tis way:

SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)"Some Text");

"Some Text" is a static text constant. It has an address in a memory and type char *. This example shows the conversion from char* to integer (LPARAM is a long integer). A pointer is also an array. An array type is not actually the same as a pointer type. But, it is very close to a pointer and easy to convert to a pointer. All dynamic arrays are pointers.

4. Pointers and Arrays

This is an article. I do not want to rewrite some C++ book. So, I will demonstrate here only one interesting example. It shows the difference between using a 2D automatic array and a 2D dynamic array.

#include <iostream.h>


void OutAutoElm(int nRow, int nCol, int *pAutoArray, int nSize);
void OutDynElm(int nRow, int nCol, int **pDynArray);


int main(int argc, char* argv[])
{
  const int nSize = 5;            // Size of matrix

  int AutoArray[nSize][nSize];    // Auto Array. Allocate memory
                                  // in the stack.
  **DynArray;                     // Dynamic Array pointer.

  // Memory allocation for Dynamic Array in the heap.
  DynArray = new int*[nSize];
  for(int i=0; i< nSize; i++){
    DynArray[i] = new int[nSize];
  }

  AutoArray[2][3] = 7;                         // Assign some
                                               // element of
                                               // AutoArray
  OutAutoElm(2, 3, (int *)AutoArray, nSize);   // and call output
                                               // function

  DynArray[3][4] = 9;           // Assign some element of
                                // DynamicArray
  OutDynElm(3, 4, DynArray);    // and call output function

  AutoArray[5][0] = 10;         // Error! Outside of the array.
                                // The last element is [4][4]
                                // But the program executed in my
                                // system without any errors.

  // Release memory of Dynamic Array
  for(i=0; i< nSize; i++){
    delete[] DynArray[i]; 
  }
  delete[] DynArray;

  return 0;
}

void OutAutoElm(int nRow, int nCol, int *pAutoArray, int nSize)
{
  int nValue = *(pAutoArray + nRow*nSize + nCol);
    // What a strange expression!
    cout << "AutoArray["<<nRow<<"]["<<nCol<<"]
            ="<< nValue << endl;
}

void OutDynElm(int nRow, int nCol, int **pDynArray)
{
  int nValue = pDynArray[nRow][nCol];    // Looks Normal
  cout << "DynArray["<<nRow<<"]["<<nCol<<"]
          ="<< nValue << endl;
}

A very interesting example! AutoArray[2][3] = 7 and DynArray[3][4] = 9 looks like the same instructions. But one of them is *(AutoArray + 2 * 5 + 3) = 7; the other is *(*(DynArray+3)+4) = 9; See Figure 1.



Click here for a larger image.

Figure 1

5. Dangers

There are some common errors when using pointers. Most of them are very dangerous because they can be executed in your system without runtime errors. And nobody knows when and where they will crash the system.

  1. Using a pointer without memory allocation.
  2. Example:
    
    char *Str;
    cin >> Str;
    
  3. Array overflow. See an example in the previous paragraphs.
  4. Sending a value to the function that waits for a pointer.
  5. Example (popular beginner error):
    
    int nSomeInt = 0;
    scanf("%d", nSomeInt);     // send the value
    

    scanf is defined as int scanf(const char *, ...) . The compiler cannot test variables types. So, you will not receive an error or warning message.

    right solution is:
    
    int nSomeInt = 0;
    scanf("%d", &nSomeInt);    // send the pointer
    
  6. Pointer release errors. A common error is a memory leak. We use the "new" statement without the "delete" statement. Some other errors are shown below.
  7. Example 1:
    
    int *pArray = new int[10];
    ...
    delete pArray;    // must be delete[] pArray
    
    
    Example 2:
    
    int a = 0;
    int*p = &a;
    delete p;    // Nothing for release! Use delete only
                 // when instruction "new" was used!
    
    
    Example 3:
    
    int *a = new int;
    int *b = a;
    delete a;
    delete b;    // Error. The memory was cleared by previous
                 // delete.
    
  8. Type conversion errors. We can convert a pointer to a wrong type and use it.
  9. Example:
    
    class A{};
    class B{ public: B():M(5){} int M; }; int main(int argc, char* argv[]) { A* pA = new A; B* pB = new B; cout << ((B*)pA)->M << endl; //Error! There is no M in A! }
  10. Strange allocation. It is not my fantasy. I met the same code!
  11. void SomeFun(int a);
    ....
    int main(){
      SomeFun(*(new int) );    // Temporary variable with
                               // memory allocation.
                               // Deleting memory is impossible.
    }
    

Here I described only plain errors that are common for the C and C++ languages. When we use classes, inheritance, multiple inheritance, templates, and other OOP constructions, we have many more opportunities for making mistakes with pointers. Be optimistic!

6. Recommendations

There are some rules that could prevent you from many errors.

  1. Use pointers only if you really need to. The common situations for using pointers are: creating a dynamic array, creating an object in one function and deleting it in another function, and receiving a pointer from a library function. Do not use a pointer if you can use an automatic variable or a reference instead.
  2. If you do not allocate memory while a pointer is defined, set it to NULL. Null pointers are pretty much suited for debugging the non-initialized pointers.
  3. Example:
    
    int *pSome = NULL;
    
  4. Always test pointers returning by functions to NULL.
  5. Example:
    
    if ( ( pFile = fopen("SomeFile","r") ) == NULL){
        cerr << "SomeFile Open Error!" << end;
    }
    
  6. Always test incoming pointers using assert macros. It works only in the debugging mode; they're ignored the release mode.
  7. Example:
    
    void SomeFun(SomeType *pSomePointer){
      ASSERT(pSomePointer);
      . . .
    }
    
  8. Never use C-style strings and C-style arrays. Always use library classes instead.
  9. STL using example:
    
    #include <string>
    #include <vector>
    #include <iostream>
    
    using namespace std;
    
    int main(int argc, char* argv[])
    {
      string sName1 = "Jeanne";    // Some string object.
                                   // Use instead char *
      vector<string> sNames;       // Some array of strings.
                                   // Use instead char**
    
      sNames.push_back(sName1);
      sNames.push_back("Ann");
      sNames.push_back("George");
    
    for(int i=0; i < sNames.size(); i++){
      cout << sNames[i] << endl;
      }
    
      return 0;
    }
    

    As you see, there are no pointers, "new", and "delete" operations in this example. Same MFC classes are called CString and CArray.

  10. If you use a standard string or container class and need the pointer to its data, you can easily get it. All classes have corresponding methods or operators.
  11. MFC Examples:
    
    CString sSomeStr;
    (LPCTSTR) sSomeStr;    // char * pointer to the string buffer
    
    CArray <int,int> SomeArray;
    SomeArray.GetData( );  // int * pointer to the array buffer
    
    
    STL examples:
    
    string sSomeStr;
    sSomeStr.c_str();    // char * pointer to the string buffer
    
    vector <int> SomeArray;
    &SomeArray[0];       // int * pointer to the array buffer
    

    Remember about dangers! Use such conversions only if you really need to. For example, if you need send a pointer to a library function, ot can be a Win API function or other.

  12. When you need to send some big object to a function, use the reference instead the pointer. At least you cannot change the memory address of reference.
  13. Use new type conversion operator static_cast instead the old style conversion.
  14. Example:
    
    A* pA = new A;
    B* pB = new B;
    
    cout << ((B*)pA)->M << endl;
        // Compiler said "OK!"
    cout << static_cast<B*>(pA)->M << endl;
        // Compiler said "Error!"
    
  15. Use constant modify where it is possible
  16. Example:
    
    int a = 5;
    const int* p1 = &a;        // You cannot change pointer value
    int* const p2 = &a;        // You cannot change pointer
    const int* const p2 = &a;  // You cannot change anything
    
  17. Remember that every "new SomeType" operator needs a "delete PointerSomeType" operator, and every "new SomeType[]" operator needs a "delete[] PointerSomeType" operator.
  18. Remember that if your program works correctly, it does not mean that it has no pointer errors inside. Errors can appear on another computer in another time. Be accurate!

Announcement

I described only plain problems of using pointers in this article. I plan to continue this topic in the next article that would be called "Pointers and Classes."

Links

Author's home site: http://www.brigsoft.com
Link to author's other sources and articles: http://www.brigsoft.com/edu
Link to the previous article of this series: http://brigsoft.com/edu/DebuggingTrap/DebugginTrap.htm

© Alex Rest, 2003



Comments

  • Would a Scott win be the end of long putters

    Posted by zrqrftfnoe on 05/17/2013 06:35pm

    Would a Scott win be the end of long putters? On [url=http://jordanscheap.page4.me/]air jordans cheap[/url] Saturday at Royal Lytham St. Annes, U.S. Golf Association executive director Mike Davis talked with GolfChannel.com about the ongoing discussions to either adjust the current Rules of Golf and deem the club, and anchoring, non-conforming or maintain the status quo. We are committed to give some sort of answer this year, Davis said before venturing out as a walking rules official with the Tiger Woods group at Lytham. The reason for that is we ve told the world we re taking a fresh look at this mostly because in the last year and half things have changed. Last year Keegan Bradley became the first player to win a major using a longer-than-standard-length putter and Webb Simpson followed him to the winner s circle at last month s U.S. Open. Scott would make it a cool threesome. My putting with the short putter was so hot and cold, and before I switched it was more often cold than hot, said Scott, who is currently tied for 15th in putting with a 1.53 average. I putt much more consistent with it, which has a really positive effect on the rest of my game.It takes a little pressure off the rest of my game. But, according to Davis, this has less to do with what s happening at the game s highest levels than it does the growing popularity of long putters at the grassroots level. There s a lot more recreational players going to this. There are instructors who are telling golfers this is a better way to putt and this wasn t happening before, Davis said. While this has been around for a decade, or decades, it s different now. We re seeing a lot more used, particularly in the United States. Although the governing bodies plan to make a decision before the end of the year, Davis said he doesn t anticipate an actual change to occur before the end of the current rules cycle, which runs until January 2016. Davis stressed that no decision has been made on the issue and that officials from the USGA and Royal Ancient Golf Club of St. Andrews will meet this week to discuss the subject. We re coming to the point where it is our hope that by this fall we have made a final decision, he said. Are we happy with this stroke? Is it something that 50 years from now if 50 percent of the golf public is using this are we happy with that? That s really the issue. As for the idea that a potential Scott victory this week would tip the scales against long putters Davis was clear, That has almost zero to do with it. If we did something we talked about this before any of these guys won majors. We took this to the table before that.

    Reply
  • Dynamic Multidimenional Arrays

    Posted by Legacy on 08/19/2003 12:00am

    Originally posted by: Guy McMackerson

    Nice example but, the first coordinate on DynArray... suppose you use new int* [10] and then iterate through that and new int [20] in there, does that mean you access the last element as DynArray[9][19] or DynArray[19][9]?

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • Agile methodologies give development and test teams the ability to build software at a faster rate than ever before. Combining DevOps with hybrid cloud architectures give teams not just the principles, but also the technology necessary to achieve their goals. By combining hybrid cloud and DevOps: IT departments maintain control, visibility, and security Dev/test teams remain agile and collaborative Organizational barriers are broken down Innovation and automation can thrive Download this white paper to …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds