指针是一种数据类型,它占用内存空间,存储着一个内存地址。这篇笔记我们介绍C语言中指针的用法。
把一个变量所在的内存单元的地址保存在另外一个内存单元中,保存地址的这个内存单元称为指针,通过指针和间接寻址访问变量,这种指针在C语言中可以用一个指针类型的变量表示,例如某程序中定义了以下全局变量。
int i;
int *pi = &i;
char c;
char *pc = &c;
*
号是指针间接寻址运算符&
是取地址运算符用一个指针给另一个指针赋值时要注意,两个指针必须是同一类型的,但是可以先强制类型转换然后赋值,例如把char*
赋值给int*
。为避免出现野指针,在定义指针变量时就应该给它明确的初值,或者把它初始化为NULL。NULL是一种特殊的指针值,表示不指向任何内存,对值为NULL的指针解引用的不合法的。
在编程时经常需要一种通用指针,可以转换为任意其它类型的指针,任意其它类型的指针也可以转换为通用指针。void*
指针与其它类型的指针之间可以隐式转换,而不必用类型转换运算符。
void func(void *pv)
{
/* *pv = 'A' is illegal */
char *pchar = pv;
*pchar = 'A';
}
int main(void)
{
char c;
func(&c);
printf("%c\n", c);
// ...
}
#include <stdio.h>
int *swap(int *px, int *py)
{
int temp;
temp = *px;
*px = *py;
*py = temp;
return px;
}
int main(void)
{
int i = 10, j = 20;
int *p = swap(&i, &j);
printf("now i=%d j=%d *p=%d\n", i, j, *p);
return 0;
}
数组做右值自动转换成指针,指针可以加减操作。以下三种写法等价:
void func(int a[10]) {}
void func(int *a) {}
void func(int a[]) {}
注:参数写成指针形式还是数组形式对编译器来说没区别,都表示这个参数是指针,之所以规定两种形式是为了给读代码的人提供有用的信息,如果这个参数指向一个元素,通常写成指针的形式,如果这个参数指向一串元素中的首元素,则经常写成数组的形式。
const
限定符可以用如下方式理解:
//a指向const int,a指向的内存单元不能改写,a可以改写
const int *a;
int const *a;
//a是指向int的const指针,*a可以改写,a不能改写
int * const a;
//a是指向const int的const指针,*a a 都不能改写
int const * const a;
指向非const
变量的指针或者非const
变量的地址可以传给指向const
变量的指针,编译器可以做隐式类型转换,例如:
char c = 'a';
const char *pc = &c;
但是,指向const
变量的指针或者const
变量的地址不可以传给指向非const
变量的指针,以免透过后者意外改写了前者所指向的内存单元,例如对下面的代码编译器会报警告:
const char c = 'a';
char *pc = &c;
即使不用const
限定符也能写出功能正确的程序,但良好的编程习惯应该尽可能多地使用const
,因为:
字符串做右值和数组一样自动转换成指针。但要尤其注意的是,字符串字面值是不能改写的,如果把字符串传给一个指针,指针又改写了某些值,编译正常,但运行时报错。
const char *p = "abcd";
const char str1[5] = "abcd";
char str2[5] = "abcd";
使用->
可以访问结构体指针成员,(*p).c
等价于p->c
。
#include <stdio.h>
struct complex_struct
{
double x, y;
};
int main(void)
{
struct complex_struct cs = {1, 2};
struct complex_struct *csp = &cs;
printf("%f\n", csp->x);
return 0;
}
在C语言中,函数也是一种类型,可以定义指向函数的指针。我们知道,指针变量的内存单元存放一个地址值,而函数指针存放的就是函数的入口地址(位于.text
段)。
#include <stdio.h>
void say_hello(const char *str)
{
printf("Hello %s\n", str);
}
int main(void)
{
void (*f)(const char *) = say_hello;
f("Guys");
return 0;
}
void (*f)(const char *)
的解释:这个写法声明了一个变量f
,f
首先跟*
号结合在一起,因此是一个指针。(*f)
外面是一个函数原型的格式,参数是const char *
,返回值是void,所以变量f
是指向这种函数的指针。函数名做右值自动转换成函数指针。也可以写成void (*f)(const char *) = &say_hello
;