C语言深入理解指针(非常详细)(二)

news2025/1/21 9:27:00

目录

  • 指针运算
    • 指针+-整数
    • 指针-指针
    • 指针的关系运算
  • 野指针
    • 野指针成因
      • 指针未初始化
      • 指针越界访问
      • 指针指向的空间释放
    • 如何规避野指针
      • 指针初始化
      • 注意指针越界
      • 指针不使用时就用NULL
      • 避免返回局部变量的地址
  • assert断言
  • 指针的使用和传址调用
    • 传址调用
    • 例子(strlen函数的实现)

指针运算

指针的基本运算有三种,分别是:
• 指针±整数
• 指针-指针
• 指针的关系运算

指针±整数

因为数组在内存中是连续存放的,比如int类型的数组,每个元素相差4个字节,因此我们只需要知道首元素的地址就可以通过加减的方式找到后面元素的地址

int arr[10] = {1,2,3,4,5,6,7,8,9,10}
#include <stdio.h>
//指针+- 整数
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]);
for(i=0; i<sz; i++)
{
printf("%d ", *(p+i));//p+i 这⾥就是指针+整数 i每增加1就往后移动4个字节
}
return 0;
}

指针-指针

/指针-指针
#include <stdio.h>
int my_strlen(char *s)
{
char *p = s;
while(*p != '\0' )//遇到\0就代表字符串结束
p++;
return p-s;//同过着两个指针相减我们可以得到这个指针的总长度
}
int main()
{
printf("%d\n", my_strlen("abc"));
return 0;
}

指针的关系运算

//指针的关系运算
#include <stdio.h>
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++;//p没加1就增加4个字节
}
return 0;
}

野指针

概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的

野指针成因

指针未初始化

#include <stdio.h>
int main()
{
int *p;//局部变量指针未初始化,默认为随机值
*p = 20;
return 0;
}

指针越界访问

#include <stdio.h>
int main()
{
int arr[10] = {0};
int *p = &arr[0];
int i = 0;
for(i=0; i<=11; i++)//i=10和i=11时越界了
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
return 0;
}

指针指向的空间释放

#include <stdio.h>
int* test()
{
int n = 100;
return &n;//不是全局变量,在函数结束后地址就会消失
}
int main()
{
int*p = test();
printf("%d\n", *p);
return 0;
}

如何规避野指针

指针初始化

如果明确知道指针指向哪里就直接赋值地址,如果不知道指针应该指向哪里,可以给指针赋值NULL(空指针,也可以理解为0,但是不完全是0,因为0有整形和char类型,只是有那个意思)
NULL 是C语言中定义的⼀个标识符常量,值是0,0也是地址,这个地址是无法使用的,读写该地址会报错

#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endi

初始化如下

#include <stdio.h>
int main()
{
int num = 10;
int*p1 = &num;
int*p2 = NULL;
return 0;
}

注意指针越界

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

指针不使用时就用NULL

当指针变量指向⼀块区域的时候,我们可以通过指针访问该区域,后期不再使用这个指针访问空间的时候,我们可以把该指针置为NULL。因为约定俗成的一个规则就是:只要是NULL指针就不去访问
因此使用指针之前可以判断指针是否为NULL。
这里就是用if语句判断

int main()
{
int arr[10] = {1,2,3,4,5,67,7,8,9,10};
int *p = &arr[0];
for(i=0; i<10; i++)
{
*(p++) = i;
}
//此时p已经越界了,可以把p置为NULL
p = NULL;
//下次使⽤的时候,判断p不为NULL的时候再使⽤
//...
p = &arr[0];//重新让p获得地址
if(p != NULL) //判断
{
//...
}
return 0;
}

避免返回局部变量的地址

我们就需要创建的变量不是局部变量,也就是说我们可以创建全局变量,当然你可以在mian函数里面创建变量,然后将变量的地址传入函数中,再通过函数进行一系列操作,结束时可以将变量的地址传出,这样就可以避免返回局部变量了。

assert断言

assert.h 头文件定义了宏 assert() ,用于在运行时确保程序符合指定条件,如果不符合,就报错终止运行。这个宏常常被称为“断言”
可以理解为进行了一次安检,在通过时会对这个变量进行检测,判断是否符合条件

 assert(p != NULL);

上面代码在程序运行到这⼀行语句时,验证变量 p 是否等于 NULL 。
如果确实不等于 NULL ,程序继续运行,否则就会终止运行,并且给出报错信息提示
assert() 宏接受⼀个表达式作为参数。如果该表达式为真(返回值非零), assert() 不会产生任何作用,程序继续运行。
如果该表达式为假(返回值为零),assert() 就会报错,在标准错误流 stderr 中写入⼀条错误信息,显示没有通过的表达式,以及包含这个表达式的文件名和行号。
assert() 的使用对程序员是非常友好的,使用 assert() 有几个好处:它不仅能自动标识文件和出问题的行号,还有⼀种无需更改代码就能开启或关闭 assert() 的机制。
如果已经确认程序没有问题,不需要再做断言,就在 #include <assert.h> 语句的前面,定义⼀个NDEBUG

#define NDEBUG
#include <assert.h>

然后,重新编译程序,编译器就会禁用文件中所有的 assert() 语句。如果程序又出现问题,可以移除这条 #define NDBUG 指令(或者把它注释掉),再次编译,这样就重新启用了 assert() 语句。
assert() 的缺点是,因为引入了额外的检查,增加了程序的运行时间。
⼀般我们可以在debug中使用,在release版本中选择禁用assert就行,在VS这样的集成开发环境中,在release版本中,直接就是优化掉了。这样在debug版本写有利于程序员排查问题,在release版本不影响用户使用时程序的效率

指针的使用和传址调用

传址调用

学习指针的目的是使用指针解决问题,那什么问题,非指针不可呢?
例如:写⼀个函数,交换两个整型变量的值

#include <stdio.h>
void Swap1(int x, int y)
{
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
printf("交换前:a=%d b=%d\n", a, b);
Swap1(a, b);
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}

代码运行入下:
在这里插入图片描述
在main函数内部,创建了a和b,a的地址是在调用Swap1函数时,将a和b传递给了Swap1函数,在Swap1函数内部创建了形参x和y接收a和b的值,但是
x和y确实接收到了a和b的值,不过x的地址和a的地址不一样,y的地址和b的地址不一样,相当于x和y是独立的空间,那么在Swap1函数内部交换x和y的值,自然不会影响a和b,当Swap1函数调用结束后回到main数,a和b的没法交换。Swap1函数在使用的时候,是把变量本⾝直接传递给了函数,这种调用函数的方式我们之前在函数的时候就知道了,这种叫传值调用
。因此当我们传入内存后,运行结果如下:
在这里插入图片描述
我们可以看到实现成Swap2的方式,顺利完成了任务,这里调用Swap2函数的时候是将变量的地址传
递给了函数,这种函数调用方式叫:传址调用

结论:实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实参。所以Swap是失败的了

例子(strlen函数的实现)

//计数器⽅式
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\n", len);
return 0;
}

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

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

相关文章

MySQL 8.0.34安装教程

一、下载MySQL 1.官网下载 MySQL官网下载地址&#xff1a; MySQL :: MySQL Downloads &#xff0c;选择下载社区版&#xff08;平时项目开发足够了&#xff09; 2.点击下载MySQL Installer for Windows 3.选择版本8.0.34&#xff0c;并根据自己需求&#xff0c;选择下载全社区安…

2023开学礼新疆石河子大学图书馆藏八一新书《乡村振兴战略下传统村落文化旅游设计》许少辉新财经理工

2023开学礼新疆石河子大学图书馆藏八一新书《乡村振兴战略下传统村落文化旅游设计》许少辉新财经理工

监控服务器与Zabbix服务器时间同步配置

一、简介 zabbix server数据采集对时间同步的要求比较高&#xff0c;因为被监控的主机时间快了&#xff0c;会导致数据读取失败等问题&#xff0c;时间慢了&#xff0c;会有一堆的因为数据写入延时产生的误告警&#xff0c;会发生告警恢复时间比告警产生时间早的情况。此案列以…

CSS中如何实现文字渐变色效果(Text Gradient Color)?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 文字渐变色效果&#xff08;Text Gradient Color&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这…

MIT6.824 Spring2021 Lab 1: MapReduce

文章目录 0x00 准备0x01 MapReduce简介0x02 RPC0x03 调试0x04 代码coordinator.gorpc.goworker.go 0x00 准备 阅读MapReduce论文配置GO环境 因为之前没用过GO,所以 先在网上学了一下语法A Tour of Go 感觉Go的接口和方法的语法和C挺不一样, 并发编程也挺有意思 0x01 MapRed…

Navicat16安装教程

注&#xff1a;因版权原因&#xff0c;本文已去除破解相关的文件和内容 1、在本站下载解压后即可获得Navicat16安装包和破解补丁&#xff0c;如图所示 2、双击“navicat160_premium_cs_x64.exe”程序&#xff0c;即可进入安装界面&#xff0c; 3、点击下一步 4、如图所示勾选“…

Delphi 12 β版新增两个有用功能

目录 一、字符串长度允许超过255 二、新增多字符串功能 一、字符串长度允许超过255 现在&#xff0c;字符串字面量的长度可以超过 255 个字符&#xff1b;换句话说&#xff0c;字符串字面量不再局限于经典的 Pascal ShortString 类型。注意字面字符串的长度仍可能受到编辑器的…

一文读懂强化学习:RL全面解析与Pytorch实战

目录 一、引言强化学习的核心组成为什么强化学习重要&#xff1f;实用性与广泛应用自适应与优化推动AI研究前沿引领伦理与社会思考 二、强化学习基础马尔可夫决策过程&#xff08;MDP&#xff09;状态&#xff08;State&#xff09;动作&#xff08;Action&#xff09;奖励&…

私有云盘Nextcloud在线解压开发(瞎搞瞎搞0.0)

私有云盘 Nextcloud在线解压开发 缘由&#xff1a; 问&#xff1a;为啥百度网盘会员人家可以在线解压哇&#xff1f;&#xff1f;&#xff1f; 我&#xff1a;what&#xff1f;那必须安排哇&#xff01;&#xff01;&#xff01; python代码如下 from flask import Flask, req…

个微机器人开发接口

请求URL&#xff1a; http://域名地址/member/login域名地址开发者账号密码:后台系统自助开通 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/json 参数&#xff1a; 参数名必选类型说明account是string开发者账号password…

Centos 7 通过Docker部署OnlyOffice

前言&#xff1a; 在本文中&#xff0c;我们将详细介绍如何使用 Docker 部署功能强大的协作办公套件 OnlyOffice。通过 Docker&#xff0c;您可以轻松构建、部署和管理 OnlyOffice&#xff0c;从而提高团队协作和企业办公的效率。 一、安装Docker 1、向系统添加Docker CE软件仓…

Python小知识 - 1. Python装饰器(decorator)

Python装饰器&#xff08;decorator&#xff09; Python装饰器是一个很有用的功能&#xff0c;它可以让我们在不修改原有代码的情况下&#xff0c;为已有的函数或类添加额外的功能。 常见的使用场景有&#xff1a; a. 函数缓存&#xff1a;对于一些计算量较大的函数&#xff0c…

【小沐学NLP】Python使用NLTK库进行分词

文章目录 1、简介2、安装2.1 安装nltk库2.2 安装nltk语料库 3、测试3.1 分句分词3.2 停用词过滤3.3 词干提取3.4 词形/词干还原3.5 同义词与反义词3.6 语义相关性3.7 词性标注3.8 Text对象 结语 1、简介 NLTK - 自然语言工具包 - 是一套开源Python。 支持自然研究和开发的模块…

Android GB28181客户端开发(1):GB28181协议简介

Android GB28181客户端开发(1):GB28181协议简介 公共安全视频监控联网系统信息传输、交换、控制技术要求(2016版) 源码请翻到文章结尾 介绍GB28181协议 GB28181协议是一种基于IP网络的远程视频监控系统,它定义了设备之间的通信协议和数据格式。GB28181协议的主要特点是支…

YOLOv5算法改进(14)— 更换Neck之BiFPN

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。BiFPN &#xff08; Bidirectional Feature Pyramid Network &#xff09;是一种加权双向&#xff08;自顶向下 自底向上&#xff09;特征金字塔网络&#xff0c;是目标检测中神经网络架构设计的选择之一&#xff0c;是为…

【易售小程序项目】小程序首页完善(滑到底部数据翻页、回到顶端、基于回溯算法的两列数据高宽比平衡)【后端基于若依管理系统开发】

文章目录 说明细节一&#xff1a;首页滑动到底部&#xff0c;需要查询下一页的商品界面预览页面实现 细节二&#xff1a;当页面滑动到下方&#xff0c;出现一个回到顶端的悬浮按钮细节三&#xff1a;商品分列说明优化前后效果对比使用回溯算法实现ControllerService回溯算法 优…

气象站在日常生活中的重要性

气象站在我们的日常生活中起着重要的作用&#xff0c;它监测着天气的变化&#xff0c;能够提供及时、准确的天气信息&#xff0c;对我们的生产和生活都有着极大的影响。 一、气象站的工作原理 气象站通过一系列传感器设备&#xff0c;对风速、风向、温度、湿度、气压、雨量等…

华为数通方向HCIP-DataCom H12-821题库(单选题:241-261)

第241题 ​​LS Request​​报文不包括以下哪一字段? A、通告路由器(Advertising Router) B、链路状态 ID (Link Srate ID) C、数据库描述序列号(Database Dascription Sequence lumber) D、链路状态类型 Link state type) 答案:C 解析: LS Request 报文中包括以下字段…

将qt6编写的简单小程序烧录Android手机中,以及编译生成apk位置

准备工作 1、一个qt能够编译通过的简单工程。参考&#xff1a;https://www.bilibili.com/video/BV1tp4y1i7EJ?p15 2、配置好QT6的Android环境&#xff0c;(JDK,SDK,NDK等)&#xff0c;可参考&#xff1a;https://mar-sky.blog.csdn.net/article/details/132630567 3、一台闲置…

【计算机硬件CPU】

【计算机硬件CPU】 1、计算机硬件的五大单元2、一切设计的起点&#xff1a; CPU 的架构3、精简指令集 &#xff08;Reduced Instruction Set Computer, RISC&#xff09;4、复杂指令集&#xff08;Complex Instruction Set Computer, CISC&#xff09;5、例题&#xff1a;最新的…