指针的运算
指针与整数的运算规则:
指针和整数可以进行运算, 其结果为指针
- p + n <==> (unsigned int)p + n * sizeof(*p)
结论: 当指针 p 指向一个同类型的数组的元素时:
- p + 1 将指向当前元素的下一个元素
- p - 1 将指向当前元素的上一个元素
/* 测试代码 */
#include <stdio.h>
int main()
{
int a[5] = {0};
int* p = NULL;
printf("a = 0x%X\n", (unsigned int)(a));
printf("a + 1 = 0x%X\n", (unsigned int)(a + 1)); // a + 1 == 0x22FF18 + 1 * sizeof(int) == 0x22FF18 + 1 * 4 == 0x22FF1C
printf("p = 0x%X\n", (unsigned int)(p));
printf("p + 1 = 0x%X\n", (unsigned int)(p + 1));
return 0;
}
运行结果
a = 0x22FF18
a + 1 = 0x22FF1C
p = 0x0
p + 1 = 0x4
指针与指针之间的运算规则:
指针之间只支持减法运算
参与减法运算的指针类型必须相同
p1 - p2 <==> ((unsigned int)p1 - (unsigned int)p2) / sizeof(type)
注意:
只有当两个指针指向同一个数组中的元素时, 指针相减才有意义, 其意义为指针所指元素的下标差
当两个指针指向的元素不在同一个数组中时, 结果未定义
/* 测试代码 */
#include <stdio.h>
int main()
{
int i = 0;
char s1[] = {'H', 'e', 'l', 'l', 'o'};
char s2[] = {'W', 'o', 'r', 'l', 'd'};
char* p0 = s1;
char* p1 = &s1[3];
char* p2 = s2;
int* p = &i;
printf("%d\n", p0 - p1); // -3
printf("%d\n", p0 + p2); // error
printf("%d\n", p0 - p2); // (C语言未定义, 不同编译器不同实现)
printf("%d\n", p0 - p); // error
printf("%d\n", p0 * p2); // error
printf("%d\n", p0 / p2); // error
return 0;
}
指针的比较
指针可可以进行关系运算 ( <, <=, >, >= )
指针关系运算的前提是**同时指向同一个数组中的元素
任意两个指针之间的 比较运算(==, != )无限制
参与比较运算的指针类型必须相同
数组的访问方式
- 以下标的形式访问数组中的元素
int main()
{
int a[5] = {0};
a[1] = 3;
a[2] = 5;
return 0
}
- 以指针的形式访问数组中的元素
int main()
{
int a[5] = {0};
*(a + 1) = 3;
*(a + 2) = 5;
return 0;
}
下标形式 vs 指针形式
以固定增量在数组中移动时, 指针效率高于下标形式
下标形式与指针形式的转换
- a[n] <⇒ (a + n) <==> (n + a) <==> n[a]
注:现代编译器中, 在固定增量时, 下标形式的效率已经和指针形式相当。从可读性和代码维护的角度来看, 下标形式更优
a 和 &a 的区别
a 为数组首元素的地址
&a 为整个数组的地址
a 和 &a 的区别在于指针运算
a + 1 ===> (unsigned int) a + sizeof(*a)
&a + 1 ===> (unsigned int)(&a) + sizeof(*&a) ===> (unsigned int)(&a) + sizeof(a)