我们继续开始指针的学习基于指针(1)对指针的了解我们继续开始指针的学习,这一节我们要正式的开始指针的学习之路了,我们会写一些函数指针这也是指针的魅力之处。
一,数组名的理解
我们先从我们熟悉的数组开始,说起数组名我们要先看一下数组传参的本质。
其实我们数组也是一种指针,如arr[1],也可以写成 *(arr+1) 。这既是指针的表示,那这里的数组名到第代表了什么呢?这里我们也可以看出arr这个数组名其实就是数组首元素的地址。
我们来用代码验证一下:
#include<stdio.h>
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
printf("%d\n", arr[1]);
printf("%d\n", *(arr + 1));
return 0;
}
运算结果:
从运算的结果看这验证了我们的理论,那再证明一下数组名是首元素的地址:
这也可以证明理论,数组名就是首元素的地址,这个时候可能就有人会有疑问如果数组名是首元素的地址,那下面的代码怎么理解呢?
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", sizeof(arr));
return 0;
}
运行一下就会发现这个sizoef(arr)得出的结果是40,如果数组名是首元素的地址那么它的大小会是4或8。那这是怎么回事呢?
其实数组名就是首元素的地址是对的,就是有两个例外:
1.sizeof(数组名),sizeof中单独放数组名,这里的数组名表示的是整个数组,计算的是整个数组的大小单位是字节。
2.&数组名,这里的数组名表示的是整个数组,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)。
除了这两个情况之外其它的情况数组名都是表示数组首元素的地址。
这时有好奇的同学可以试一下下面的代码:
我们发现这三个的地址一模一样那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和&arr的区别,arr+1会跳4个字节,而&arr+1会跳40个字节这就证明了&arr取出的是整个数组的地址,+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);
//scanf("%d",arr+i)也可以这样写
}
//输出
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
}
return 0;
}
这里我们分析一下因为arr是首元素的地址,arr赋值给p那么p这个指针和arr是等价的可以用arr[i]可以访问数组,那么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", p+i);
//scanf("%d",arr+i)也可以这样写
}
//输出
for (i = 0; i < sz; i++)
{
printf("%d ", p[i]);
}
return 0;
}
这里的*(p+i)换成p[i]也是可以的这就说明这两个是等价的,同理arr[i]也可以替换成 *(arr+i)。也是转换成首元素的地址+偏移量取出元素的地址,再进行解引用来访问。
三,一维数组传参的本质
在以上的种种运行结果可以显示,一维数组传参的本质其实是传的是数组首元素的地址,通过这个地址可以找到数组中的所有元素。
#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 };
test1(arr);
return 0;
}
总结:一维数组传参,形参可以写成数组方式也可以写成指针方式。
其中用sizeof(arr)计算的是一个地址的大小(单位字节)而不是数组大小(单位字节),正是因为函数的参数部分是本质是指针。
四,二级指针
指针变量也是变量,是变量就会有地址,那指针变量的地址存放在哪里?
答案是二级指针:
这里解释一下,图中的地址实际上可能并不是连续的地址,这里就是为了方便。
这就是二级指针,二级指针中存放的是一级指针的地址,可以同过二级指针修改一级指针的数据,进而控制a。
1.*ppa通过对ppa中的地址进行解引用,这样找到的是pa,*ppa其实访问的就是pa。
int b=20;
*ppa=&b;//等价于pa=&b
2.**ppa先通过*ppa找到pa,然后对pa进行解引用操作:*pa,那找到的是a。
**paa=30;
//等价于*pa=30
//等价于a=30
五,指针数组
指针数组是指针还是数组?
我们类比一下,整型数组,是存放整型的数组,字符数组是存放字符的数组。
指针数组就是存放指针的数组,所以指针数组其实是数组。
六,指针数组模拟二维数组
#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中
int* parr[] = { 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;
}
parr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型一维数组,parr[i][j]就是整型一维数组中的元素。
上述的代码模拟出的二维数组并非完美的二维数组,因为每一个并非是连续的。
六,冒泡排序
这里讲一下冒泡排序,这是一个经典的排序方法,它的核心是两两相邻进行比较。
这里讲的冒泡排序后期会用指针的方式进行实现,所以这里尽量理解要不然后面会很难理解,我也会讲的详细一点。
#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-i-1 ; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
int main()
{
int arr[] = { 3,1,4,2,6,5,8,9,7,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ",arr[i]);
}
return 0;
}
这里要排序10个数两两比较就需要进行就要进行9次(sz-1),每一趟比较都会把最大的数排到相应的位置,剩余的数就会减少比较次数(sz-1-i)。如果遇到前一位比后一位大就交换,依次类推就可以完成排序。
下面给大家来个测试看看你能不能理解下面的代码改进方法:
#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])
{
flag = 0;//发生交换,就证明无序
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j + 1] = tmp;
}
}
if (flag == 1)//这一趟没交换证明已有序不需要后续的排列了
break;
}
}
int main()
{
int arr[] = { 3,1,4,2,6,5,8,9,7,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
ok,今天的分享就到此结束了,感谢你的阅读,也祝你知识越来越巩固,为正在努力前行的我们,加油祝贺。