C语言指针(一)

目录

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.mzph.cn/news/616580.shtml

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

相关文章

XSS的利用(包含:蓝莲花、beef-xss)

0x00、环境搭建 dvwa靶场 操作指南和最佳实践:使用 DVWA 了解如何防止网站漏洞_dvwa源代码-CSDN博客 xss漏洞接收平台 下载:GitHub - firesunCN/BlueLotus_XSSReceiver 将解压后的BlueLotus_XSSReceiver原代码放置 phpstudy 安装目录的WWW文件夹下 访问平台:http://127…

力扣刷题记录(28)LeetCode:797、200、463

797. 所有可能的路径 解题思路&#xff1a;回溯算法&#xff0c;当收集到的路径的最后一个值等于n-1时&#xff0c;收集答案。 参数&#xff1a;图、当前结点 class Solution { public:vector<int> path;vector<vector<int>> ans;void dfs(vector<vector…

企业培训系统源码:构建智能、可扩展的学习平台

企业培训系统在现代企业中扮演着至关重要的角色。本文将通过深度解析企业培训系统的源码&#xff0c;介绍如何构建一个智能、可扩展的学习平台&#xff0c;涉及关键技术和代码实例。 1. 技术栈选择与项目初始化 在构建企业培训系统之前&#xff0c;选择适当的技术栈是至关重…

Linux操作系统----实用工具Git(配实操图)

绪论​ “针对问题 解决问题 针对问题&#xff01;”&#xff0c;本章主要讲解的是Git是什么以及Git的如何搭建仓库和如何在Linux环境下通过指令的形式提交自己的代码到远程仓库。 话不多说安全带系好&#xff0c;发车啦&#xff08;建议电脑观看&#xff09;。 1.Git的来源以…

vulnhub靶场之DC-5

一.环境搭建 1.靶场描述 DC-5 is another purposely built vulnerable lab with the intent of gaining experience in the world of penetration testing. The plan was for DC-5 to kick it up a notch, so this might not be great for beginners, but should be ok for p…

el-select 单选时,选择后输入框的is-focus状态并没有取消

前两天在封装组件的时候&#xff0c;发现el-select 单选时&#xff0c;选择后输入框的is-focus状态并没有取消&#xff0c;需要手动点其它地方才会取消&#xff0c;于是想着找找为什么 一、通过调试源码发现&#xff0c;输入框在点击选项后触发blur&#xff0c;紧接着又触发了…

STM32学习笔记二十一:WS2812制作像素游戏屏-飞行射击游戏(11)探索游戏脚本

还记得上次在第十七章中为BOSS创建的路径动画吧。我们写了一大坨的代码来描述BOSS的运动路径&#xff0c;但凡是写过几年代码的人都不会干出这样的事情。-_-! 没办法&#xff0c;谁叫那时候还没有脚本呢。这章就来补齐这块短板。 脚本属于配置化的一种&#xff0c;你可以把脚…

大模型学习与实践笔记(四)

一、大模型开发范式 RAG&#xff08;Retrieval Augmented Generation&#xff09;检索增强生成&#xff0c;即大模型LLM在回答问题或生成文本时&#xff0c;会先从大量的文档中检索出相关信息&#xff0c;然后基于这些检索出的信息进行回答或生成文本&#xff0c;从而可以提高回…

【实用技巧】Steam Wallpaper Engine 壁纸引擎向手机导入壁纸方法

一、内容简介 本文介绍如何使用电脑上的 Wallpaper Engine &#xff08;Steam 平台中的壁纸引擎&#xff09;向安卓手机导入并使用壁纸。 二、所需原材料 安卓手机&#xff08;以笔者使用的华为荣耀50为例&#xff09;、安装有Steam以及Wallpaper Engine的电脑 三、导入方法…

c++最值查找

目录 min和max函数 min_element和max_element 例 nth_element函数 例 例题 题目描述 输入描述 输出描述 解 min和max函数 只能传入两个值或一个列表 时间复杂度为O(1),数组O(n)&#xff0c;n为元素个数 min_element和max_element min_element(st,ed)返回地址[st,…

Rust 最新版1.75.0升级记

升级方法 稳定版 C:\>rustup update stable info: syncing channel updates for stable-x86_64-pc-windows-msvc info: latest update on 2023-12-28, rust version 1.75.0 (82e1608df 2023-12-21) info: downloading component cargo 5.9 MiB / 5.9 MiB (100 %) 3.…

宏集案例丨宏集PC Runtime软件助推食品行业生产线数字化革新

来源&#xff1a;宏集科技 工业物联网 宏集案例丨宏集PC Runtime软件助推食品行业生产线数字化革新 原文链接&#xff1a;https://mp.weixin.qq.com/s/DwzVzifUiidNr-FT3Zfzpg 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; 01 前言 近年来&#xff0c;中国食品行业…

html+css实现子元素完全居中常见方案

详细过程 查看公众号文章 htmlcss实现子元素完全居中常见方案 获取更多内容&#xff0c;请关注微信公众号。搜索“码圈小橙子”&#xff0c;或扫描下方二维码获取关注

FFmpeg编程录制音频(Mac OS)

之前我们使用FFmpeg命令行工具进行了简单的音视频操作&#xff0c;这次在Mac OS环境下编写代码实现简单的音频录制功能。 FFmpeg命令行音频录制 首先回顾一下Mac OS环境下简单的音频录制命令行实现&#xff1a; ffmpeg -f avfoundation -i ":0" -t 20 -acodec pcm…

opencv拉流出现missing picture in access unit with size 4错误解决

0、应用场景问题 我们使用opencv作为拉流客户端&#xff0c;获取画面后进行图像处理并推流&#xff08;使用ffmpeg库&#xff09;。 opencv解码同样使用ffmpeg库。 我们要求opencv能根据业务不断进行拉流操作&#xff0c;等效的逻辑代码如下&#xff1a; while(1) {printf(&…

gazebo模型库目录(国内源)

这个是比较普遍的&#xff0c;一般用途&#xff1a; GitCode - 开发者的代码家园https://gitcode.com/geniusChinaHN/osrf.gazebo_models/tree/master/ambulance这个主要是车辆&#xff1a; car_demo: osrf汽车模型库https://gitee.com/geniuschinahn/car_demo还有这个是以前…

YOLOv6s,map值打印成两位小数(原本是显示0.538,变成显示为53.79)

显示结果 更改前&#xff1a; 更改后&#xff1a; 方法 将tools/eval.py中的--do_pr_metric后面改为defaultTrue即可打印出map值原本是显示0.538&#xff0c;变成显示为53.79&#xff0c;方法为&#x1f447; 在YOLOv6-main/yolov6/core/evaler.py中做如下更改&#xff1a…

对回调函数的各种讲解说明

有没有跟我师弟一样的童靴~&#xff0c;学习和使用ROS节点时&#xff0c;对其中的callback函数一直摸不着头脑的&#xff0c;以下这么多回调函数的讲解&#xff0c;挨个看&#xff0c;你总会懂的O.o 回调函数怎么调用,如何定义回调函数&#xff1a; 回调函数怎么调用,如何定义…

最大公共子串

解题思路&#xff1a; 解题代码&#xff1a; UP主运用的方法很巧妙。厉害。

IPv6路由协议----BGP4+

BGP基本概念 边界网关协议BGP(Border Gateway Protocol)是一种实现自治系统AS(Autonomous System)之间的路由可达,并选择最佳路由的距离矢量路由协议。 MP-BGP是对BGP4进行了扩展达到在不同网络中应用的目的,BGP4原有的消息机制和路由机制并没有改变。MP-BGP在IPv6单播网…