指针(1)

1.内存和地址

1.1   内存

生活中我们有了房间号才能够快速找到房间,同样,在计算机中CPU(中央处理器)在处理数据时,需要的数据是在内存中进行读取的,处理完之后又会放回内存中。

在内存空间中,也是将内存划分为一个个的内存单元,每个内存单元的大小为1个字节,1个字节相当于8个比特位,一个比特位可以存储一个二进制的0或1

补充

1byte=8bit

1KB=1024byte

1MB=1024KB

1GB=1024MB

1TB=1024GB

1PB=1024TB

生活中我们将门牌号叫做地址,在计算机中,我们把内存单元的编号叫做地址,c语言中我们把它叫作指针

2.指针变量和地址

2.1

c语言中创建变量其实就是向内存中申请空间

我们使用一个获取地址的操作符(&)得到一个变量的地址

 通过观察内存,&a取出的是a所占4个字节中较小的地址

2.2

2.2.1 指针变量

我们将取到的地址存放在指针变量

int main()
{
	int a=10;
	int*p=&a;//取出a的地址存放在指针变量p中
	return 0;
}

 指针变量也是一种变量,这个变量就是用来存放地址的,存放在其中的值都可以理解为地址

2.2.2 拆解指针类型

pa左面写的是int*,*说明pa是指针变量,int说明pa指向的是整型类型的对象

2.2.3 解引用操作符(*)

int main()
{
	int a=10;
	int*pa=&a;//取出a的地址存放在指针变量p中
	*pa= 0;
	return 0;
}

通过解引用,*pa就把a由10 改为0

2.4 指针变量的大小

32位机器就有32根地址总线,把这32根地址总线产生的二进制序列当作一个地址,一个地址就是32byte,就是4个字节

在64位的机器中,就变成了8个字节

所以以后一提到地址的大小就是4个字节(32位)或者8个字节(64位)

x86环境就是32位环境,根据运行结果来看,指针变量的大小是与类型无关的,只要指针类型的变量在相同的平台下,大小就都是相同的

3.指针变量类型的意义

3.1  指针的解引用

指针类型决定了对指针解引用的时候有多大的权限(一次可以操作几个字节)

例如:char*的指针解引用只能访问一个字节,而int*的指针解引用就可以访问4个字节

3.2   指针+-整数

可以看出,char*类型的指针变量+1跳过一个字节,int*类型的指针跳过4个字节

指针的类型决定了指针向前走或向后走一步有多大

3.3  void*指针

void*是一种无类型的指针,可以用来接受任意类型的指针。局限性是,不能进行+-和解引用的运算

int main()
{
	int a = 10;
	int* p = &a;
	char* pa = &a;
	return 0;
}

运行后编译器给出警告

但是当我们用void*类型就不会出现这种问题

从这里看出,void*可以接收不同类型的指针,但是无法直接进行指针的运算

4.const修饰指针 

4.1 const修饰变量

变量是可以被修改的,把变量的地址交给一个指针变量,通过这个指针变量也是可以修改变量的

我们希望加上一些限制,使其不能被修改,这就是const的作用

int main()
{
	int m = 0;
	m = 20;//m可以被修改
	const int n = 0;
	n = 20;
	return 0;//n不能被修改
}

 但是如果我们绕过你n,使用n的地址去修改n,就可以了,这样就是在打破语法规则

4.2 const修饰指针变量

#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

void test1()
{
	int n = 10;
	int m = 20;
	int* p = &n;
	*p = 20;//Ok n=20,m=20
	p = &m;//N0,n=10,m=20
}

void test2()
{
	int n = 10;
	int m = 20;
	int*const p = &n;//const修饰的是指针变量本身,指针变量本身不可以修改,但是指针变量所指向的内容可以改变
	*p = 20;//OK
	//p = &m;//这里编译器会报错
}

void test3()
{

	int n = 10;
	int m = 20;
	int const*  p = &n;//const修饰的是指针指向的内容,保证指针指向的内容不被改变,但是指针本身可以被改变
	//*p = 20;//报错
	p = &m;//OK
}

void test4()
{
	int n = 10;
	int m = 20;
	int const* const p = &n;//const既修饰了指针变量本身,又修饰了指针所指向的内容,二者都不可以被改变
	//*p = 20;//报错
	//p=&m;//报错
}
int main()
{
	test1();
	test2();
	test3();
	test4();
	return 0;
}

 得出结论

1.const放在*的左边(int const *p):修饰的是指针所指向的内容,保证指针指向的内容不能通过指针来改变,但是指针变量本身可以改变

2.const放在*的右边(int *const p):修饰的是指针变量本身,保证了指针变量的内容不能改变,但是指针所指向的内容,可以通过指针改变

5.指针运算

指针的运算一般有三种..
1.指针+-整数

2.指针-指针

3.指针的关系运算

5.1指针+-整数=指针

数组在内存中是连续存放的,只要知道了第一个元素的地址,就可以找到后面所以的元素

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", *(p+i));
	}
	return 0;
}

 这里的p+i就是指针+-整数

5.2 指针-指针=整数(两个指针之间的元素个数)

int my_strlen(char* s)
{
	char* p = s;
	while (*p != '\0')
	p++;
	return p - s;
}

int main()
{
	printf("%d\n", my_strlen("abc"));
	return 0;
}

//运行结果为3

指针-指针的运算的前提条件是:两个指针必须指向同一块空间

注意!!!指针+指针是无意义的

5.3 指针的关系运算

指针的大小比较

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	while (p < arr + sz)
	{
		printf("%d ", *p);
		p++;
	}
	return 0;
}

6.野指针 

6.1 野指针的成因

1,指针未初始化

int main()
{
	int* p;//局部变量未初始化,默认为随机值
	*p = 20;
	return 0;
}

2,指针越界访问

int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	for (int i = 0; i < 11; i++)
	{
		*(p++) = i;//指针指向的范围超出数组arr的范围,p就是野指针
	}
	return 0;
}

 3,指针指向的空间释放

int* test()
{
	int n = 100;
	return &n;
}
int main()
{
	int* p = test();
	printf("%d\n", *p);
	return 0;
}

在test()中,我们想让它返回一个指向局部变量n的指针。但是,存在一个问题,当test函数执行完毕是,n这个局部变量所占用的空间就会被释放,指向它的指针就会变为悬空指针。

在main()函数中,当我们想要打印*p是,实际上访问的是一个已经被释放的内存地址

6.2 如何避免野指针

6.2.1    如果明确知道指针指向哪里就直接赋地址,如果不知道,就给指针赋值NULL。

NULL是c语言中定义的一个标识符常量,值为0,0也是地址,但这个地址无法使用

初始化如下

int main()
{
	int num = 10;
	int* p1 = &num;
	int* p2 = NULL;
	return 0;
}

6.2.2   小心指针越界

一个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围,超出了就是越界访问

6.2.3   指针变量不再使用时,即使设置为NULL,使用之前检查有效性

当指针变量指向一块区域时,我们可以通过指针访问该区域,后期不使用就即使设置为NULL,,只要是NULL指针就不去访问,在使用之前我们就要判断是不是NULL,如果是就不去访问

6.2.4   避免返回局部变量的地址

7.assert断言

assert.h头文件定义了assert(),用于在运行时确保程序符合指定的条件,如果不符合,就报错终止运行

assert(p!=NULL);

assert()接受一个表达式作为参数,如果表达式为真,程序继续运行,否则就会报错,并会在标准错误流stderr中写入一条错误信息,显示没有通过的表达式,以及这个表达式的文件名和行号

如果确认程序没有任何问题的话,无需更改代码,在头文件前定义一个宏NDEBUG,编译器就会禁用所以assert()

它的缺点就是引入额外的检查,增加了程序的运行时间

我们可以在debug中使用,在release直接禁用就可

8.指针的使用和传址调用

 8.1  strlen的模拟实现

strlen()的功能时求字符串的长度,统计“\0”之前的字符个数

函数原型为

size_t strlen(const char *P);

 参考代码

int my_strlen(const char* str)
{
	int count = 0;
	assert(str);
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	int len = my_strlen("abcdef");
	printf("%d", len);
	return 0;
}

8.2  传值调用和传址调用 

 写一个函数,交换两个整型变量的值,我们可能会写出以下代码

运行结果为

void Swap(int x, int y)
{
	int temp = x;
	x= y;
	y= temp;
}
int main()
{
	int a = 10, b = 20;
	Swap(a, b);
	printf("%d %d", a, b);
	return 0;
}

我们发现a和b并没有交换 

我们在main函数内部,创建了a和b,在调用Swap函数时,将a和b传给了Swap函数,x和y接受了a和b的值,但是x和a的地址不同,是两块独立的空间,只在Swap函数内部交换x和y的值,自然不会影响a和b的值,所以a和b没有交换,这就是传值调用 

结论:实参传递给形参时,形参会单独开辟一块空间接收,对形参的修改不会影响实参

 我们要达到的目的时在Swap函数中操作的就是main函数中的a和b,所以我们把a和b的地址传给Swap函数就好了

void Swap(int *px, int*py)
{
	int temp = *px;
	*px= *py;
	*py= temp;
}
int main()
{
	int a = 10, b = 20;
	Swap(&a, &b);
	printf("%d %d", a, b);
	return 0;
}

 

这种方式叫做传址调用 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/459822.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OJ_最长公共子序列

题干 C实现 #include <iostream> #include <stdio.h> #include <algorithm> using namespace std;int dp[1002][1002];int main() {int n,m;char s1[1001];char s2[1001];scanf("%d%d",&n,&m);scanf("%s%s",s1,s2);//dp[i][j]是…

拼多多、淘宝、抖音、小红书商家,如何轻松在1688找到靠谱货源?

无论你是做拼多多、淘宝、抖音小店、小红书或者1688运营及采购商们&#xff0c;只要想在1688上寻找靠谱货源时&#xff0c;可以按照以下几个步骤进行筛选&#xff1a; 一、明确需求 首先&#xff0c;你需要清晰地了解自己的经营方向、目标消费群体以及所需产品的具体规格、材…

可变形卷积v4 |更快更强,效果远超DCNv3

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;助力高效涨点&#xff01;&#xff01;&#xff01; 一、论文摘要 我们介绍了可变形卷积v4 (DCNv4)&#xff0c;这是一种高效的算子&#xff0c;专为广泛的视觉应用而设计。DCNv4通过两个关键增强解决了…

26.网络游戏逆向分析与漏洞攻防-网络通信数据包分析工具-实现生成日志文件的功能

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;25.利用全新的通…

PTA- - -个位数统计(C语言)

Hello,好久没更新啦&#xff0c;今天给大家讲解一下PTA平台上面的“个位数统计”这道题吧~ 题目是要统计一个数字每个位上数字出现的次数。下面是一个解决方案的思路和相应的 C 语言代码&#xff1a; 思路&#xff1a; 初始化一个大小为10的数组&#xff0c;用于计数每个数字…

【LeetCode】升级打怪之路 Day 24:回溯算法的解题框架

今日题目&#xff1a; 46. 全排列51. N 皇后78. 子集 目录 LC 46. 全排列LC 51. N 皇后LC 78. 子集 【classic】1&#xff09;思路一2&#xff09;思路二 今天学习了回溯算法的解题框架&#xff1a;回溯算法解题套路框架 | labuladong 回溯算法的整体框架都是&#xff1a; re…

提高工作效率,选择SmartEDA优质电子电路设计软件

在当今快节奏的工程环境中&#xff0c;电子电路设计软件的选择至关重要。随着技术的不断发展&#xff0c;工程师们需要能够快速、精确地设计和验证各种电子电路。而SmartEDA作为一款领先的电子电路设计软件&#xff0c;为工程师们提供了提高工作效率的强大工具。 1. 提供全面的…

pandas 数据透视和逆透视

本篇介绍 pandas 数据重塑的几个有用变换。假设我们有学生语数外考试的成绩数据&#xff0c;大家常见的是这种格式&#xff1a; 如果数据放在数据库中&#xff0c;下面的格式比较符合数据库范式&#xff1a; 现在&#xff0c;任务来了。要实现由图一向图二的变换&#xff0c;传…

centos破解root密码以及如何防止他人破解root密码

目录 破解root密码 服务器重启 1.再重启页面上下选择第一个按e进入内核编辑模式 2.找到linux16开头的一行&#xff0c;光标移动到最后添加 init/bin/sh Ctrlx 保存 3.进入单用户模式 4.重新挂在根分区 5.关闭selinux 6.更新密码 passwd 7.在根分区下面创建一个隐藏文件…

移动端使用 echarts中 滚动条 dataZoom 改造为内容区域可以左右滚动

移动端使用 echarts中 滚动条 dataZoom 改造为内容区域可以左右滚动 直接上图 &#xff1a; 主要是下面这段代码&#xff1a; "dataZoom": [{"type": "inside","show": false,"xAxisIndex": [0],"zoomOnMouseWheel&…

Frostmourne - Elasticsearch源日志告警配置

简介 配置Frostmourne 接入Elasticsearch源进行日志匹配告警&#xff0c;并静默规则&#xff0c;告警消息发送到企业微信&#xff0c;告警信息使用Markdown。 部署安装教程查看&#xff1a; https://songxwn.com/frostmourne_install ELK 安装教程&#xff1a;https://songx…

Spring Boot整合canal实现数据一致性解决方案解析-部署+实战

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 1.前言 2.canal部署安装 3.Spring Boot整合canal 3.1数据库与缓存一致性问题…

golang中new和make的区别

1. 先看一个例子 package mainimport "fmt"func main() {var a *int*a 10fmt.Println(*a) }运行结果是啥呢&#xff1f; 问&#xff1a;为什么会报这个panic呢&#xff1f; 答&#xff1a;因为如果是一个引用类型&#xff0c;我们不仅要声明它&#xff0c;还要为…

若依(ruoyi-vue)后端部署windows系统 (一文搞通,从idea安装到打包部署)

一、下载idea并破解&#xff0c;防止时间久了没法打开 访问 IDEA 官网&#xff0c;下载 IDEA 2023.2.3 版本的安装包&#xff0c;下载链接如下 : https://www.jetbrains.com/idea/download/ 卸载旧版本&#xff0c;安装新版本 弹框会提示选择安装路径&#xff0c;我这里直接选择…

蜡烛图K线图采用PictureBox控件绘制是实现量化交易的第一步非python量化

用vb6.0开发的量化交易软件 VB6量化交易软件的演示视频演示如上 股票软件中的蜡烛图是非常重要的一个东西&#xff0c;这里用VB6.0自带的Picture1控件的Line方法就可以实现绘制。 关于PictureBox 中的line 用法 msdn 上的说明为如下所示 object.Line [Step] …

大模型语言系列-Agent

文章目录 前言一、Agent是什么&#xff1f;二、LLM Agent1.西部世界小镇Agent2.BabyAGI3.AutoGPT4.Voyager Agent 总结 前言 自2022年ChatGPT诞生以来&#xff0c;LLM获得了收获了大量关注和研究&#xff0c;但究其根本&#xff0c;技术还是要为应用服务&#xff0c;如何将LLM…

数据结构与算法----复习Part 15 ()

本系列是算法通关手册LeeCode的学习笔记 算法通关手册&#xff08;LeetCode&#xff09; | 算法通关手册&#xff08;LeetCode&#xff09; (itcharge.cn) 目录 一&#xff0c;二叉搜索树&#xff08;Binary Search Tree&#xff09; 二叉搜索树的查找 二叉搜索树的插入 …

自动点赞软件崛起背后的秘密!你还不知道就真的OUT了!

先来看视频 智能引流黑科技&#xff0c;ks自动点赞软件教程 在数字化的世界中&#xff0c;社交媒体已经成为了我们日常生活的一部分。点赞、评论、分享&#xff0c;这些互动方式在塑造我们的数字身份的同时&#xff0c;也推动了信息的传播。然而&#xff0c;随着自动点赞软件的…

css入门基础(二)链接伪类细节详讲

注释很详细&#xff0c;直接上代码 新增内容&#xff1a; 1.链接伪类的使用顺序规范 2.链接伪类的使用效果 3.浏览器安全策略对visited伪类造成的影响 4.visited伪类的工作原理 源码&#xff1a; index.html <!DOCTYPE html> <html lang"en"> <head&…

【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 前言1. 移动零&#xff0…
最新文章