C语言——深入解析C语言指针:从基础到实践从入门到精通(三)
文章目录
- 一.数组名的理解
- 二.使用指针访问数组
- 三.一维数组传参的本质
- 四.冒泡排序
- 五.二级指针
- 六.指针数组
- 七.指针数组模拟和实现
- 总结
前面简单介绍指针访问数组,本节接介绍指针和数组的关系,如何用指针更高效,更快捷的访问数组!
一.数组名的理解
在前面我们在使用指针访问数组的时候通常用:
int arr[10] = { 1,2,3,4,5,6,7,8,10 };
int* p = &arr[0];
使用&arr[0]的方式拿到了数组的首元素地址,但是也可以用arr获取首元素地址
#include<stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("&arr[0]=%p\n", &arr[0]);printf("arr =%p\n", arr);return 0;
}
发现数组名
就是数组首元素(第一个元素)地址
如果数组名是首元素地址的话,用sizeof计算出来的地址大小应该是4/8
但是之前在用sizeof计算数组大小的时候,arr作为表达式时候计算的出来的是整个数组的大小
#include<stdio.h>
int main()
{int arr[5] = { 1,2,3,4,5 };printf("%d\n", sizeof(arr));return 0;
}
输出的结果是20,如果是数组地址输出的应为4/8;
其实:数组名是首元素地址是正确的,但是有两个例外
sizeof(数组名),sizeof中单独
放数组名,表示为整个数组
计算的是整个数组的大小,单位是字节
&数组名,表示为整个数组
,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)
除此之外:数组名都表示数组首元素的地址
实例:
#include<stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("&arr[0] =%p\n", &arr[0]);//首元素地址printf("arr =%p\n", arr);//首元素地址printf("&arr =%p\n", &arr);//数组的地址return 0;
}
但是发现输出的结果都一样,那么数组的地址和数组首元素的地址到底有什么区别呢?
arr与&arr
#include<stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("&arr[0] =%p\n", &arr[0]);printf("&arr[0]+1 =%p\n", &arr[0]+1);printf("arr =%p\n", arr);printf("arr +1 =%p\n", arr+1);printf("&arr =%p\n", &arr);printf("&arr +1 =%p\n", &arr+1);return 0;
}
&arr[0]+1相差4个字节,arr和arr+1相差4个字节,他们都是首元素的地址,+1跳过一个元素
&arr和&arr+1相差40个字节,因为&arr是数组的地址,+1跳过整个数组
指针类型决定±1跳过多少字节
二.使用指针访问数组
指针访问数组
#include<stdio.h>
int main()
{int arr[10] = { 0 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);int* p = arr;for ( i = 0; i <sz; i++){scanf("%d", p + i);}for ( i = 0; i <sz; i++){printf("%d ", *(p + i));}return 0;
}
由前面介绍知道,数组名arr是首元素的地址,用arr赋值给p,arr等价于p,那么我们可以用arr访问数组,是否也可以用p[i]访问数组
#include<stdio.h>
int main()
{int arr[10] = { 0 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);int* p = arr;for (i = 0; i < sz; i++){scanf("%d", arr+ i);}for (i = 0; i < sz; i++){printf("%d ", *(arr + i));}return 0;
}
结论:
可以把下标引用操作符 [ ] 当作加号 +可以进行交换律
指针让我们对空间多了一种访问方式
三.一维数组传参的本质
数组是无法在函数内部计算数组元素的个数的
#include<stdio.h>
void test(int arr[])
{int sz2 = sizeof(arr) / sizeof(arr[0]);printf("sz2 =%d\n", sz2);
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);printf("sz1 =%d\n", sz);test(arr);return 0;
}
在test函数中没有正确得出元素个数
数组名是首元素地址,在作为参数传递的过程中传递的是数组名,实际上传递的是数组首元素的地址。因此函数内部计算的是地址的大小而不是数组的个数。函数参数部分是指针(地址),所以在函数内部是无法求数组元素个数的
因为传递的是指针,所以函数参数部分也可以写成指针的形式
#include<stdio.h>
void test1(int arr[])
{printf("%d\n", sizeof(arr));
}
void test2(int *arr)
{printf("%d\n", sizeof(arr));
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);printf("sz1 =%d\n", sz);test1(arr);test2(arr);return 0;
}
如果想要在函数内打印数组可以写成:
#include<stdio.h>
void test(int* arr, int sz)
{int i = 0;for ( i = 0; i < sz; i++){printf("%d ", arr[i]);}
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);printf("sz1 =%d\n", sz);test(arr,sz);return 0;
}
总结:一维数组传参,形参部分可以写数组的形式,也可以写成指针的形式
四.冒泡排序
排序思想:
相邻两个元素进行比较
#include<stdio.h>
void Bubble_sort(int* arr, int sz)
{int i = 0;for ( i = 0; i < sz-1; i++){int j = 0;for ( j= 0; j< sz-1-j; j++){if (arr[j] > arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}
int main()
{int arr[10] = { 0 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);for ( i = 0; i < sz; i++){scanf("%d", &arr[i]);}Bubble_sort(arr, sz);for ( i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}
优化:
#include<stdio.h>
void Bubble_sort(int* arr, int sz)
{int flag = 1;int i = 0;for (i = 0; i < sz - 1; i++){int j = 0;for (j = 0; j < sz - 1 - j; j++){if (arr[j] > arr[j + 1]){flag = 0;//说明是无序的int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}if (flag==1)//如果flag==1说明没有进行交换,是有序{break;}}
}
int main()
{int arr[10] = { 0 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);for (i = 0; i < sz; i++){scanf("%d", &arr[i]);}Bubble_sort(arr, sz);for (i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}
五.二级指针
指针变量也是变量,是变量就有地址,指针变量用二级指针
来存放
#include<stdio.h>
int main()
{int a = 10;int* pa = &a;int** ppa =&pa;printf("%d\n", **ppa);return 0;
}
由图会发现ppa也有地址,也可以放在指针变量中,多级指针但是一般情况下不会超过二级指针
六.指针数组
指针数组还是数组可以类比🚩:整型数组存放的是整数,字符型数组存放的是字符。
那么指针数组存放的是指针
数组类型 | 存放内容 |
---|---|
整型数组 | 整数 |
字符型数组 | 字符 |
指针数组 | 指针 |
实例
#include<stdio.h>
int main()
{int a = 10;int b = 20;int c = 30;int* arr[3] = { &a,&b,&c };return 0;
}
一个个创建指针变量太麻烦,可以创建一个指针数组里面存放指针变量
七.指针数组模拟和实现
#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* parr[3] = { arr1,arr2,arr3 };int i = 0;int j = 0;for ( i = 0; i < 3; i++){for (j = 0;j < 5;j++){printf("%d ", parr[i][j]);}printf("\n");}return 0;
}
注:二维数组是是连续存放的