前言:对于指针我们已经有了初步的了解,并已能够简单使用。今天我们来深入理解指针。让我们的指针功力更上一层楼。
1 使用指针访问数组
有了指针的知识,再结合数组的特点,我们就可以使用指针来访问数组了。
#include<stdio.h>
int main()
{
int arr[10] = {
0 };
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = arr;
int i = 0;
for (i = 0; i < sz; i++)
{
//这几种方式都是可以的
//scanf("%d", &arr[i]);
//scanf("%d",(arr+i));
scanf("%d",(p+i));
}
for (i = 0; i < sz; i++)
{
//任选一种方式
//printf("%d ", arr[i]);
printf("%d ",p[i]);
//printf("%d ", *(arr + i));
//printf("%d ", *(p + i));
}
return 0;
}
数组名是数组首元素的地址
。将数组名arr赋值给指针变量p,那么数组名arr和p在这里是等价的。我们可以使用arr[i]来访问数组元素,那么也可以使用p[i]来访问数组元素。
数组元素的访问在编译器处理的时候,也是转换成数组首元素的地址+偏移量求出元素的地址,然后解引用访问的。
2 一维数组传参的本质
数组是可以传递给函数的,这一次我们来讨论一下数组传参的本质。之前我们都是在函数外部计算数组元素个数,那我们把数组传递给函数后,能否在函数内部求得数组元素的个数呢?
#include<stdio.h>
//参数部分写成数组形式,本质上还是指针。也可以写成指针形式
int test(int arr[])
{
int sz = sizeof(arr) / sizeof(arr[0]);
return sz;
}
int main()
{
int arr[10] = {
1,2,3,4,5,6,7,8,9,10 };
int sz1 = sizeof(arr) / sizeof(arr[0]);
int sz2 = test(arr);
printf("sz1=%d\n", sz1);
printf("sz2=%d\n",sz2);
return 0;
}
可以看到,在函数内部并没有求得正确的结果。这是为什么呢?这就不得不搞清楚一维数组传参的本质了。
前面我们提到过数组名代表的是数组首元素的地址
,那么在test函数里的形参理论上应该使用指针变量来接收地址。因此在函数内部里的sizeof(arr)求的是一个地址的大小(单位是字节),而不是数组的大小(单位是字节)。正是因为函数的形参部分本质上是指针,所以函数内部无法求出数组元素个数的。
3 冒泡排序
核心思想就是:两两相邻的元素进行比较
。
#include<stdio.h>
void bubble_sort(int arr[], int sz)
{
int i = 0;
// 趟数
for (i = 0; i < sz - 1; i++)
{
int flag = 1;//假设这一趟是有序的
int j = 0;
// 一趟需要比较的次数
for (j = 0; j < sz - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0;//发生交换,说明无序
}
}
//第一趟有序的话,后面就无需排序了
if (