Pointer declaration
指针声明
指针是一种引用另一种类型的函数或对象的对象类型,可能会添加限定符。指针也可能指什么都没有,它由特殊的空指针值表示。
句法
在指针声明的声明语法中,类型说明符
序列指定指向类型(可能是函数或对象类型,可能不完整),声明符
的形式如下:
* qualifiers(optional) declarator | (1) | |
---|
其中声明符可以是标识正在声明的指针的标识符,包括另一个指针声明符(它将指示指向指针的指针):
float *p, **pp; // p is a pointer to float
// pp is a pointer to a pointer to float
int (*fp)(int // fp is a pointer to function with type int(int)
出现在*
和标识符(或其他嵌套声明符)之间的限定符限定了正在声明的指针的类型:
int n;
const int * pc = &n; // pc is a non-const pointer to a const int
// *pc = 2; // Error: n cannot be changed through p without a cast
pc = NULL; // OK: pc itself can be changed
int * const cp = &n; // cp is a const pointer to a non-const int
*cp = 2; // OK to change n through cp
// cp = NULL; // Error: cp itself cannot be changed
int * const * pcp = &cp; // non-const pointer to const pointer to non-const int
说明
指针用于间接寻址,这是一种无处不在的编程技术; 它们可用于实现传递引用语义,访问具有动态存储持续时间的对象,以实现“可选”类型(使用空指针值),结构之间的聚合关系,回调(使用指向函数的指针),通用接口(使用指针void)等等。
指向对象
指向对象的指针可以用应用于对象类型表达式(可能不完整)的地址 - 运算符的结果初始化:
int n;
int *np = &n; // pointer to int
int *const *npp = &np; // non-const pointer to const pointer to non-const int
int a[2];
int (*ap)[2] = &a; // pointer to array of int
struct S { int n; } s = {1}
int* sp = &s.n; // pointer to the int that is a member of s
指针可能作为操作数出现在间接操作符(一元*
)上,后者返回标识指向对象的左值:
int n;
int* p = &n; // pointer p is pointing to n
*p = 7; // stores 7 in n
printf("%d\n", *p // lvalue-to-rvalue conversion reads the value from n
指向结构和联合类型对象的指针也可以作为通过指针运算符访问成员的左侧操作数->。
由于数组到指针的隐式转换,可以使用数组类型的表达式初始化指向数组第一个元素的指针:
int a[2];
int *p = a; // pointer to a[0]
int b[3][3];
int (*row)[3] = b; // pointer to b[0]
某些加法,减法,复合赋值,增量和减量运算符是为指向数组元素的指针定义的。
在某些情况下,为指向对象的指针定义比较运算符:表示相同地址的两个指针比较相等,两个空指针值相等,指向同一数组元素的指针与这些元素的数组索引相同,以及指向struct成员按照这些成员的声明顺序进行比较。
许多实现还提供了随机起源指针的严格总排序,例如,如果它们被实现为连续(“平坦”)虚拟地址空间内的地址。
指向功能
指向函数的指针可以用函数的地址初始化。由于功能到指针的转换,操作符的地址是可选的:
void f(int
void (*pf1)(int) = &f;
void (*pf2)(int) = f; // same as &f
与函数不同,指向函数的指针是对象,因此可以存储在数组中,复制,分配,作为参数传递给其他函数等。
指向函数的指针可以在函数调用操作符的左侧使用; 这会调用指向函数:
#include <stdio.h>
int f(int n)
{
printf("%d\n", n
return n*n;
}
int main(void)
{
int (*p)(int) = f;
int x = p(7
}
解引用函数指针会得到指向函数的函数指示符:
int f(
int (*p)() = f; // pointer p is pointing to f
(*p)( // function f invoked through the function designator
p( // function f invoked directly through the pointer
平等比较运算符定义为指向函数的指针(如果指向相同的函数,则它们相等)。
指针无效
指向任何类型的对象的指针都可以隐式转换为指针void
(可以是const或volatile限定的),反之亦然:
int n=1, *p=&n;
void* pv = p; // int* to void*
int* p2 = pv; // void* to int*
printf("%d\n", *p2 // prints 1
void指针用于传递未知类型的对象,这在通用接口中很常见:malloc
返回值void*
,qsort
期望用户提供的回调接受两个const void*
参数。pthread_create需要用户提供的接受和返回的回调void*
。在所有情况下,调用者有责任在使用前将指针转换为正确的类型。
空指针
每种类型的指针都有一个特殊的值,称为该类型的空指针值
。值为空
的指针不指向对象或函数(取消引用空
指针是未定义的行为),并将相同类型的所有指针值相等,其值也为空
。
要将指针初始化为空值或将空值赋予现有指针,可以使用空指针常量(NULL
或任何其他具有零值的整数常量)。静态初始化还会初始化指向其空值的指针。
空指针可以指示没有对象或可以用来指示其他类型的错误条件。通常,接收指针参数的函数几乎总是需要检查值是否为空,并以不同的方式处理该情况(例如,free
在传递空指针时什么也不做)。
注意
尽管任何指向对象的指针都可以转换为指向不同类型对象的指针,但是取消引用指向与对象的声明类型不同的类型的指针几乎总是未定义的行为。细节请参见严格的别名。
可以通过指针访问对象的函数,这些指针不是别名。详情请参阅限制。 | (自C99以来) |
---|
数组类型的左值表达式在大多数上下文中使用时,会经历到指向数组第一个元素的指针的隐式转换。详情请看阵列。
char *str = "abc"; // "abc" is a char[4] array, str is a pointer to 'a'
指向char的指针通常用于表示字符串。为了表示一个有效的字节串,一个指针必须指向一个字符,它是一个char数组的元素,并且在某个索引处必须有一个char值为零的char大于或等于指针。