C语言------深入理解指针(二)
指针(三)
本小节结合指针和数组进行使用
1.数组名的理解
数组名一定是数组首元素的地址吗

从上面的运行中可看出,好像上面的说法是正确的,那么我们来看下面这个代码
从上面这个运行结果可看出,显然以上说法不够严谨,因此我们需要研究数组名到底是什么。那么请继续往下看:
数组名就是数组首元素的地址,但有两个例外:
(1)sizeof(数组名) :sizeof中单独放数组名时,这里的数组名表示整个数组,计算的是整个数组的大小单位是字节。
(2)&数组名 ,这里的数组名表示的是整个数组,取出的是整个数组的地址
**虽然,整个数组的地址和数组首元素地址的值虽然是一样的,但是它们是有差异的 **,请看下图:(指针类型决定了加减几个字节)
2.使用指针访问数组
使用指针向数组里存值并打印

还可以写成:
i[arr]只是为我们增加了一种角度理解指针和数组,是写代码尽量不要用,因为容易混淆。
3.一维数组传参的本质
一维数组的传参,形参的部分可以写成数组的形式,也可以写成指针的形式
4.冒泡排序
核心思想:
- 两两相连的元素进行比较
随机给一串数字,求它的升序排序
7 4 10 3 8 9 1 2 6 5,下面来进行排序

代码实现逻辑:
(1)确定趟数:n个元素-->n-1趟排序
(2)一趟内部,两两相邻的元素进行比较
代码实现:
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-i;j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
void print_arr(int arr[], int sz)
{
//打印
int i = 0;
for (i = 0;i < sz;i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[10] = { 9, 8,7,6,5,4,3,2,1,0 };
//将arr中的数字排成升序
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
print_arr(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 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 (flag == 1)
break;
}
}
void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0;i < sz;i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[10] = { 9, 8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
print_arr(arr, sz);
return 0;
}
5.二级指针
- 这里,我们肯定会想到有二级指针那一级指针是什么,其实一级指针就是我们学过的:
c
int a=10;
int* pa=&a;//这里pa有了一个新的地址,pa是指针变量,pa也是一级指针
//其中,第二行的int是说明pa指向的对象是int类型,*说明pa是指针变量
那么,二级指针就是:
c
int** ppa=&pa;//这里ppa有了一个新的地址,ppa是二级指针变量
//int*说明ppa指向的对象是int*类型的
//第二个*说明ppa是指针变量

- 二级指针变量是用来存放一级指针变量的地址的
6.指针数组
类比于字符数组和整型数组:
c
char arr[5];//存放字符的数组
int arr[10];//存放整型的数组
指针数组就可以写为:
c
char* arr[5];//存放指针(地址)的数组
int*
float*
7.指针数组模拟二维数组
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* arr[] = { arr1,arr2,arr3 };
//arr是指针数组
int i = 0;
for (i = 0;i < 3;i++)
{
int j = 0;
for (j = 0;j < 5;j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
图解:
指针(四)
1.字符指针变量
c
char arr[]="abcdef";
char* pc=arr;//我们都知道这是建立了一个数组,然后把首元素的地址存放到pc
字符指针变量就是省略数组那一步,既可以指向一个字符,也可指向一个字符串。而常量字符串不能被修改,所以前面需要加const修饰一下
c
const char* pc="abcdef";//这里的"abcdef"是常量字符串,不能被修改,所以常常需要用const修饰一下
//而pc中存放的是首字母a的地址

2.数组指针变量
1.首先,我们知道数组指针就是指向数组的指针且存放的是数组的地址。
c
&arr[0];//取出的是首元素的地址
&arr;//取出的是整个数组的地址
c
int arr[10]={0};
int* p=arr;
//p是整形指针变量
//存放的是首元素的地址
//p指向的是首元素
//这里p+1就是跳过4个字节
2.那么,数组指针变量指的是什么呢?
c
int (*p)[10]=&arr;//这就表示一个数组指针变量里面存放的是数组的地址,
//p是数组指针变量
//p指向的就是数组arr
//那么这里&arr+1就跳过40个字节
3.二维数组传参的本质
二维数组传参的本质上传递的是第一行这个一维数组的地址,则形参就可以写成指针形式也可以写成数组,如下:
c
void test(int(*arr)[5],int r,int c)
{
int i = 0;
for (i = 0;i < r;i++)
{
int j = 0;
for (j = 0;j < c;j++)
{
printf("%d ", *(*(arr + i)+j));
}
printf("\n");
}
}
int main(){
int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
test(arr, 3, 5);
return 0;
4.函数指针变量
(1).函数指针变量的创建:
类比于上述,那么函数指针变量就是存放函数地址的。
c
int Add(int x, int y)
{
return x + y;
}
int* test(int n, char* p)
{
}
int main() {
printf("%p\n", &Add);//打印函数的地址
printf("%p\n", Add);//也是打印函数的地址
int (*pf)(int, int) = &Add;//pf就是函数指针变量
int*((*pt)(int,char*)) = &test;//同理,要看清函数类型
return 0;
}
(2).函数指针变量的使用:
c
int Add(int x, int y)
{
return x + y;
}
int main() {
int (*pf)(int, int) = &Add;
int r=(*pf)(20, 50);
//上面也可以这样写:int r=pf(20, 50);
printf("%d\n", r);
return 0;
}
运行结果当然就是70
(3).typedef关键字
作用是给类型进行重命名:
(一),普通类型重命名
c
typedef unsigned int unit;
int main()
{
unsigned int num = 100;
unit num2 = 100;
(二),整形指针类型重命名
c
typedef int* pint;
int main()
{
int* p1,p2;
pint p3,p4;
}
(三),数组指针类型重命名
c
typedef int (*parr_t)[5];
int main()
{
int arr[5] = { 0 };
int (*p)[5] = &arr;
parr_t p2 = &arr;
}
(四),函数指针类型的重命名
c
typedef int(*pf_t)(int, int);
int Add(int x, int y)
{
return x + y;
}
int main()
{
int(*pf)(int, int) = &Add;
pf_t pf2 = &Add;
}
5.函数指针数组
回顾一下指针数组:
c
char* arr[5];
int* arr[6];
而函数指针数组就是指针数组的一种,这种数组中存放的是函数指针
c
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
int main()
{
int(*pArr[4])(int, int) = { Add,Sub,Mul,Div };
}