Chinaunix首页 | 论坛 | 博客
  • 博客访问: 314573
  • 博文数量: 28
  • 博客积分: 2156
  • 博客等级: 大尉
  • 技术积分: 232
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-02 15:31
文章分类

全部博文(28)

文章存档

2011年(7)

2010年(21)

分类: LINUX

2010-07-07 20:53:54

本文对指针进行了深入浅出的细致的讲解,非常适合初学者!



Passing Pointers to Functions

The ability to pass pointers to functions is very useful, but very easy to master. If we were to make a program that takes a number and adds five to it, we might write something like the following:


#include <stdio.h>


void AddFive(int Number)
{
    Number = Number + 5;
}

void main()
{
    int nMyNumber = 18;
    
    printf("My original number is %d\n", nMyNumber);
    AddFive(nMyNumber);
    printf("My new number is %d\n", nMyNumber);
}


However, the problem with this is that the Number referred to in AddFive is a copy of the variable nMyNumber passed to the function, not the variable itself. Therefore, the line Number = Number + 5 adds five to the copy of the variable, leaving the original variable in main() unaffected. Try running the program to prove this.


输出(供参考):

[root@xudonglee APUE]# vi test.c
[root@xudonglee APUE]# cc test.c
test.c: In function ‘main’:
test.c:10: 警告:‘main’ 的返回类型不是 ‘int’
[root@xudonglee APUE]# ./a.out
My original number is 18
My new number is 18


To get around this problem, we can pass a pointer to where the number is kept in memory to the function, but we'll have to alter the function so that it expects a pointer to a number, not a number. To do this, we change void AddFive(int Number) to void AddFive(int* Number), adding the asterisk. Here is the program again, with the changes made. Notice that we have to make sure we pass the address of nMyNumber instead of the number itself? This is done by adding the & sign, which (as you will recall) is read as "the address of."



#include <stdio.h>

void AddFive(int* Number)
{
    *Number = *Number + 5;
}

void main()
{
    int nMyNumber = 18;
    
    printf("My original number is %d\n", nMyNumber);
    AddFive(&nMyNumber);
    printf("My new number is %d\n", nMyNumber);
}


Try coming up with an example of your own to demonstrate this. Notice the importance of the * before Number in the AddFive function? This is needed to tell the compiler that we want to add five to the number pointed to by the variable Number, rather than add five to the pointer itself. The final thing to note about functions is that you can return pointers from them as well, like this:

int * MyFunction();
In this example, MyFunction returns a pointer to an integer.

输出(供参考):

[root@xudonglee APUE]# vi test.c
[root@xudonglee APUE]# cc test.c
test.c: In function ‘main’:
test.c:10: 警告:‘main’ 的返回类型不是 ‘int’
[root@xudonglee APUE]# ./a.out
My original number is 18
My new number is 23




Pointers to Classes

There are a couple of other caveats(注意事项) with pointers, one of which is structures or classes. You can define a class as follows:

class MyClass
{
public:
    int m_Number;
    char m_Character;
};


Then you can define a variable of type MyClass as follows:
MyClass thing;
You should already know this. If not, try reading up on this area. To define a pointer to MyClass, you would use:
MyClass *thing;
...as you would expect. Then you would allocate some memory and make this pointer point to the memory:
thing = new MyClass;
This is where the problem comes in: how then would you use this pointer? Well, normally you would write'thing.m_Number, but you can't with a pointer because thing is not a MyClass, but a pointer to it. So, thing itself does not contain a variable called m_Number; it is the structure that it points to that contains m_Number. Therefore we must use a different convention. This is to replace the . (dot) with a -> (dash followed by a greater than sign). An example showing this is below:

class MyClass
{
public:
    int m_Number;
    char m_Character;
};

void main()
{
    MyClass *pPointer;
    pPointer = new MyClass;

    pPointer->m_Number = 10;
    pPointer->m_Character = 's';

    delete pPointer;
}




Pointers to Arrays

You can also make pointers that point to arrays. This is done as follows:
int *pArray;
pArray = new int[6];
This will create a pointer, pArray, and make it point to an array of six elements. The other method, not using dynamic allocation, is as follows:
int *pArray;
int MyArray[6];
pArray = &MyArray[0];
Note that, instead of writing &MyArray[0], you can simply write MyArray. This, of course, only applies to arrays and is a result of how they implemented in the C/C++ language. A common pitfall is to write pArray = &MyArray;, but this is incorrect. If you write this, you will end up with a pointer to a pointer to an array (no typo), which is certainly not what you want.

Using Pointers to Arrays

Once you have a pointer to an array, how do you use it? Well, let's say you have a pointer to an array of ints. The pointer will initially point to the first value in the array, as the following example shows:

#include <stdio.h>


void main()
{
    int Array[3];
    Array[0] = 10;
    Array[1] = 20;
    Array[2] = 30;

    int *pArray;
    pArray = &Array[0];

    printf("pArray points to the value %d\n", *pArray);
}


To make the pointer move to the next value in the array, we can say pArray++. We can also, as some of you probably guessed by now, say pArray + 2, which would move the array pointer on by two elements. The thing to be careful of is that you know the what the upper bound of the array is (3 in this example), because the compiler cannot check that you have not gone past the end of array when you are using pointers. You could easily end up crashing the system that way. Here is the example again, this time showing the three values that we set:


#include <stdio.h>


void main()
{
    int Array[3];
    Array[0] = 10;
    Array[1] = 20;
    Array[2] = 30;

    int *pArray;
    pArray = &Array[0];

    printf("pArray points to the value %d\n", *pArray);
    pArray++;
    printf("pArray points to the value %d\n", *pArray);
    pArray++;
    printf("pArray points to the value %d\n", *pArray);
}


You can also subtract values, so pArray - 2 is 2 elements from where pArray is currently pointing. Make sure, however, that you add or subtract to the pointer and not to its value. This kind of manipulation using pointers and arrays is most useful when used in loops, such as the for or while loops.

Note also that if you have a pointer to a value, e.g. int* pNumberSet, you can treat it as an array. For example, pNumberSet[0] is equivalent to *pNumberSet; similarly, pNumberSet[1] is equivalent to *(pNumberSet + 1).

One final word of warning for arrays is that if you allocate memory for an array using new, as in the following example:
int *pArray;
pArray = new int[6];
...it must be deleted using the following:
delete[] pArray;
Notice the [] after delete. This tells the compiler that it is deleting a whole array and not just a single item. You must use this method whenever arrays are involved; otherwise, you will end up with a memory leak.



Last Words

One final note: you must not delete memory that you did not allocate using new, as in the following example:

void main()
{
    int number;
    int *pNumber = number;
    
    delete pNumber; // wrong - *pNumber wasn't allocated using new.


}




Common Questions and FAQ

Q: Why do I get "symbol undefined" errors on new and delete?

A: This is most likely caused by your source file being interpreted by the compiler as being a plain C file. The new and delete operators are a new feature of C++. This is usually remedied by ensuring that you are using a *.cpp extension on your source code files.

Q: What's the difference between new and malloc?

A: new is a keyword only present in C++ and is now the standard way (other than using Windows' memory allocation routines) to allocate memory. You should never use malloc within a C C++ application unless absolutely necessary. Because malloc is not designed for the object-oriented features of C++, using it to allocate memory for classes will prevent the constructor of the class being called, as just one example of the problems that can arise. As a result of the problems that arise from the use of malloc and free, and because they are now for all intents and purposes obsolete, they are not discussed in any detail in this article. I would discourage their use wherever possible.

Q: Can I use free and delete together?

A: You should free memory with the equivalent routine to that used to allocated it. For instance, use free only on memory allocated with malloc, delete only on memory allocated with new and so on.



References

References are, to a certain degree, out of the scope of this article. However, since I've been asked many times by people reading this about them, I will discuss them briefly. They are very much related to pointers in that, in many cases, they can be used as a simpler alternative. If you recall from above, I mentioned that the ampersand (&) is read as "the address of" unless in a declaration. In the case of its presence in a declaration such as that shown below, it should be read as "a reference to."
int& Number = myOtherNumber;
Number = 25;
The reference is like a pointer to myOtherNumber, except that it is automatically dereferenced. So, it behaves just as it were the actual value type rather than a pointer type. The equivalent code to this, using pointers, is shown below:
int* pNumber = &myOtherNumber;
*pNumber = 25;
The other difference between pointers and references is that you cannot "reseat" a reference. That is to say that you cannot change what it is pointing to after its declaration. For instance, the following code would output "20."

int myFirstNumber = 25;
int mySecondNumber = 20;
int &myReference = myFirstNumber;

myReference = mySecondNumber;

printf("%d", myFristNumber);


When in a class, the value of the reference must be set by the constructor in the following way:


CMyClass::CMyClass(int &variable) : m_MyReferenceInCMyClass(variable)
{
    // constructor code here


}




Summary

This topic is very hard to master initially, so it is worth looking over at least twice: most people do not understand it immediately. Here are the main points again:
  1. Pointers are variables that point to an area in memory. You define a pointer by adding an asterisk (*) in front of the variable name (i.e. int *number).
  2. You can get the address of any variable by adding an ampersand (&) in front of it, i.e. pNumber = &my_number.
  3. The asterisk, unless in a declaration (such as int *number), should be read as "the memory location pointed to by."
  4. The ampersand, unless in a declaration (such as int &number), should be read as "the address of."
  5. You can allocate memory using the new keyword.
  6. Pointers MUST be of the same type as the variables you want them to point to; so, int *number will not point to a MyClass.
  7. You can pass pointers to functions.
  8. You must delete memory that you have allocated by using the delete keyword.
  9. You can get a pointer to an array that already exists by using &array[0];.
  10. You must delete an array that is dynamically allocated using delete[], not just delete.
This is not an absolutely complete guide to pointers. There are a few other things that I could have covered in more detail, such as pointers to pointers, and also things that I chose not to cover at all, such as function pointers, which I believe are too complex for a beginner's article. There are also things which are used rarely enough that a beginner would be better off not being flummoxed(使困惑,使慌乱) by these unwieldy(难使用的;难驾驭的, 难控制的) details.

That's it! Try running some of the programs presented here and come up with some examples of your own.





阅读(778) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~