C语言——深入理解指针(二)
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)一趟内部,两两相邻的元素进行比较
代码实现:
#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;
}
运行:
以上这种代码,只有在非常完全混乱的时候才会非常有效,当一些数字在接近排好序,再用上述代码就会多余了,因此上面的代码还可以优化
优化:
#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.二级指针
- 这里,我们肯定会想到有二级指针那一级指针是什么,其实一级指针就是我们学过的:
int a=10;
int* pa=&a;//这里pa有了一个新的地址,pa是指针变量,pa也是一级指针
//其中,第二行的int是说明pa指向的对象是int类型,*说明pa是指针变量
那么,二级指针就是:
int** ppa=&pa;//这里ppa有了一个新的地址,ppa是二级指针变量
//int*说明ppa指向的对象是int*类型的
//第二个*说明ppa是指针变量
- 二级指针变量是用来存放一级指针变量的地址的
6.指针数组
类比于字符数组和整型数组:
char arr[5];//存放字符的数组
int arr[10];//存放整型的数组
指针数组就可以写为:
char* arr[5];//存放指针(地址)的数组
int*
float*
7.指针数组模拟二维数组
#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.字符指针变量
char arr[]="abcdef";
char* pc=arr;//我们都知道这是建立了一个数组,然后把首元素的地址存放到pc
字符指针变量就是省略数组那一步,既可以指向一个字符,也可指向一个字符串。而常量字符串不能被修改,所以前面需要加const修饰一下
const char* pc="abcdef";//这里的"abcdef"是常量字符串,不能被修改,所以常常需要用const修饰一下
//而pc中存放的是首字母a的地址
2.数组指针变量
1.首先,我们知道数组指针就是指向数组的指针且存放的是数组的地址。
&arr[0];//取出的是首元素的地址
&arr;//取出的是整个数组的地址
int arr[10]={0};
int* p=arr;
//p是整形指针变量
//存放的是首元素的地址
//p指向的是首元素
//这里p+1就是跳过4个字节
2.那么,数组指针变量指的是什么呢?
int (*p)[10]=&arr;//这就表示一个数组指针变量里面存放的是数组的地址,
//p是数组指针变量
//p指向的就是数组arr
//那么这里&arr+1就跳过40个字节
3.二维数组传参的本质
二维数组传参的本质上传递的是第一行这个一维数组的地址,则形参就可以写成指针形式也可以写成数组,如下:
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).函数指针变量的创建:
类比于上述,那么函数指针变量就是存放函数地址的。
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).函数指针变量的使用:
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关键字
作用是给类型进行重命名:
(一),普通类型重命名
typedef unsigned int unit;
int main()
{unsigned int num = 100;unit num2 = 100;
(二),整形指针类型重命名
typedef int* pint;
int main()
{int* p1,p2;pint p3,p4;
}
(三),数组指针类型重命名
typedef int (*parr_t)[5];
int main()
{int arr[5] = { 0 };int (*p)[5] = &arr;parr_t p2 = &arr;
}
(四),函数指针类型的重命名
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.函数指针数组
回顾一下指针数组:
char* arr[5];
int* arr[6];
而函数指针数组就是指针数组的一种,这种数组中存放的是函数指针
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 };
}