
🎉个人主页: 缘三水的博客
❄专栏传送门:C语言专栏(新手向)
🎀人生格言:行动是迷茫的最好解药
🚀个人介绍:

往篇回顾
文章目录
正文开始
(一)数组名的理解
数组名是首元素的地址
示例
c
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
printf("&arr[0] : %p\n", &arr[0]);
printf("arr : %p\n", arr);
return 0;
}
结果

拓展: %p 是专门用来打印地址的占位符,以16进制形式打印
但是有两个特殊情况
特殊情况1
sizeof(数组名)
这里的数组名表示整个数组
计算数组名的数据类型长度 时不是4或者8
而是 (元素个数 X 每一个元素的数据类型长度)
示例

特殊情况2
&数组名
&数组名,在值上与首元素的地址相同,但实际含义不同
&数组名,实际上是取出整个数组的地址
两者的指针类型是不同的
数组名(首元素地址)±整数,跨度是一个元素的大小
&数组名±整数,跨度是一个数组的大小
示例

&arr[0]和&arr[0]+1相差4个字节
arr和arr+1相差4个字节
+1就是跳过⼀个元素
然而&arr和&arr+1相差40个字节
+1操作是跳过整个数组
(二)指针访问数组
问题 向数组输入值,并打印
示例1
c
int main()
{
int arr[10] = { 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz; i++)//输入
{
scanf("%d",&arr[i]);
}
for (int i = 0; i < sz; i++)
{
printf("%d ",arr[i]);
}
return 0;
}
示例2 利用指针向数组里输入值,改变数组内容
c
int main()
{
int arr[10] = { 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = arr;
for (int i = 0; i < sz; i++)
{
scanf("%d", p + i);//p可以改为arr
}
for (int i = 0; i < sz; i++)
{
printf("%d ", *(p+i));//p可以改为arr
}
return 0;
}
也可以将输入和打印中的p改为arr
说明数组名就是首元素的地址,arr和p在这里是等价的
我们再看示例1和示例2中的printf函数,得出
c
arr[ i ] == * (arr + i)
数组元素的访问在编译器处理的时候,也是转换成首元素的地址+偏移
量求出元素的地址,然后解引用来访问的
又因为
c
*(arr + i) == *(i + arr)
而且
c
*(i+arr)== i[arr]//这种形式不常写,影响理解代码的效率
因此1,我们得出一种类似加法交换律的结论
arr[ i ] == * (arr + i) = = *(i +arr) == i[arr]
(三)一维数组传参本质

由结果看见
两个计算数组元素个数的结果不相同
实际上是因为一维数组传参,传的数组名是首元素的地址
只有在上面提到的两种特殊情况中,数组名才代表整个数组
这里函数的参数部分是本质是指针
因此,传一维数组应该用指针变量接收
而我们这里将首元素地址用int类型接收
指针变量计算大小则由环境决定
在x64环境下,指针变量大小是8,因此得出sz2 = 2
但是如果我们写int*arr接收的话,则程序会出现问题
总结:
一维数组传参本质上传的是首元素的地址
在函数内部求一维数组的元素个数是错误的
⼀维数组传参,形参的部分可以写成数组的形式 ,也可以写成指针的形式
示例
用int*接收,打印数组内容

(四)冒泡排序
冒泡排序 :两两相邻的元素进行比较
问题
一组数字,有n个元素,要排成升序形式
1.确定趟数
n个元素--进行n-1趟排序
2.一趟内部两两比较
一趟排序,数字内部两两相邻进行比较
前面数字大,就进行两个值的交换
直到成为正确的排序

根据上面两个步骤,写出代码
c
//冒泡排序
//排成升序形式,两两相邻元素进行比较
void bubble_sort(int arr[], int sz)
{
//1.确定趟数
int i = 0;
for (i = 0; i < sz - 1; i++)
{
//2.一趟内部排序
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;
}
}
}
}
void print_num(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[10] = { 10,9,8,7,6,5,4,3,2,1 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
print_num(arr, sz);
return 0;
}
但是如果碰见在n-1趟之内就已经排序好的,仍然需要进行比较,这就影响了效率
于是我们可以这样优化
在进行一次无需交换的趟数时,说明已经排序好了,就直接break 跳出循环,排序结束
而我们可以用一个状态量来判断是否进行了一次无需交换的趟
部分代码优化
c
//优化
void bubble_sort(int arr[], int sz)
{
//1.确定趟数
int i = 0;
for (i = 0; i < sz - 1; i++)
{
//2.一趟内部排序
int j = 0;
//假定排序好
int flag = 1;
for (j = 0; j < sz - 1 - i; j++)
{
if (arr[j] > arr[j + 1])//进行一次无需交换的趟,说明不进入if语句内部,flag值仍为1
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0;//说明是经过一趟排序,不是排序好的,flag赋为0
}
}
if (flag == 1)
break;//经过一次无需交换趟数,说明已经排序完,无需再判断,跳出循环
}
}
(五)二级指针
我们知道指针变量也是变量,那指针变量是不是也有自己对应的地址(指针)呢?
是的,一级指针变量对应的地址被称作二级指针
c
int a = 10;
int* pa = &a;//一级指针
int** ppa = &pa;//二级指针
我们来拆解这个二级指针
可以看到二级指针有两个*
后面的*说明这个ppa是指针变量
前面的 int *则说明这个指针指向的类型是 int *类型的
使用
c
**ppa 等价于 *pa 等价于 变量a
(六)指针数组
定义
指针数组是存放指针的数组
类型
因为数组的类型是由元素的类型 决定
所以,如果存放的是整型类型的元素的地址 ,那么数组类型就是int *
如果存放的是字符类型的元素的地址,那么数组类型就是 char *
示例
c
int main()
{
int a = 10;
int b = 20;
int c = 30;
int* arr[3] = { &a,&b,&c };
return 0;
}
使用示例
利用指针数组,模拟一个二维数组
c
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 i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", *(arr[i] + j));//*(arr[i] + j) == arr[i][j]
}
printf("\n");
}
return 0;
}
打印每一个元素时,也可以这样写
*(arr[ i ] + j) == arr[ i ][ j ]

总结
这篇文章我们详细介绍了指针部分内容,希望能对你有帮助
有错误的地方希望可以得到大佬的指正
最后不要吝啬你的点赞,收藏和评论!!!
感谢你的观看