数组的本质
- 数组是一段连续的内存空间
- 数组的空间大小为 sizeof(array_type) * array_size【array_size:数组的元素个数】
- 数组名可看作指向数组第一个元素的常量指针
问题:
1. a + 1 的意义是什么?结果是什么
2. 指针运算的意义是什么?结果又是什么?
编程实验: a + 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));
printf("p = 0x%X\n", (unsigned int)(p));
printf("p + 1 = 0x%X\n", (unsigned int)(p + 1));
return 0;
}
输出:
a = 0xBFD627C8
a + 1 = 0xBFD627CC
p = 0x0
p + 1 = 0x4
分析:
p + 1 ==> 0 + 1 * sizeof(*p) ==> 0 + 1 * sizeof(int) ==> 0 + 4 ==> 4
a + 1 ==> 0xBFD627C8 + 1 * sizeof(*a) ==> 0xBFD627C8 + 1 * sizeof(a[0]) ==> 0xBFD627C8 + 1 * sizeof(int) ==> 0xBFD627C8 + 1 * 4 ==> 0xBFD627C8 + 4 ==> 0xBFD627CC
指针的运算
- 指针是一种特殊的变量,与整数的运算规则为
p+n; <--> (unsigned int)p + n * sizeof(*p)
结论:当指针指向一个同类型的数组的元素时, p+1 将指向当前元素的下一个元素; p-1 将指向当前元素的上一个元素。
- 指针之间只支持减法运算
- 参与减法运算的指针类型必须相同
p1 - p2; <--> ((unsigned int)p1 - (unsigned int)p2) / sizeof(type);
注意:
1. 只有当两个指针指向同一个数组中的元素时,指针相减才有意义,其意义为指针所指元素的**下标差**。
2. 当两个指针指向的元素不在同一个数组中时,结果未定义。
以上两条注意事项面对绝大部分的使用情况。
指针的运算是很灵活的,在特殊情况下,可以通过强制类型的转换,实现不同类型指针间的运算,而得到巧妙的结果。
已知一个结构体里面的成员地址,可以反推出该结构体的首地址 :
struct _tag
{
int aa;
int bb;
unsigned int* node;
};
指针的比较
- 指针也可以进行关系运算( <, <=, >, >= )
- 任意关系运算的前提是同时指向同一个数组中的元素
- 任意两个指针之间的比较运算( ==, != ) 无限制
- 参与比较运算的指针类型必须相同
实例分析: 指针运算初探
#include <stdio.h>
int main()
{
char s1[] = {'H', 'e', 'l', 'l', 'o'};
int i = 0;
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);
// printf("%d\n", p0 + p1);
// printf("%d\n", p0 - p2);
// printf("%d\n", p0 - p);
// printf("%d\n", p0 * p1);
// printf("%d\n", p0 / p1);
return 0;
}
输出:
-3
分析:
p0 - p2; 编译无警告,无错误,但大部分情况下,这样操作是没有实际意义的
p0 + p1; error: invalid operands to binary + (have ‘char *’ and ‘char *’) // 操作符不支持
p0 - p; error: invalid operands to binary - (have ‘char *’ and ‘int *’) // 指针类型不同
p0 * p1; error: invalid operands to binary * (have ‘char *’ and ‘char *’) // 操作符不支持
p0 / p1; error: invalid operands to binary / (have ‘char *’ and ‘char *’) // 操作符不支持
实例分析: 指针运算的应用
#include <stdio.h>
#define DIM(a) (sizeof(a) / sizeof(*a))
int main()
{
char s[] = {'H', 'e', 'l', 'l', 'o'};
char* pBegin = s;
char* pEnd = s + DIM(s); // key point
char* p = NULL;
printf("pBegin = %p\n", pBegin);
printf("pEnd = %p\n", pEnd);
printf("Size: %d\n", pEnd - pBegin);
for(p=pBegin; p<pEnd; p++)
{
printf("%c\n", *p);
}
printf("\n");
return 0;
}
输出:
pBegin = 0xbf9c17af
pEnd = 0xbf9c17b4
Size: 5
H
e
l
l
o
分析:
pEnd = s + DIM(s) ==>
s + 5 ==> 0xbf9c17af + 5 * sizeof(*s) ==> 0xbf9c17af + 5 * sizeof(char) ==> 0xbf9c17af + 5 * 1 ==> 0xbf9c17af + 5 ==> 0xbf9c17b4
小结
- 数组声明时编译器自动分配一片连续的内存空间,空间名为数组名
- 指针声明是只分配了用于容纳地址值的 4 字节空间
- 指针和整数可以进行运算,其结果为整数
- 指针之间只支持减法运算,其结果为数组元素下标差
- 指针之间支持比较运算,其类型必须相同
补充:以上实验在32位机器中运行。
当指针大小占用 8 字节时(64位机器), 使用 (unsigned int) 强制类型转换将发生数据截断,导致得到不正常的结果。
以上内容参考狄泰软件学院系列课程,请大家保护原创!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。