C语言指针(一)

news2024/11/16 11:49:02

目录

1.什么是指针

2.指针变量和地址

1.解引用操作符

2.指针变量类型的意义

3.void*指针

4.const修饰指针

1.const放在*左边

2.const放在*右边

3.指针的运算

1.指针加减整数

2.指针减指针

3.指针比较大小

4.野指针

1.没有给指针变量初始化

2.指针指向的空间释放

3.指针越界访问

5.assert断言

6.传值调用和传址调用


1.什么是指针

在c语言中指针就是地址;我们将内存中的空间划分成一个一个字节,每一个字节都有自己的地址;一个字节是8bit位;

我们可以把地址看作一个宿舍的编号,一个宿舍有8个同学;通过这个宿舍的编号可以找到里面居住的同学;

在32位机器上,地址大小为32bit(4字节);

在64位机器上,地址大小为64bit(8字节);

2.指针变量和地址

指针变量的形式:

int a=10;
int* pa=&a;//指针变量

指针变量也是一种变量,只不过它里面存的是地址,同时,只要将一个正整数存入里面,他就会将那个数字看作是地址;那么这种指针类型的大小是多少呢?

我们知道如果是32位机器的话,地址的大小一定是4字节;那么int*的指针是否是4个字节呢?

那指针变量有char*,int*,double*,那么他们的类型又是多大呢?

同时我们要知道,地址的大小事4个字节,那么无论是什么类型的地址,它都是地址,只要是地址在32位机器上就是4个字节,在64位机器上就是8个字节;

我们发现好像类型不相同,大小好像都还是一样的,那么我们指针变量还要有类型的区分呢?

1.解引用操作符

我们取出地址是要去使用的,那么如何去使用?

指针操作中一个很重要的操作符解引用操作符( );比如上面我们要去通过这个指针变量pa对它指向的对象进行操作:

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

解引用操作符的作用就是通过某个地址找到这块地址所属的空间;

2.指针变量类型的意义

前面我们提到了,既然类型不同但是大小还是一样,那为什么还要有这么多不同的类型呢?

这里我们先来看2组代码:

我们通过内存观察发现,指针的类型不同好像操作的范围也不同;char*的指针只能操作一个字节,int*的指针能操作4个字节;

然后再让我们来看一组代码:

我们发现刚开始pa和ps指向的都是a;但是int*的指针加一从c4变成了c8,char*的指针从c4变成了c5;前面我们知道内存的每一个字节都是有自己的编号的,那么是不是就说明int*的指针加一跳过了4个字节,char*的指针跳过了个字节;同理,short*加一跳过2个字节;减法也是同理;

通过上面2个代码的演示我们可以总结2条指针类型的意义:

1.指针类型决定了解引用操作进行访问的字节的最大权限(所能操作的字节个数);

2.指针类型决定了指针进行加一减一运算向前和向后的距离;

3.void*指针

这种类型的指针是无具体类型的指针;这种类型的指针无法进行加一减一的运算,同时也无法进行解引用操作;这种类型有点类型于一个大的垃圾桶,什么类型的指针都能往里面装;

我们知道等号2变的类型必须相等,不然就会报错;

但是void*的类型的指针就不会有这种报错:

void*指针一般在函数里面用的比较多,比如我们进行传参的时候我们也不知道我们传的是什么类型数据的地址,这个时候我们就可以用void* 来接收这个地址;这个我们后面再谈;

4.const修饰指针

const是c语言的关键字,可以用来修饰变量和指针;它可以使变量具有常属性(常量是不可修改的),相当于使得我们无法对这个变量进行修改,从语法形式上限制了我们;

虽然我们从语法形式上限制了变量a,但是我们可以通过地址来找a的空间并将它修改了;这是非常不安全的;

我们不想让这个指针变量通过地址来改变a,就可以通过给指针变量前面加上const来修饰它;

1.const放在*左边

const放在*左边是限制*pa;如果是这样写int const* pa效果是一样的,都是限制了*pa;这样就不能通过地址来改变这个值了;

2.const放在*右边

const放在右边就限制了pa所指向的对象不可修改;但是可以通过地址来修改地址所指向的那块空间;

总结:

const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。但是指针变量本⾝的内容可变。


const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指
向的内容,可以通过指针改变。

3.指针的运算

1.指针加减整数

前面我们就提到了指针加减整数,不同类型的指针加减整数,向前和向后的距离不同,比如:char*的指针加一跳过一个字节,int*的指针加一跳过4个字节;

同理其他的类型也遵循这个规则;

2.指针减指针

这种一般用于同一块空间中进行计算;

数组名等于首元素的地址,arr+9说明此时指针变量指向了数组的最后一个元素;指针减去指针计算的是指针之间的元素个数;

3.指针比较大小

和数字一样,地址之间也有大小之分;

在数组中地址是由低到高变化的,栈区上的地址是从高往低使用的;

比较的方法和整数比较一样:

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

4.野指针

 在我们使用指针的时候一定要正确的使用指针,避免出现野指针;那么野指针又是什么呢?

准确来说野指针是没有明确的指向空间的,可能那块空间并不属于你,但是你通过野指针对那块区域进行操作;那么野指针是如何形成的呢?

1.没有给指针变量初始化

看过前面的栈区的创建和销毁那篇文章应该都知道,我们在创建一个局部变量的时候如果不进行初始化,里面放的就是cccccccc这种随机值;如果将这种随机值放在指针变量中的话,会默认将它看作是一个地址,如果此时我们对这个地址进行加一减一,解引用等操作,这是很危险的;那块空间并不是操作系统分配给我们的,而是一个随机的地址;

2.指针指向的空间释放

我们进行函数调用的时候,在里面所创建的局部变量出了函数作用域都是会销毁的;如果此时我们传回来了一个地址并且还用一个指针变量接收了这个地址;

这里我们虽然能运行起来并且打印的结果还是对的,是因为这个函数的栈帧空间没有被破坏,如果我们在前面随便打印一个东西,就会破坏栈帧空间,打印的就不是那个结果了;总而言之,返回栈空间地址都是不对的;

我们重点不在上面,当函数运行结束之后,函数的栈帧空间就会返回给操作系统,此时pa虽然拿到了那块地址的编号,但是并没有什么用,这块空间已经不属于我们了;此时,pa就是野指针;

3.指针越界访问

这里我们通过指针来访问数组的每一个元素,并把i赋值给每一个元素;当i=10的时候,此时指针已经指向了数组的外面,此时指针就是野指针,如果我们对这个地址进行操作,就是对野指针进行操作,这是很危险的;

在用指针的时候,我们自己要知道指针指向的地址是否是有效地址,避免出现返回栈区地址,指针越界访问等等问题;在我们不使用指针或者指针指向的地址的空间被销毁的时候,要及时将指针置为NULL(空指针);

5.assert断言

在使用指针的时候我们通常都会去判断指针指向的目标是否为NULL,会去判断指针的有效性;

assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报
错终⽌运⾏。这个宏常常被称为“断⾔”。

我们可以看到assert在报错的同时还会告诉我们出错的文件路径,还要第几行出现的,非常的好用;同时,在我们不使用的时候还可以关闭它:

我们只需要在assert.h的头文件前面加上#define NDEBUG即可,一定要在它的前面加上才有用;

#define NDEBUG
#include <assert.h>

同时,在Release版本会自动屏蔽assert断言;

6.传值调用和传址调用

传值调用这个很好理解,就是传的数值;比如我们写的加法函数:

int Add(int x, int y)
{
	return x + y;
}

int main()
{
	int a = 10;
	int b = 20;
	int ret = Add(a, b);
	printf("%d", ret);
	return 0;
}

这个时候我们传递的是a和b的数值,a和b是形参;修改形参不会影响实参;

传址调用就是传递地址,有时候我们仅仅有传值调用是没办法完成我们的目的的;比如,设计一个函数,让a和b的数值交换;此时,我们如果用传值调用的话是没法完成的,其1是形参无法改变实参,其二是函数的返回值有且仅有一个值;这个时候我们缺的就是如何于主调函数的a和b建立联系;这个时候就可以用传址调用;

void Fact(int* pa, int* pb)
{
	int tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}

int main()
{
	int a = 10;
	int b = 20;
	Fact(&a, &b);
	printf("交换之后%d %d", a, b);
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MES系统中的设备管理及设备数据采集

随时工厂数字化建设的大力推进&#xff0c;设备管理的效率得到了很大的提升&#xff0c;特别是作为机加工企业&#xff0c;设备是整个企业非常重要的核心资产。 一、设备进行数据采集面临痛点&#xff1a; 设备数据状况无法获取与掌握 设备老旧&#xff0c;信息化基础差&…

制造知识普及--MES系统中的调度排产管理

要想弄清楚MES系统调度排产的管理机制&#xff0c;则要首先搞清楚车间调度排产是一套怎样的工作流程&#xff0c;它的难点在什么地方&#xff1f; 生产调度指的是具体组织实现生产作业计划的工作&#xff0c;是对执行生产作业计划过程中发生的问题和可能出现的问题&#xff0c…

Springboot+vue学生考试系统

Springbootvue学生考试系统 演示视频 【Springbootvue学生考试系统】 https://www.bilibili.com/video/BV1gk4y1Q7em/?share_sourcecopy_web&vd_source11344bb73ef9b33550b8202d07ae139b 主要功能&#xff1a; 管理员可以添加题库分配课程教师&#xff0c;指定考试范围指定…

性能测试分析案例-定位服务吞吐量下降

环境准备 预先安装 docker、curl、wrk、perf、FlameGraph 等工具 sudo yum groupinstall Development Tools # 安装火焰图工具 git clone https://github.com/brendangregg/FlameGraph # 安装wrk git clone https://github.com/wg/wrk cd wrk && make && sud…

LeetCode 38 外观数列

题目描述 外观数列 给定一个正整数 n &#xff0c;输出外观数列的第 n 项。 「外观数列」是一个整数序列&#xff0c;从数字 1 开始&#xff0c;序列中的每一项都是对前一项的描述。 你可以将其视作是由递归公式定义的数字字符串序列&#xff1a; countAndSay(1) "1…

数字信号处理 唐向宏著 pdf +课后答案 免费下载

数字信号处理——原理、实现与仿真 pdf 唐向宏著 &#xff0b;课后答案 杭州电子科技大学 费劲心思在网上花钱买的&#xff0c;共享给大家 永久链接&#xff1a;https://wwi.lanzoup.com/b0140pf4f 密码&#xff1a;aflj 里面除了有原书PDF&#xff0c;还有课后题答案

二极管选型怎么选?常用参数要熟练~

同学们大家好&#xff0c;今天我们继续学习杨欣的《电子设计从零开始》&#xff0c;这本书从基本原理出发&#xff0c;知识点遍及无线电通讯、仪器设计、三极管电路、集成电路、传感器、数字电路基础、单片机及应用实例&#xff0c;可以说是全面系统地介绍了电子设计所需的知识…

AnyText多语言文字生成与编辑模型——让AI绘图自由添加精美文字

随着AIGC的爆火,图片生成技术得到飞速发展,当前AI生成的图片已达到真假难辨的高保真度。例如stable diffusion与midjourney为代表的文生图大模型。不过,当合成图片中出现文字内容时,现存的AI技术依然无法驾驭文字内容。因此,modescope提出了一种新型的文字生成方法,此方法…

数谷·企声|贵州空港智能科技:以“智”提“质”,助力贵阳智慧机场建设

当前&#xff0c;我国民航正大力推进“平安、绿色、智慧、人文”的四型机场建设。贵州空港智能科技有限公司&#xff08;下称“空港智能科技”&#xff09;作为贵州民航产业集团有限公司&#xff08;下称“民航产业集团”&#xff09;信息化建设的排头兵和主力军&#xff0c;近…

SQL-条件查询与聚合函数的使用

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;重拾MySQL &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出现错误&am…

(leetcode)Z字形变换 -- 模拟算法

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 题目链接 . - 力扣&#xff08;LeetCode&#xff09; 输入描述 string convert(string s, int numRows)&#xff0c;输入一个字符串s&#xff0c;以及一个行数numRows&#xff0c;将字符串按照这个行数进行Z字形排列&…

FPGA UDP协议栈:基于88E1111,支持RGMII、GMII、SGMII三种模式,提供3套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐我这里已有的以太网方案本协议栈的 1G-UDP版本本协议栈的 10G-UDP版本本协议栈的 25G-UDP版本1G 千兆网 TCP-->服务器 方案1G 千兆网 TCP-->客户端 方案10G 万兆网 TCP-->服务器客户端 方案 3、该UDP协议栈性能4、详细设计方案设…

C练习——魔术师猜三位数

题目&#xff1a; 有一种室内互动游戏&#xff0c;魔术师要每位观众心里想一个三位数abc&#xff08;a、b、c分别是百位、十位和个位数字&#xff09;&#xff0c;然后魔术师让观众心中记下acb、bac、bca、cab、cba五个数以及这5个数的和值。只要观众说出这个和是多少&#xf…

使用Python进行客户行为分析

客户行为分析是一个有价值的过程&#xff0c;它使企业能够做出数据驱动的决策&#xff0c;增强客户体验&#xff0c;并在动态市场中保持竞争力。 下面是我们可以遵循的客户行为分析任务的过程&#xff1a; 收集与客户互动相关的数据。它可以包括购买历史记录&#xff0c;网站…

C桑(Cython)从入门到入土(2): np数组操作对比

C桑(Cython)从入门到入土 2. np数组操作对比 Node sc518 Copy has image data of type unsigned long long实际上, &#x1f446;&#x1f3fb;这个错误是我探索Cython的缘起… code1: Form: 更现代的方法是使用内存视图而不是指针&#xff1a; cdef np.uint32_t[:,:,::1] …

爬虫逆向破解翻译接口参数

Python 请求baidu翻译接口&#xff1a;https://fanyi.baidu.com/v2transapi?fromzh&toen 步骤一&#xff1a; 查找构建请求参数 JS 断点发现如下参数&#xff1a; w {from: _.fromLang,to: _.toLang,query: e,transtype: i,simple_means_flag: 3,sign: b(e),token: windo…

【Linux】宝塔端口不通

1.问题描述&#xff1a;端口不通 以端口16588为例&#xff1a; 服务器16588端口是关闭的&#xff0c;防火墙规则是放通的&#xff0c;是由于服务器内的对应程序没有监听到 对应 的公网上 图1&#xff1a;端口检测 图2&#xff1a; 端口已放行 此时访问仍然不通&#xff0c;但…

Error: start of central directory not found; zipfile corrupt.

【报错】使用 unzip 指令在 AutoDL 上解压 .zip 文件时遇到 Error: start of central directory not found; zipfile corrupt. 报错&#xff1a; 重新上传后还是解压失败排除了 .zip 文件上传中断的问题。 【原因】Windows 和 Linux 下的压缩文件的二进制格式有所不同&#x…

Python-动态烟花【附完整源码】

烟花代码 运行效果&#xff1a;Python动态烟花代码 import pygame from random import randint from random import uniform from random import choice import math vector pygame.math.Vector2 # 重力变量 gravity vector(0, 0.3) # 控制窗口的大小 DISPLAY_WIDTH DISP…

【C#】当重复使用一段代码倒计时时,使用普通类和静态方法,实现简单的封装性、可扩展性、可维护性

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》序列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…