🏔️山高万仞,只登一步!
文章目录
前面简单介绍指针访问数组,本节接介绍指针和数组的关系,如何用指针更高效,更快捷的访问数组!
一.数组名的理解
在前面我们在使用指针访问数组的时候通常用:
c
int arr[10] = { 1,2,3,4,5,6,7,8,10 };
int* p = &arr[0];
使用&arr[0]的方式拿到了数组的首元素地址,但是也可以用arr获取首元素地址
c
#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作为表达式时候计算的出来的是整个数组的大小
c
#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中单独
放数组名,表示为整个数组
计算的是整个数组的大小,单位是字节
&数组名,表示为整个数组
,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的 )
除此之外:数组名都表示数组首元素的地址
实例:
c
#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
c
#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跳过多少字节
二.使用指针访问数组
指针访问数组
c
#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]访问数组
c
#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;
}
结论 :
可以把下标引用操作符 [ ] 当作加号 +可以进行交换律
指针让我们对空间多了一种访问方式
三.一维数组传参的本质
数组是无法在函数内部计算数组元素的个数的
c
#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函数中没有正确得出元素个数
数组名是首元素地址,在作为参数传递的过程中传递的是数组名,实际上传递 的是数组首元素的地址 。因此函数内部计算的是地址的大小而不是数组的个数。函数参数部分是指针(地址),所以在函数内部是无法求数组元素个数的
因为传递的是指针,所以函数参数部分也可以写成指针的形式
c
#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;
}
如果想要在函数内打印数组可以写成:
c
#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;
}

总结:一维数组传参,形参部分可以写数组的形式,也可以写成指针的形式
四.冒泡排序
排序思想:
相邻两个元素进行比较
c
#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;
}
优化:
c
#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;
}
五.二级指针
指针变量也是变量,是变量就有地址,指针变量用二级指针
来存放
c
#include<stdio.h>
int main()
{
int a = 10;
int* pa = &a;
int** ppa =&pa;
printf("%d\n", **ppa);
return 0;
}

由图会发现ppa也有地址,也可以放在指针变量中,多级指针但是一般情况下不会超过二级指针
六.指针数组
指针数组还是数组 可以类比🚩:整型数组存放的是整数,字符型数组存放的是字符。
那么指针数组存放的是指针
数组类型 | 存放内容 |
---|---|
整型数组 | 整数 |
字符型数组 | 字符 |
指针数组 | 指针 |
实例
c
#include<stdio.h>
int main()
{
int a = 10;
int b = 20;
int c = 30;
int* arr[3] = { &a,&b,&c };
return 0;
}
一个个创建指针变量太麻烦,可以创建一个指针数组里面存放指针变量
七.指针数组模拟和实现
c
#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;
}
注:二维数组是是连续存放的
总结
