1.一维数组与指针
一维数组数组名是一个地址),它代表了数组的首地址,数组在内存中连续存放
对于一个数组ar,ar的值与&ar[0]相等。
2.指针操作数组
1)把指针当作数组名来使用
格式:指针名[偏移位置]
例如:p[i]
2)指针偏移
格式:*(指针名+偏移位置)
指针+1或-1是向上或向下偏移sizeof(int)个字节。
例如:*(p+i)
3)指针自身++来获取每个元素的位置
格式:*(指针名++)
指针++或--是向上或向下移动sizeof(int)个字节。
例如:*(p2++)
从上面三种操作方式上来看,我们可以发现,在第一种和第二种中,指针本身的位置并没有改变,在循环完后,指针还是指在数组的首地址,但是在第三种方式中,指针的位置改变了,偏移量正好是20个字节,表示在方法三中,指针是通过自己的移动来读取元素的位置的。
3.数组自身的读取方式
1)数组名[偏移位置]
例如:ar[i]
注 i[ar],会被编译器转化为*(i+ar),一般不常用。
2)*(数组名+偏移位置)
例如:*(ar+i)
3)模仿指针变量的自身++,*(数组名++)
!!!错误!!!
“增量操作数需要左值”
数组名虽也是一个指针,指向数组元素的首地址,这与指针变量不同的是,数组名是一个常量,不能改变其值,也就自然不能用于++和--了,所以出现错误。
4.数组名与指针的区别
类型 | 是否可变 | 是否可运算 |
数组名 | 不可变,常量 | 无法+和- |
指针 | 可变,变量 | 可+和- |
代码:
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>
int main()
{
const int a=0x12345678;
int ar[5]={1,2,3,4,5};
int* p=ar;//一维数组名表示第一个元素的地址
int* p1=&ar[0];//也表示第一个元素的地址,ar[i]=*(ar+i)
for(int i=0;i<5;++i)
{
//p[i]=*(p+1)
printf("%d %d %d %d %d\n",p1[i],p[i],*(p+i),ar[i],*(ar+i));
}
return 0;
}
结果:
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
5 5 5 5 5
5.函数参数传递
代码:当把数组名作为函数的形参时,函数退化成指针
#include<stdio.h>
//参数也可以是:int br[],int n
void print_ar(int *br,int n)
{
sizeof(br);
printf("%d",sizeof(br));
}
int main()
{
int ar[4]={12,23,34,45};
int size=sizeof(ar);
int (*s)[4]=&ar;
int *ip;
print_ar(ar,4);
printf("\n");
printf("%d",sizeof(ar));
}
结果:
8
16
6.指针型数组
用于存放地址的指针数组,每个元素存放的都是地址。
格式:指针类型 数组名[N]
代码:
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>
int main()
{
int b[3] = { 1,2,3 };
int *p[3] = { b,&b[1],&b[2]};
for (int i = 0; i < 3; i++)
{
printf("%p\n", *(p+i));
}
printf("\n");
for (int i = 0; i < 3; i++)
{
printf("%d\n", *(*(p + i)));
}
printf("\n");
return 0;
}
结果:
0000004bed7ffccc
0000004bed7ffcd0
0000004bed7ffcd4
1
2
3
代码中,p是一个指针型数组,所以它也是一个数组名,满足数组名的特性。即它是一个常量,不可实现++和--运算,它里面存放的是地址,用*(p+i)是访问它的第i个元素,该元素是地址;用*(*(p+i))是访问它第i个元素地址中存放的值,也说明p是一个指针的指针。