深入了解指针(二)
- 数组名理解
- 使用指针访问数组
- 一维数组的传参本质
- 冒泡排序
- 二级指针
- 指针数组
- 指针数组模拟二维数组
1.数组名理解
在上一个章节我们在使用指针访问数组的内容时,有这样的代码
int arr[10]={1,2,3,4,5,6,7,8,9,10};
int * p=&arr[0];
这里我们使用&arr[0]的方式拿到了数组的第一个元素的地址,但是数组名本来就是地址,而且是数组首元素的地址
我们发现数组名和数组首元素的地址打印出的结果一模一样,那么得出结论:数组名就是数组首元素(第一个元素)的地址。
既然说数组名就是首元素的地址但是有两个例外:
- sizeof(数组名)
- &数组名
sizeof(数组名),sizeof中单独放数组名,这里表示的是整个数组,计算的是整个数组的大小,单位是字节
&数组名,这里的数组名表示整个数组,取出的是整个数组的地址(整个数组的地址和首元素的地址是有区别的)
这个时候我们发现三分打印结果一模一样,那么arr和&arr又有什么区别呢??
我们发现arr和arr+1相差四个字节,其+1跳过的是数组的一个元素
&arr和&arr+1相差四十个字节,其+1跳过的是整个数组。
2.使用指针访问数组
#include<stdio.h>
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = arr;
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
}
printf("\n");
for (i = 0; i < sz; i++)
{
printf("%d ", *(arr + i));
}
printf("\n");
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
for (i = 0; i < sz; i++)
{
printf("%d ", p[i]);
}
printf("\n");
return 0;
}
这里我们发现其打印的结果一样,因为
p[i]的本质就是*(p+i)
arr[i]的本质就是*(arr+i)。
数组元素在访问编译器的处理的时候,也是转换成首元素的地址+偏移量求出元素的地址,然后解引用来访问的。
3.一维数组的传参本质
#include<stdio.h>
int test(int arr[])
{
sz1=sizeof(arr)/sizeof(arr[0]);
printf("sz1=%d \n",sz1);
}
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9,10};
sz=sizeof(arr)/sizeof(arr[0]);
printf("sz=%d \n",sz1);
test();
}
这里我们发现sz和sz1是两个截然不同的值,为什么呢??
因为我们前文说过数组名就是首元素地址,
那么可以知道形参int arr[]的本质就是指针int * arr 为四个字节使用计算sz1=1。
总结:一维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。
4.冒泡排序
在许多数据中,他的大小是乱序的,为了把他们排序为升序,我们可以利用冒泡排序来实现。
思想:就是两两进行交换,大的往后移动来实现。实现代码如下:
#include<stdio.h>
void Bubble_sort(int * arr,int sz)
{
int i=0;
for(i=0;i<sz-1;i++)//确定排序的趟数
{
int j=0;
int flag=1;//如果arr[j]<arr[j+1],就不用进入循环,加快效率
for(j=0;j<sz-1-i;j++)
{//两两比较,交换排序
if(arr[j]>arr[j+1])
{
flag=0;//发生交换就说明无序
int tmp=arr[j+1];
arr[j+1]=arr[j];
arr[j]=tmp;
}
if(flag==1)//没有进入循环
break;
}
}
}
int main()
{
int arr[]={9,8,7,6,5,4,3,2,1};
int sz=sizeof(arr)/sizeof(arr[0]);
Bubble_sort(arr,sz);
for(int i=0;i<=sz-1;++i)//打印出排序完的数据
{
printf("%d ",arr[i]);
}
return 0;
}
5.二级指针
指针变量也是变量,变量也有地址,那指针变量的地址存放在哪里呢??
这时候我们就需要利用二级指针来存放一级指针的地址了。
我们可以这样理解:
6.指针数组
很多小明看到指针数组,心里就想指针数组到底是数组还是指针???
我们来类比一下:
字符数组——就是存放字符的数组——还是数组
整形数组——就是存放整形的数组——还是数组
那么顾名思义指针数组就是存放指针的数组——就是数组
就是指针数组的每个元素用来存放地址(指针变量)的
例如:int *arr[7]={&a,&b,&c,&d,&e,&f,&g};
7.指针数组模拟二维数组
#include<stdio.h>
int main()
{
int arr1[]={1,2,3,4,5};
int arr2[]={2,3,4,5,6};
int arr3[]={3,4,5,6,7};
int *arr[]={arr1,arr2,arr3};//数组名是首元素的地址,可以存放在int *arr[]数组中
int i=0;
int j=0;
for(i=0;i<3;i++)
{
for(j=0;j<5;j++)
{
printf("%d ",arr[i][j]);//==*(*(arr+i)+j)
//1.(arr+i)找到地址
//2. *(arr+i)对找到的地址解引用
//3.找到一维数组中的首元素地址
//4. *(*(arr+i)+j)对找到的地址解引用取到数据
}
printf("\n");
}
return 0;
}