分类: C/C++
2013-05-18 23:41:05
很多C语言新手对指针表示很苦恼,也有很多人就是因为指针而对C语言失去了学习的兴趣。那么指针到底是什么?为什么指针会让那么多初学者如此苦恼呢?甚至直接让那些计算机专业的学生因此而放弃从事编程呢?下面就让我以自己那粗浅的认识谈谈吧。
首先,说到指针我们就会立即想到地址,地址又是什么呢?地址就是变量保存的位置,也就是变量的家的门牌号。我们要获取变量的值那就必须到保存这个变量的地址去查看,就像我们要知道一个人的具体家境,我们就需要到他家去看看,那就必须要到知道他家的门牌号,这样找到了他家,我们就能亲眼看到他的情况。这就是地址。
那么指针和地址到底什么关系呢?地址就是位置,而指针除了是位置还说明了这个位置的类型,比如表明这个地址保存的是什么类型的数据。
其实指针并不恐怖,其实任何变量都是存放在某一地址处的,也就是说其实指针就是给了我们门牌号,而一般非指针变量是给了门牌里对应的人家的内部情况。所以说我们不必去害怕指针,因为它只是门牌号而已。
对于如下指针变量的定义Int *p;其实就是给了一个门牌板子p,板子p上并没有写门牌号具体是多少,但是告诉了我们这是一个要写门牌号的板子,而且告诉了我们这个板子是为中国人(int假如代表中国)制造的,将会挂在一户中国人家的门前。而如下语句int *p;int a;p=&a;这个就是给p板子上写了门牌号了,门牌号就是a的地址。建立一栋别墅,别墅的门牌号就是a的地址,然后有户中国人入住了,就这么简单。
这就是简单的指针变量。
函数参数传递的都是一个个具体值,不管是传一个int还是char或者数组。其实本质都是传递了一个值。如果是int那就是int类型值,如果是char那就是char类型的值,如果是指针或者数组,那就是一个地址的具体值,一个长整型的值。所以说函数传的参数都是具体值,不管你写的是指针还是数组。
现在我们看看例子,定义:void fun(int a,int *p);调用fun(5,&n);这个例子我们看到形参a给的值是5,形参指针p给的是n的地址,地址是个长整型值,所以说函数参数传递的都是值,只是有的传递的是直接的值,有的是地址,对于传的是地址,我们在函数中使用时,就是对这个地址进行赋值或者从地址中取值。我们传参时传地址的好处是我们对其操作不会随函数的终止而丢失。函数内的普通变量是会随函数终止而释放的,静态变量的生存期是整个程序。而我们传地址,我们操作的是地址,那个地址处的值被修改了,但是我们的函数不会因为函数的结束而修改那个地址的值,所以我们传地址的作用就是相当于在函数中使用了全局变量一样。
这只是我的简单理解,也是写给指针的初学者,所以就这样把最简单的意思表达一下,希望能帮助理解吧。
多插一句,对于初学者,很多人对实参和形参分不清楚,实参就是例子中的5和&n,形参就是函数声明中的a和*p,实参和形参在名字上没有任何关系,不用名字相同,但是类型一定要相同。实参是传递给函数的真是值,而形参是接受传来的值的变量。
例子代码:
#include
void fun(int a,int *p)
{
a=10;
*p=10;
}
int main()
{
int a;
int n;
a=5;
n=5;
fun(a,&n);
printf("After fun: a=%d n=%d\n",a,n);
return 0;
}
函数指针,顾名思义就是一个指向函数的指针。我们先看一个例子:
#include
void fun(int a,int *p)
{
a=10;
*p=10;
}
int main()
{
int a;
int n;
void (*p_fun)(int a,int *p);
p_fun=&fun;
a=5;
n=5;
(*p_fun)(a,&n);
printf("After fun: a=%d n=%d\n",a,n);
return 0;
}
我们不用管程序干嘛,我们只要看蓝色的三行。
首先void (*p_fun)(int a,int *p);这一行定义了函数指针,这个指针的地址就是函数的入口。
p_fun=&fun;这一行我们给函数指针一个明确的地址,这样程序就知道从哪里开始运行这个函数。
(*p_fun)(a,&n);这一行是函数指针的使用,程序通过这一行就从函数指针指向的地址进行调用函数。
这样我们就完成了函数指针的完整使用。
通过这个例子,我们可以这样理解函数指针,这是一个指针,只是这个指针指向的地址是一个函数的入口。而函数指针的使用也是和普通变量指针的用法一样,首先定义一个指针void (*p_fun)(int a,int *p);,接着给指针初始化p_fun=&fun;,然后我们才能使用它(*p_fun)(a,&n);。这样我们就可以很好地理解函数指针了。
我们直接来看例子。
#include
void p_fun()
{
printf("void p_fun()\n");
}
void fun(void (*p)())
{
printf("void fun()\n");
(*p)();
}
int main()
{
int a;
int n;
void (*p)();
a=5;
n=5;
p=&p_fun;
fun(p);
printf("After fun: a=%d n=%d\n",a,n);
return 0;
}
从上面我们看出其实函数指针作为参数和我们正常传递一个指针做参数是一样的。仅仅是在声明时存在一点小小的差异。
首先我们要明确:指针数组是数组,数组指针是指针。指针数组的每个数组元素都是一个指针,而数组指针是指向一个数组的指针。
下面我们看一下它们的定义:
Int *p[5];
Int (*p)[5];
首先你需要认识哪个是数组指针,哪个是指针数组。
前者是指针数组,后者是数组指针。
本例中指针数组Int *p[5];这个数组的每个元素是一个int型的指针。数组大小为5*4=20.而数组指针Int (*p)[5];是一个指针p,p所指向的是这个数组的首地址,由于它是一个指针,所以它的大小就是4。