深入浅出指针(1)——初识指针

本文详细介绍了C语言中指针的作用,解释了为何使用指针来传递参数以修改函数内部的值,以及为什么避免使用全局变量。讨论了通过指针减少值传递的开销和提高效率,并通过示例展示了指针的定义、访问、算数运算以及指针常量和常量指针的区别。通过对指针深入理解,可以更好地掌握C语言的高级特性。
摘要由CSDN通过智能技术生成

为什么使用指针

函数的值传递,无法通过调用函数,来修改函数的实参

C语言中的一切函数调用中,值传递都是“按值传递”的。如果要在函数中修改被传递过来的对象,就必须通过这个对象的指针来完成。

#include<stdio.h>

void add_blood(int Blood){ 
	Blood +=1000; 
}

int main(void)
{
	int blood=1;
	add_blood(blood);
	printf("%d\n",blood);
	return 0;
}

运行上面的代码你会发现blood的值还是1,并没有加上1000。这是因为函数参数的传递都是值传递,main函数的blood存放在一个地址空间上,而函数中的Blood又是另外一个空间的,并不是main函数中的的地址。
只是把blood的值1赋值给Blood,相当于把函数中Blood的值初始化为1,然后函数在Blood等于1的基础上进行操作。并不会影响到主函数中的blood。

为什么不用全局变量,来避免这个问题

当然聪明的你可能会想到用全局定义某个变量来解决这个问题,能想到这里,说明你是一个善于思考的good boy。在这里插入图片描述

#include<stdio.h>

int blood = 1;

void add_blood() {
	blood += 1000;
	
}

int main(void)
{
	add_blood();
	printf("%d\n", blood);
	return 0;
}

,粗略看起来,上面代码貌似可以完美解决值传递问题,但是,我们都知道,函数的作用是可以提高代码重复利用率,如果需求不只是blood加1000,那么我们是不是要定义很多变量,并且还要将他们加1000.。这岂不是与函数的本意相冲突吗?而且还会造成资源浪费。

被调用函数需要提供更多的“返回值”给调用函数
//加血成功返回 ture ,否则返回 false ; 
bool add_blood2(int blood){ 
	if(blood >= 1000) {
		 return false; 
	}else { 
		blood +=1000; 
	}
	return true; 
	//另外还需要返回最新的血量,不能实现 
}
减少值传递时带来的额外开销,提高代码执行效率
#include<stdio.h>


struct Game {
	int level;//等级
	const char name[15] = "hello world" ;//游戏名
	char details[128];//状态描述

};


void text(struct Game game)
{
	//打印地址,比较text中game是不是和主函数game一样
	printf("text 中game的地址:0x%p\n", &game);

	printf("text 中struct game 的大小:%d\n", sizeof(game));
}

int main(void)
{

	Game game;
	printf("struct game 的大小:%d\n", sizeof(game));
	text(game);
	printf("main 中game的地址:0x%p\n", &game);

	return 0;
}

在这里插入图片描述
通过比较main中和text中的game的地址我们可以得到这样的结论,程序运行时有两个Game结构实体。那么有没有什么方法可以让我们的程序只有一个Game实体,从而减少开销。答案是肯定的,那就是指针。

如何使用指针

什么是指针

为了说清楚什么是指针,就必须搞清楚数据在内存中是如何存储的,又是如何读取的。如果在程序中定义了一个变量,在程序编译时,系统会根据程序中定义的变量类型给这个变量分配内存单元。指针就是存储这个内存单元地址的变量

指针的定义
    int room=10; 
//定义了一个指针 名称是 p1, 它是一个指针,可以指向一个整数
	int* p1;
	int* p2, p3;//注意这样定义只有p2是指针
	int* p4, * p5;// 应该这样定义

//指针 p1 指向了 room 也就是说: p1 的值就是一个变量room的地址!!!
	p 1= &room;

	printf("room的地址:0x%p\n", &room);
	printf("p存的值:0x%p\n", p1);
	

在这里插入图片描述

指针的访问
访问指针
#include <stdio.h> 

int main(void){ 
	int room = 2 ;
//1.访问(读、写)指针变量本身的值,
//和其它普通变量的访问方式相同
	int *p1 = &room;
//等价于int *p2 = &room; 
	int *p2 = p1;
	printf("room 的地址: %d\n", &room); 
	printf("p1 的值: 0x%p p2 的值: 0x%p\n", p1, p2);
	return 0;
}
访问指针所指向的内容
#include <stdio.h> 
#include <stdlib.h> 

int main(void){ 
	int room = 2 ;
 	int * girl = &room; 
 	int x = 0;
 	 
// *是一个特殊的运算符,*girl 表示读取指针 girl 所指向的 变量的值,
// *girl 相当于 room 
 	x = *girl;
 	printf("x: %d\n", x);
 	
//相当于 room = 4 
 	*girl = 4; 
 	printf("room: %d, *girl: %d\n", room, *girl); 
 	 
 	system("pause"); 
 	return 0; 
 }

指针的算数运算
指针的自增运算
#include <stdio.h> 
#include <stdlib.h> 

int main(void){ 
	int ages[]={21,15,18,14,23,28,10}; 
	int len = sizeof(ages)/sizeof(ages[0]);
	 
//使用数组的方式来访问数组 
	for( int i=0; i<len; i++){ 
		printf("第%d 个学员的年龄是:%d\n", i+1, ages[i]); 
	}
	
//打印数组的地址和第一个成员的地址 
	printf("ages 的地址: 0x%p , 第一个元素的地址: 0x%p\n", ages, &ages[0]);

//访问第一个元素 
 	int *p = ages; 
	printf("数组的第一个元素:%d\n", *p); 
	
	 for(int i=0; i<len; i++){ 
	 	printf("数组的第%d 个元素:%d 地址:0x%p\n", i+1, *p, p);
	 	 p++; //相当于 p = p+ 1*(sizeof(int)) 
	 }
	 
 	char ch[4]={'a','b','c','d'}; 
 	char * cp = ch; 
 	for(int i=0; i<4; i++){ 
 		printf("数组的第%d 个元素:%c 地址:0x%p\n", i+1, *cp, cp);
 		 cp++; }
    system("pause");
 	return 0; 
 }

总结: p++ 的概念是在 p 当前地址的基础上 ,自增 p 对应类型的大小 p = p+ 1*(sizeof(类型))
**注:**数组的地址是一段连续的地址。在这里插入图片描述

指针常量与常量指针

1.指针常量:在指针常量中,指针自身的值是一个常量,不能改变,在定义的时候必须初始化,且指向的地址不可改变。

#include<stdio.h>
int main(void)
{
	int age = 18;
	int height = 180;
	int* const p = &age;//指针常量必须初始化
	//p = height;//指针指向的地址是固定的,不能发生改变
	*p = 18;//但是可以改变指针p指向的地址内所存储的数据

	return 0;
}

2.常量指针
在常量指针中,指针所指向的地址中的数据不可发生改变,但是指针指向的地址可以发生改变。

#include<stdio.h>
int main(void)
{
	
	int age = 18;
	int height = 180;
	const int* p1 = &age;
	int const* p2 = &age;//俩种写法都可以表示常量指针
	p1 = &height;//指针指向的地址可以改变
	age = 20;
	//*p1 = 20;//不可以改变


	return 0;
}

总结: 看 const 离类型(int)近,还是离指针变量名近,离谁近,就修饰谁,谁就 不能变

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值