这篇文章我们来谈谈指针在函数中的用法,即作为参数和作为返回值的用法。
指针作为参数
下面我们以一个比较经典的例子来说明这个问题——交换函数的实现来介绍这部分内容。下面是一种实现方法:
void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
我们必须知道C语言中用值进行参数传递,所以函数调用中用作实际参数的变量无法改变,因此上面的方法是无效的。为了解决这个问题,我们不再传递变量a
和b
作为函数的实际参数,而是提供&a
和&b
,即指向a
和b
的指针。我们通过间接引用符号*
来间接改变a
和b
中的值。下面是新的swap()
函数:
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
另外我们需要再讨论另一个问题,那就是scanf()
函数,对于这个函数,我想大部分人并不陌生。其实这个函数的第二个参数就是指针变量,因此我们在使用这个函数时,需要向其传递一个指针类型。很多人在使用这个函数时会产生一个误区:传递变量前必须有&
符号,其实这是错误的,正如我们前面所说的,只要求是指针类型。
int a, b;
int *p = &b;
scanf("%d", &a); // 不要漏掉&符号
scanf("%d", p); // p是指针类型,可以不用&符号
假如我们不想让函数对传进来的指针进行修改我们该怎么办呢?你可能会想到const
修饰符,但是const
该如何使用呢?你可能会想到以下几种方式:
void f1(const int *p);
void f2(int const *p)
void f3(int* const p);
void f4(const int* const p);
我们先来谈谈f1
,它的参数是这样的const int *p
,这种写法是限制我们不能修改指针所指向的对象的值。f2
的作用和f1
相同。而f3
的作用是保护指针,即地址不被修改。我们刚刚说的是不能对指针进行修改,因此f3
的这种写法符合我们的需要。其实这三种写法很好区分也很好记,对于f1
和f2
,const
修饰的是*p
,所以它保护的是指针所指向的值;对于f3
,const
修饰的是p
,所以它保护的是指针本身。对于f4
,我想你已经猜出来了,它既对指针本身进行保护,也对指针指向的值进行保护。
- 保护指针指向的值
void f(const int *p)
{
int j;
*p = 0; /***错误***/
p = &j; /***合法***/
}
- 保护指针本身
void f(int* const p)
{
int j;
*p = 0; /***合法***/
p = &j; /***错误***/
}
- 既保护指针,有保护指针指向的值
void f(const int* const p)
{
int j;
*p = 0; /***错误***/
p = &j; /***错误***/
}
作为返回值
我们不仅可以为函数传递指针,还可以编写返回指针的函数。其实这很容易掌握,我们可以返回实际参数传入的指针的其中一个,也可以返回指向外部(全局)变量或者指向声明为static
的局部变量的指针,但是我们不能返回指向局部变量的指针!
int *f(void)
{
int i;
...
return &i;
}
因为局部变量具有自动存储期限,函数调用时“自动”分配,函数返回时收回分配。因此一旦函数f
返回,变量i
就不存在了,所以指向变量i
的指针是无效的。
参考资料
- somnik的博客:全局变量与局部变量的区别
- C语言程序设计现代方法, K.N.King, 人民邮电出版社
网友评论