对于初学C语言的朋友,除了觉得指针有点神秘之外,最大的问题之一可能是理解指针到底是用来干什么的。
我会回答说:“指针绝对是必不可少的,我们会一直使用,请相信我”,你可能会丢我砖头(说不定还有西红柿和鸡蛋) :P ,因为我说了等于没说。
好吧,我会给你一个问题,你会发现假如不用指针是不能解决的。这个问题有点类似我们这一课的引子。在这一课的结尾我们还会重新来谈这个问题,并看一下用我们马上要学到的知识如何解决。
问题是这样:
我要写一个函数,它返回两个值。
“这不可能!” 你会理直气壮地说。
确实啊,之前我们学过:一个函数只能通过return返回一个值:
int function()
{
return value;
}
如上,我们将函数的返回值类型定为int,那么就用return返回一个int类型的值。
我们也可以不返回任何值,只要把函数的返回值类型定为void:
void function()
{
}
你会说:“是啊,要一个函数一次返回两个值,不可能啊,我们不能写两个return啊。臣妾做不到啊...”
假设我要写的这个函数是这样:
《
我们给它输入的参数是一个分钟数,它返回给我们两个值:小时数和分钟数。例如:
传给函数30,它返回0小时30分钟
传给函数60,它返回1小时0分钟
传给函数90,它返回1小时30分钟
》
我们可以试着来写一下这个函数:
#include <stdio.h>
/* 我把函数原型放在开头了,并没有用到.h头文件,因为程序实在太小了。当然在正常情况下,一般是用.h头文件比较好 */
void transformMinutes(int hours, int minutes);
int main(int argc, char *argv[])
{
int hours = 0, minutes = 90;
/* 我们的分钟数是 90。我想要在调用transformMinutes函数后,小时数变为1,分钟数变为30 */
transformMinutes(hours, minutes);
printf("%d 小时 : %d 分钟\n", hours, minutes);
return 0;
}
void transformMinutes(int hours, int minutes)
{
hours = minutes / 60; // 90 / 60 = 1
minutes = minutes % 60; // 90 % 60 = 30
}
看上去还不错对么?我们来运行一下这个程序。输出:
0 hours and 90 minutes
不对,不对,这个函数没有按照我们所想的来运行嘛!
到底这里发生了什么呢?
事实上,C语言的函数参数默认是传值调用的,就是说当我们传给函数的参数一个变量时,事实上传递的是这个变量的一份拷贝,并不是这个变量本身!程序会先对这个要传递给函数的变量做一份拷贝,然后把这份拷贝传给函数使用。
所以说:上面我们main函数里的hours变量和实际传给transformMinutes函数的hours,是不一样的,传给transformMinutes函数的只是hours变量的一个拷贝而已。就好比用复印机复印了一份纸张,内容是一样,但是一个是原件,一个是复印件。
当然了,我们的函数transformMinutes很乖很呆萌,你叫它干的活它肯定出色完成:在函数内部,它把参数hours和minutes的值通过计算转换成了1和30。
但是,注意了,因为transformMinutes拿到的两个参数hours和minutes的值本身只是实际的变量hours和minutes的一份拷贝。而且我们之前学过,在函数结束时,它里面的非static变量都会销毁,所以hours和minutes这两个拷贝就都会被删除了。
所以函数transformMinutes勤勤恳恳地工作之后,把程序交还给main函数继续执行,但是hours和minutes这两个main函数里的变量的值并没有被改变,还是0和90。可惜啊!
注意:函数的参数的名字和要传给它的变量的名字不需要是一样的,上例中我们为了清楚表示含义,才把main函数里的两个变量和函数transformMinutes的两个参数都命名为hours和minutes,其实你大可以把函数的参数写成随便什么名字,例如
void transformMinutes(int h, int m)
简而言之,问题还是在那里。
这里我们需要用函数来改变两个变量的值,我们不能用return,因为一个函数只能return一个返回值;也不能用全局变量,虽然全局变量行得通,但是我们之前的课已经说了,尽量不用这种不安全的变量。
那么指针到底能怎样来解决我们的难题呢?我们慢慢道来。