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)一趟内部,两两相邻的元素进行比较

代码实现:
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 };
}
相关推荐
智者知已应修善业4 小时前
【51单片机2个按键控制流水灯转向】2022-10-25
c语言·经验分享·笔记·嵌入式硬件·51单片机
阿巴~阿巴~5 小时前
字节:计算机存储单位
c语言·开发语言
用户6120414922137 小时前
C语言做的飞机大战游戏(控制台版)
c语言·后端·敏捷开发
yuezhilangniao15 小时前
关于开发语言的一些效率 从堆栈角度理解一部分c java go python
java·c语言·开发语言
-森屿安年-16 小时前
C语言学习笔记——文件
c语言·笔记·学习
小六学编程16 小时前
C语言库中的字符函数
c语言
Hello_Embed17 小时前
STM32HAL 快速入门(三):从 HAL 函数到寄存器操作 —— 理解 HAL 库的本质
c语言·stm32·单片机·嵌入式硬件·学习
学不动CV了18 小时前
FreeRTOS入门知识(初识RTOS任务调度)(三)
c语言·arm开发·stm32·单片机·物联网·算法·51单片机
_poplar_18 小时前
09 【C++ 初阶】C/C++内存管理
c语言·开发语言·数据结构·c++·git·算法·stl