指针介绍
指针的声明与其他任何变量一样,除了在变量的类型和名称之间放置星号(*
)以表示它是一个指针。
int *pointer; /* inside a function, pointer is uninitialized and doesn't point to any valid object yet */
要声明两个相同类型的指针变量,请在同一声明中使用每个标识符前面的星号。例如,
int *iptr1, *iptr2;
int *iptr3, iptr4; /* iptr3 is a pointer variable, whereas iptr4 is misnamed and is an int */
由&符号(&
)表示的地址或引用运算符给出了给定变量的地址,该变量可以放在适当类型的指针中。
int value = 1;
pointer = &value;
由星号(*
)表示的间接或解除引用运算符获取指针指向的对象的内容。
printf("Value of pointed to integer: %d\n", *pointer);
/* Value of pointed to integer: 1 */
如果指针指向结构或联合类型,那么你可以取消引用它并使用 ->
运算符直接访问其成员:
SomeStruct *s = &someObject;
s->someMember = 5; /* Equivalent to (*s).someMember = 5 */
在 C 中,指针是一种不同的值类型,可以重新分配,否则将被视为一个变量。例如,以下示例打印指针(变量)本身的值。
printf("Value of the pointer itself: %p\n", (void *)pointer);
/* Value of the pointer itself: 0x7ffcd41b06e4 */
/* This address will be different each time the program is executed */
因为指针是一个可变变量,所以它可能无法通过设置为 null 来指向有效对象
pointer = 0; /* or alternatively */
pointer = NULL;
或者只是包含一个不是有效地址的任意位模式。后者是一个非常糟糕的情况,因为在指针被取消引用之前无法测试,只有对指针为空的情况进行测试:
if (!pointer) exit(EXIT_FAILURE);
如果指针指向有效对象,则只能取消引用指针,否则行为未定义。许多现代实现可能会通过引发某种错误(如分段错误和终止执行) 来帮助你,但其他实现可能只会使你的程序处于无效状态。
解引用运算符返回的值是原始变量的可变别名,因此可以更改它,修改原始变量。
*pointer += 1;
printf("Value of pointed to variable after change: %d\n", *pointer);
/* Value of pointed to variable after change: 2 */
指针也可以重新分配。这意味着指向对象的指针稍后可用于指向同一类型的另一个对象。
int value2 = 10;
pointer = &value2;
printf("Value from pointer: %d\n", *pointer);
/* Value from pointer: 10 */
与任何其他变量一样,指针具有特定类型。例如,你不能将 short int
的地址分配给指向 long int
的指针。这种行为被称为类型惩罚,并且在 C 中是被禁止的,尽管有一些例外。
尽管指针必须是特定类型,但为每种类型的指针分配的内存等于环境用于存储地址的内存,而不是指向的类型的大小。
#include <stdio.h>
int main(void) {
printf("Size of int pointer: %zu\n", sizeof (int*)); /* size 4 bytes */
printf("Size of int variable: %zu\n", sizeof (int)); /* size 4 bytes */
printf("Size of char pointer: %zu\n", sizeof (char*)); /* size 4 bytes */
printf("Size of char variable: %zu\n", sizeof (char)); /* size 1 bytes */
printf("Size of short pointer: %zu\n", sizeof (short*)); /* size 4 bytes */
printf("Size of short variable: %zu\n", sizeof (short)); /* size 2 bytes */
return 0;
}
(注意:如果你使用的是不支持 C99 或 C11 标准的 Microsoft Visual Studio,则必须在上面的示例中使用 %Iu
1 而不是%zu
。)
请注意,上面的结果可能因环境而异,但所有环境对于不同类型的指针都会显示相同的大小。
根据卡迪夫大学 C 指针介绍的信息提取
指针和数组
指针和数组在 C 中紧密相连 .C 中的数组总是保存在内存中的连续位置。指针算术始终按指向的项目大小进行缩放。因此,如果我们有一个三个双打的数组,以及指向基数的指针,则*ptr
指的是第一个双重,*(ptr + 1)
指向第二个,*(ptr + 2)
指向第三个。更方便的表示法是使用数组符号 []
。
double point[3] = {0.0, 1.0, 2.0};
double *ptr = point;
/* prints x 0.0, y 1.0 z 2.0 */
printf("x %f y %f z %f\n", ptr[0], ptr[1], ptr[2]);
所以基本上 ptr 和数组名称是可以互换的。此规则还意味着数组在传递给子例程时会衰减到指针。
double point[3] = {0.0, 1.0, 2.0};
printf("length of point is %s\n", length(point));
/* get the distance of a 3D point from the origin */
double length(double *pt)
{
return sqrt(pt[0] * pt[0] + pt[1] * pt[1] + pt[2] * pt[2])
}
指针可以指向数组中的任何元素,也可以指向最后一个元素之外的元素。但是,将指针设置为任何其他值(包括数组之前的元素)是错误的。 (原因是在分段体系结构上,第一个元素之前的地址可能跨越段边界,编译器确保最后一个元素加上一个元素不会发生)。