C语言:四、指针

这篇博客详细介绍了C语言中的指针概念,从地址的引入到指针变量、指针与数组、函数指针的使用,再到内存管理和内存泄漏的防范,全面解析了指针在C语言中的重要作用和应用场景。

1.地址的概念引入

#include<stdio.h>

//一、访问的访问有两种方式
//1.通过变量名直接访问 2.通过地址间接访问

int main() 
{
	int home = 100;
	
	printf("home是:%d\n",home);//1.通过变量名访问

	printf("home的地址是:%p\n",&home);//二、&取地址,取变量名所代表的变量所在的内存地址

	printf("home是:%d",*(&home));//三、*  此时作为  取出内存地址中的数据的值  的运算符

	//四、指针=地址
}

2.指针变量的引入

#include<stdio.h>

int main()
{
	int a = 10;//整型变量—存放的是整数

	char c = 'c';//字符变量—存放的是字符

	int array[3] = {1,2,3};//数组—存放的是一组数据

	int* p;//指针变量—存放的是地址
	p = &a;//p中存放a的地址

	int* p2 = &a;//定义并初始化一个指针变量

	/*只有在定义一个指针变量时,*才是指针的标识符
	其他情况下*都是运算符*/
}
#include<stdio.h>

int main()
{
	int a = 10;
	int* pa = &a;
	printf("%d\n", pa);//以十进制输出pa中的内容(十进制形式输出a的地址)
	printf("%p\n", pa);//输出指针变量pa中的内容,与%d一样(十六进制)
	printf("%x\n", pa);//输出十六进制pa中存放的内容(还是a的地址)
	printf("%x\n", &pa);//以十六进制输出指针变量pa的地址
	printf("%d\n", *pa);//以十进制输出pa所指的地址内存放的内容(a里头的数)
	printf("%x\n", *(&pa));//以十六进制输出pa内的内容
}

在这里插入图片描述

3.指针的概念总结

4.通过指针来访问变量

5.指针分类型&指针与数组

#include<stdio.h>

int main()
{
	int a = 10;//整型变量—存放的是整数
	int* pa;
	pa = &a;
	printf("a的地址是:%p\n",pa);
	printf("a的地址++是:%p\n", ++pa);//地址++后移动一个整数类型的大小,即4个字节

	int array[3] = { 1,2,3 };//数组—存放的是一组数据
	int* parray;//指针变量—存放的是地址
	parray = &array;//由下面两行代码执行结果对比发现,将数组名赋值给指针变量等价于将数组的首地址赋值给指针变量
	printf("a0的地址是:%p\n", &array[0]);
	printf("array的地址是:%p\n", parray);
	printf("++array的地址是:%p\n", ++parray);

	printf("parray对应的值是:%d\n",* parray);//提取首地址对应的变量记得解引用
	printf("parray[0]对应的值是:%d\n", parray[0]);//或者用指针变量+下标的方式打印首个变量

}

在这里插入图片描述

6.指针数组函数的综合

#include<stdio.h>
//提示用户找到10个数,并找出其中的最大值、最小值,并计算它们的平均值

void inputing(int* datas,int size) 	//提示用户输入第几个数,获取用户的输入
										
{
	int i;
	for (i = 0;i < size;i++) {
		printf("请输入第%d个数:", i + 1);
		scanf_s("%d", datas);
		if (*datas > 100 || *datas < 0) {
			printf("超出范围,请重新进入程序\n");
			system("pause\n");
			exit(-1);
		}
		datas++;
	}
}

void printing(int* datas, int size)
{
	for (int i=0;i<size;i++) 
	{
		printf("第%d个学生的成绩是%d\n",i+1,datas[i]);
	}
}

int best(int* datas, int size)
{
	int max = datas[0];
	for (int i = 0;i < size;i++) {
		if (max < datas[i])
			max = datas[i];//不断将更大值赋给max
	}
	printf("最大值为:%d\n", max);
	return max;
}

int lowest(int* datas, int size)
{
	int min = datas[0];
	for (int i = 0;i <size;i++) {
		if (min > datas[i])
			min = datas[i];//不断将更小值赋给min
	}
	printf("最小值为:%d\n", min);
	return min;
}

float av(int datas[], int size)
{
	int sum = 0;
	float av = 0;
	for (int i = 0;i < size;i++) {
		sum += datas[i];
	}

	av = (float)sum / size;
	printf("平均值是:%d\n", av);
	return av;
}

int main() {
	//定义一个10个整数的整数型数组(初始化数组)
	int array[10];
	int* p;
	p = array;
	int len;
	len = sizeof(array) / sizeof(array[0]);
	//不可以写成sizeof(p)是因为p代表首地址即p[0],不代表一段长度

	//1.输入数据
	inputing(p,len);
	//2.打印数据
	printing(p, len);
	//3.找最高分
	best(p, len);
	//4.找最低分
	lowest(p, len);
	//5.算平均值
	av(p, len);
}

7.指针死怼这几件事就对了

8.为什么要用指针一

			把数据强制保存到我所希望保存到的地方(volatile)

9.为什么要用指针二

			通过地址间接访问变量,修改变量

10.为什么要用指针三

11.指针数组

	数组指针:数组内每个元素都是指针(好多指针的集合)
#include<stdio.h>

int main()
{
	//以整型指针为例
	int a = 1, b = 2, c = 3;
	int* parray[3];//多个指针叫指针数组

	parray[0] = &a;
	parray[1] = &b;
	parray[2] = &c;//三个毫不相关的整数地址

	for (int i = 0;i < 3;i++) 
	{
		printf("%d\n", * parray[i] );
	}
}

12.数组指针

指针数组:多个指针
数组指针:是一个指针变量,明确规定了要指向数组的类型及大小
#include<stdio.h>

int main()
{
	int a[3] = {1,2,3};
	int* p1 = a;//指针变量
	int(*p2)[3] = a;//数组的指针:明确规定了要指向数组的类型及大小

	printf("数组a的首地址是:%p\n",&a[0]);
	printf("===========p1和p2[3]的区别是=========\n");
	printf("++p1的结果是:%p\n",++p1);//偏移量为4
	printf("++p2的结果是:%p\n", ++p2);//偏移量为3*4
}

在这里插入图片描述

13.函数指针

该指针指向函数的地址,可以通过指针来调用函数
#include<stdio.h>

void printfhello()
{
	printf("hello world\n");
}

int add(int a, int b)
{
	return a + b;
}

int main()
{
	//如何定义函数指针
		void (*p1)();//1.声明时*表示指针
					//2.()表示函数
					//3.函数指针是专用的,格式要求很强(参数类型,个数,返回值),就像数组指针一样

		p1 = printfhello;//函数名就是地址

		//如何通过函数指针调用函数
		p1();//直接通过指针名
		(*p1)();//通过*解引用(取内容)

		int (*p2)(int a,int b);
		p2 = add;
		printf("%d",p2(1,2));//调用方法:指针名(参数1,参数2)
}

14.无类型&&malloc

#include<stdio.h>


int main()
{
//malloc函数的原型是void *malloc(size_t),是个指针函数
	//void代表返回值无类型(有返回值,但不知道类型是什么)
	//size_t代表申请空间大小(字节数大小)
	//malloc函数可以开辟一块空间

	int n;
	printf("请输入要存放的整数型元素个数总数:");
	scanf_s("%d", &n);
	//回忆之前的输入数组长度失败案例:int array[n]——只能通过写死(常数)来决定数组长度
	//malloc可以做到输入数组长度

	int* parray = (int*)malloc(n * sizeof(int));//开辟了n*4个字节的空间
	//(int*)将无类型的malloc转换为整数型的指针
	//一个整数4个字节,n个整数乘以n

	for (int i = 0;i < n;i++)
	{
		printf("请输入第%d个学生的成绩:", i + 1);
		scanf_s("%d", &parray[i]);//将成绩存进开辟的空间里
	}

	for (int i = 0;i < n;i++)
	{
		printf("第%d个学生的成绩是:%d\n", i + 1, parray[i]);
	}
}

15.什么是内存泄漏,如何避免

内存泄漏:malloc申请的空间不会主动释放,不断循环的malloc会造成内存空间超出预定空间,所以说泄漏。
解决方法:1.注意循环中有没有一直申请;2.及时释放空间free(p);p=NULL;//空指针

16.指针收官

#include<stdio.h>


int main()
{
//1.定义整型变量
	int a;

//2.定义p为指向整型数据的指针变量
	int* pa;

//3.定义整形数组a,它有5个元素
	int array[5];

//4.定义指针数组p,它由4个指向整型数据的指针元素组成
	int* p[4];//存放四个指针

//5.p为指向包含4个元素的一维数组的指针变量
	int(*p)[4];//一个指针“指几个元素”
				//和指向数组首地址的指针区别在于偏移量不一样,前者偏移量为4个字节,后者为4*4个字节

//6.f为返回整型函数值的函数
	int f();

//*7.p为返回一个指针的函数,该指针指向整型函数
	int* p();

//8.p为指向函数的指针,该函数返回一个整型值
	int (*p)();

//*9.//p是一个指针变量,它指向一个指向整型数据的指针变量
	int** p;

//10.p是一个指针变量,基本类型为void(空类型),不指向具体的对象
	void* p;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值