数组的本质:
(1)数组是一段连续的内存空间
(2)数组的大小为sizeof(array_type)*array_size
(3)数组名可看做指向数组第一个元素的常量指针
指针的运算
指针与整数的运算规则为:
p+n; (unsigned int)p+n*sizeof(*p);
指针之间的减法运算
(1)指针之间只支持减法运算
(2)参与减法运算的指针类型必须相同
p1-p2; ((unsigned int)p1 - (unsigned int)p2) / sizeof(type)
注意:
1.只有当两个指针指向同一个数组中的元素时,指针相减才有意义,其意义为指针所指元素的下表差
2.当两个指针指向的元素不在同一个数组中时,结构未定义
3.指针也可以进行关系运算(<,<=<.,>=)
4.指针关系运算的前提是同时指向同一个数组中的元素
5.任意两个指针之间的比较运算(==,!=) 无限制
6.参与比较运算的指针类型必须相同
指针运算的应用:
数组的边界位置,数组元素最后一个元素的后一个元素位置,这个语法合法
#include <stdio.h>
#define DIM(a) (sizeof(a) / sizeof(*a))
int main()
{
char s[] = {'H','e','l','l','o','w'};
char* pBegin = s;
char* pEnd = pBegin + DIM(s);
char* p = NULL;
printf("pBegin = %p\n", pBegin);
printf("pBegin = %p\n", pEnd);
printf("size = %d\n", pEnd - pBegin);
for(p = pBegin; p < pEnd; p++)
printf("%c", *p);
return 0;
}
下标形式vs指针形式
(1)指针以固定增量在数组中移动时,效率高于下标形式
(2)指针增量为1且硬件具有硬件增量模型时,效率更高
(3)下标形式与指针形式的转换
a[n] == *(a+n)
*(n+a) == n[a];
数组可以当做常量指针使用,指针也可以当做数组名使用
int a[] = {1,2,3,4,5}; //a的地址0x601040
extern int a[]; //正确
extern int* a; //段错误
#include <stdio.h>
int main()
{
extern int* a; //仅仅声明
printf("&a = %p\n", &a); //a的地址,去a这个标识符的地址值
printf("a = %p\n", a); //a是指针变量,保存地址值,然后到0x601040地址中取四个字节,也就是0001,打印出0x1(a指针,所以到指针所对应的地址中取4个字节)
printf("*a = %d\n", *a); //0x1地址是预留给操作系统使用,用户访问这个地址的值就会产生段错误
return 0;
}
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)
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int* p1 = (int*)(&a + 1);
int* p2 = (int*)((int)a + 1);
int* p3 = (int*)(a + 1);
printf("%d, %d, %d\n", p1[-1], p2[0], p3[1]);
return 0;
}
0x0200000000十进制 = 33554432
linux操作系统是小端模式
数组参数
数组作为函数参数时,编译器将其编译成对应的指针
void f(int a[]); == void f(int* a)
void f(int a[5]); == void f(int* a)
#include <stdio.h>
void func1(char a[5])
{
printf("In func1: sizeof(a) = %d\n", sizeof(a));
*a = 'a';
a = NULL;
}
void func2(char b[])
{
printf("In func2: sizeof(b) = %d\n", sizeof(b));
*b = 'b';
b = NULL;
}
int main()
{
char array[10] = {0};
func1(array);
printf("array[0] = %c\n", array[0]);
func2(array);
printf("array[0] = %c\n", array[0]);
return 0;
}
结论:
一般情况下,当定义的函数中有数组参数时,需要定义另一个参数来表示数组的大小
(1)数组名和指针仅使用方式相同
数组名的本质不是指针,指针的本质不是数组
(2)数组名并不是数组的地址,而是数组首元素的地址
(3)函数的数组参数退化为指针