当前位置: 首页 > news >正文

C语言学习之路--指针篇

目录

  • 一、前言
  • 二、指针
    • 一、指针是什么
      • 1、指针的重要理解
      • 2、指针变量
      • 3、其他问题
    • 二、指针和指针类型
      • 1、指针+—整数
      • 2、指针的解引用
    • 三、野指针
      • 1、野指针成因
      • 2、如何规避野指针
    • 四、指针的运算
      • 1、指针—指针
      • 2、指针的关系运算
    • 五、指针和数组
    • 六、二级指针
    • 七、指针数组

一、前言

  • 本人是一名小白,这一篇是记录我C语言学习中的指针的所学所得,仅为简单的认识下C语言中的各个知识。

二、指针

一、指针是什么

  • 指针是什么?

1、指针的重要理解

  1. 指针是内存中一个最小单元(一个字节)的编号,也就是地址。
  2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。
  • 那么,我们可以这样理解:
    在这里插入图片描述

2、指针变量

  • 我们可以通过&(取地址操作符)取出变量的内存起始地址,把该地址存放在一个变量中,这个变量就是指针变量。
#include <stdio.h>int main()
{int a = 10;    //在内存中开辟一块4个字节的空间int* pa = &a;  //这里我们对变量a,取出它的地址,可以用&(取地址操作符)//整形变量a占用4个字节的内存空间,第7行代码是将a的4个字节的第一个字节的地址存放在变量pa中,pa就是一个指针变量printf("%p", pa); //%p为指针变量的格式化输出return 0;
}

运行结果
在这里插入图片描述

  • 总结
    指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。

3、其他问题

  • 一个小的单元到底是多大?(一个字节)
  • 如何编址?
    经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。
  • 对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电
    平(低电压)就是(1或者0);
    那么32根地址线产生的地址就会是:

00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001

11111111 11111111 11111111 11111111

这里就有2的32次方个地址。
每个地址标识一个字节,那我们就可以给 (2^32Byte == 2^32/1024KB ==
2^32/1024/1024MB ==2^32/1024/1024/1024GB == 4GB) 4G的空间进行编址。
同样的方法,那64位机器,如果给64根地址线,那能编址多大空间,计算亦如此。
这里我们便明白:

  • 32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以
    一个指针变量的大小就应该是4个字节
  • 那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地
    址。
    总结
  • 指针变量是用来存放地址的,地址是唯一标识一个内存单元(一个字节)的,
  • 指针的大小在32位平台是4个字节,在64位平台是8个字节。

二、指针和指针类型

  • 我们都知道,我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢?
    准确的说:有的。
  • 当有这样的代码
int num = 10;
p = &num;

要将&num(num的地址)保存到p中,我们知道p就是一个指针变量,那它的类型是怎样的呢?

  • 因此,我们定义以下类型
char  *pc = NULL;
int  *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

这里可以看到,指针的定义方式是: type + * 。
其实:
char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址。

  • 那指针类型的意义是什么?

1、指针+—整数

#define  _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>int main()
{int n = 10;char* pc = (char*)&n;int* pi = &n;printf("%p\n", &n);printf("%p\n", pc);printf("%p\n", pc + 1);//输出比pc大1个字节printf("%p\n", pi);printf("%p\n", pi + 1);//输出比pi大4个字节return 0;
}

运行结果
在这里插入图片描述

  • 总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。

2、指针的解引用

#include <stdio.h>int main()
{int n = 0x11223344;char* pc = (char*)&n;int* pi = &n;*pc = 0;printf("%x\n", n);*pi = 0;printf("%x\n", n);return 0;
}

运行结果
在这里插入图片描述

  • 我们不难发现,pc只访问了一个字节,pi访问了4个字节。
  • 总结:
    指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
    比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

三、野指针

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

1、野指针成因

1、指针未初始化

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

2、指针访问越界

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

3、指针指向的空间释放

2、如何规避野指针

  1. 指针初始化
  2. 小心指针越界
  3. 指针指向空间释放,及时置NULL
  4. 避免返回局部变量的地址
  5. 指针使用之前检查有效性
#include <stdio.h>
int main()
{int *p = NULL;//....int a = 10;p = &a;if(p != NULL){*p = 20;}return 0;
}

四、指针的运算

1、指针—指针

#include <stdio.h>int my_strlen(char* s)
{char* p = s;while (*p != '\0')p++;return p - s;
}int main()
{char arr[] = "abc";int a = my_strlen(arr);printf("%d\n", a);return 0;
}

运行结果
在这里插入图片描述

2、指针的关系运算

for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{*vp = 0;
}
  • 实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证
    它可行。
    标准规定:
    允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与
    指向第一个元素之前的那个内存位置的指针进行比较。(上述代码中的value[0]与它前面的地址进行了比较)

五、指针和数组

#include <stdio.h>int main()
{int arr[3] = { 1,2,3 };printf("%p\n", arr);printf("%p\n", &arr[0]);return 0;
}

运行结果
在这里插入图片描述

  • 可见数组名和数组首元素的地址是一样的。
    结论:数组名表示的是数组首元素的地址。但两种情况除外
  1. sizeof(数组名),这里的数组名是表示整个数组,计算的是整个数组的大小,单位是字节
  2. &数组名,这里的数组名是表示整个数组,&数组名取出的是数组的地址,这是arr+1会跳过这个数组。
  • 那么这样写代码是可行的:
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址
  • 指针访问数组
#include <stdio.h>int main()
{int arr[3] = { 1,2,3 };int* p = arr; //指针存放数组首元素的地址int sz = sizeof(arr) / sizeof(arr[0]);//计算数组大小for (int i = 0; i < sz; i++){printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p + i);}for (int j = 0; j < sz; j++){printf("%d ", *(p + j));}return 0;
}

运行结果
在这里插入图片描述
总结: p+i 其实计算的是数组 arr 下标为i的地址。那我们就可以直接通过指针来访问数组。

六、二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
那就是 二级指针 。
在这里插入图片描述
对于二级指针的运算有:

  • *ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa

int b = 20;
*ppa = &b;//等价于 pa = &b;

  • **ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a

**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

七、指针数组

  • 指针数组是指针还是数组?
    答案:是数组。是存放指针的数组。
  • 数组我们已经知道整形数组,字符数组。

int arr1[5];
char arr2[6];

在这里插入图片描述

  • 那指针数组是怎样的呢?

int* arr3[5];//是什么?

在这里插入图片描述

即arr3是一个数组,有五个元素,每个元素是一个整形指针。

相关文章:

C语言学习之路--指针篇

目录一、前言二、指针一、指针是什么1、指针的重要理解2、指针变量3、其他问题二、指针和指针类型1、指针—整数2、指针的解引用三、野指针1、野指针成因2、如何规避野指针四、指针的运算1、指针—指针2、指针的关系运算五、指针和数组六、二级指针七、指针数组一、前言 本人是…...

吃透Java面试题,建议收藏

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址&#xff1a;https://github.com/…...

华为OD机试题,用 Java 解【最差产品奖】问题 | 含解题说明

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典本篇题目:最差产品奖 题目 A 公司准备对…...

Redis缓存优化

数据库在用户数量多&#xff0c;系统访问量大的时候&#xff0c;系统性能会下降&#xff0c;用户体验差。1.缓存优化作用&#xff1a;1.降低数据库的访问压力2.提高系统的访问性能3.从而提高用户体验实现思路&#xff1a;1.先查询缓存2.如果缓存有数据&#xff0c;直接返回3.如…...

少儿Python每日一题(23):楼梯问题

原题解答 本次的题目如下所示: 楼梯有n阶台阶,上楼可以一步上1阶,也可以一步上2阶,走完n阶台阶共有多少种不同的走法? 输入格式: 输入楼梯的阶梯数n 输出格式: 输出不同走法的个数 输入样例: 10 输出样例: 89 这是一道非常经典的题目,我们可以先寻找一下上楼梯的规律…...

【Leetcode】队列实现栈和栈实现队列

目录 一.【Leetcode225】队列实现栈 1.链接 2.题目再现 3.解法 二.【Leetcode232】栈实现队列 1.链接 2.题目再现 3.解法 一.【Leetcode225】队列实现栈 1.链接 队列实现栈 2.题目再现 3.解法 这道题给了我们两个队列&#xff0c;要求去实现栈&#xff1b; 首先&…...

(一)Tomcat源码阅读:查看官网,厘清大概轮廓

一、进入官网 点击以下链接进入官网:Apache Tomcat - Welcome!,点击介绍进入介绍&#xff0c;查看tomcat的项目结构。 二、查看项目结构 进入介绍后&#xff0c;我们可以看到下面的这些东西&#xff0c;这些对于tomcat是比较重要的&#xff0c;我们要一一对其进行解读。 这段…...

刷题记录(2023.3.14 - 2023.3.18)

[第五空间 2021]EasyCleanup 临时文件包含考点 分析源码&#xff0c;两个特殊的点&#xff0c;一个是 eval&#xff0c;另一个是 include eval 经过了 strlen filter checkNums 三个函数 include 经过了 strlen filter 两个函数 filter 检测是否包含特定的关键字或字符 fun…...

http协议 - 笔记

1 http协议 -- post,get,delete 如何使用http协议post - /api/v1/User/1 要使用 HTTP 协议 POST 方法向 /api/v1/User/1 发送请求,您可以使用一个 HTTP 客户端(例如 Postman、cURL 或浏览器扩展程序)并按照以下步骤操作: 打开您的 HTTP 客户端。在 URL 地址栏中输入 /a…...

第十八天 Vue-前端工程化总结

目录 Vue-前端工程化 1. 前后端分离开发 1.1 介绍 1.2 Yapi 2. 前端工程化 2.1 环境准备 2.2 Vue项目简介 2.3 Vue项目开发流程 3. Vue组件库Element 3.1 快速入门 3.2 常用组件 3.3 案例 Vue-前端工程化 前面我们已经讲解了HTML、CSS、JavaScript以及Vue等知识。已…...

python网上选课系统django-PyCharm

学生选课信息管理系统&#xff0c;可以有效的对学生选课信息、学生个人信息、教师个人信息等等进行管理。 开发语言&#xff1a;Python 框架&#xff1a;django Python版本&#xff1a;python3.7.7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat11 开发软件&#x…...

Java序列化与反序列化

优秀博文&#xff1a;IT-BLOG-CN 序列化&#xff1a;把对象转换为字节序列存储于磁盘或者进行网络传输的过程称为对象的序列化。 反序列化&#xff1a;把磁盘或网络节点上的字节序列恢复到对象的过程称为对象的反序列化。 一、序列化对象 【1】必须实现序列化接口Serializabl…...

【网络】网络层协议——IP

目录网络层IP协议IP基础知识IP地址IP报头格式网段划分CIDR特殊的IP地址IP地址的数量限制私有IP地址和公有IP地址路由IP总结网络层 在复杂的网络环境中确定一个合法的路径。 IP协议 IP协议作为整个TCP/IP中至关重要的协议&#xff0c;主要负责将数据包发送给最终的目标计算机…...

安装kubernetes

master110.10.10.10docker、kubelet、kubeadm、kubectlmaster210.10.10.11docker、kubelet、kubeadm、kubectlnode110.10.10.12docker、kubelet、kubeadm、kubectlnode210.10.10.13docker、kubelet、kubeadm、kubectl 1.关闭防火墙&#xff08;所有节点执行&#xff09; syste…...

三维点云转深度图

文章目录 目录 一、算法原理 算法流程 二、代码实现 1.Python代码 2....

Qt音视频开发27-ffmpeg视频旋转显示

一、前言 用手机或者平板拍摄的视频文件&#xff0c;很可能是旋转的&#xff0c;比如分辨率是1280x720&#xff0c;确是垂直的&#xff0c;相当于分辨率变成了720x1280&#xff0c;如果不做旋转处理的话&#xff0c;那脑袋必须歪着看才行&#xff0c;这样看起来太难受&#xf…...

python例程:《彩图版飞机大战》程序

目录开发环境要求运行方法《彩图版飞机大战》程序使用说明源码示例源码及说明文档下载路径开发环境要求 本系统的软件开发及运行环境具体如下。 操作系统&#xff1a;Windows 7、Windows 10。 Python版本&#xff1a;Python 3.7.1。 开发工具&#xff1a;PyCharm 2018。…...

【前端八股文】JavaScript系列:Set、Map、String常用属性方法

文章目录Set概念与arr的比较属性和方法并集、交集、差集Map概念属性和方法String用索引值和charAt()的区别charAt()和charCodeAt()方法的区别5个查找方法的区别如何把字符串分割为数组3个截取方法的区别大小写转换3个模式匹配方法&#xff08;正则表达式&#xff09;3个移除字符…...

跳跃-动态规划问题

跳跃-动态规划问题1、题目描述2、解题思路2.1 解法一&#xff1a;动态规划2.2 解法二&#xff1a;DFS深度优先搜索最大权值1、题目描述 小蓝在一个 n 行 m 列的方格图中玩一个游戏。 开始时&#xff0c;小蓝站在方格图的左上角&#xff0c;即第 11 行第 11 列。 小蓝可以在方格…...

Django笔记三十九之settings配置介绍

这一篇笔记介绍 Django 里 settings.py 里一些常用的配置项&#xff0c;这些配置有一些是在之前的笔记中有过介绍的&#xff0c;比如 logging 的日志配置&#xff0c;session 的会话配置等&#xff0c;这里就只做一下简单的回顾&#xff0c;有一些是之前没有介绍过的就着重介绍…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

stm32wle5 lpuart DMA数据不接收

配置波特率9600时&#xff0c;需要使用外部低速晶振...

消息队列系统设计与实践全解析

文章目录 &#x1f680; 消息队列系统设计与实践全解析&#x1f50d; 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡&#x1f4a1; 权衡决策框架 1.3 运维复杂度评估&#x1f527; 运维成本降低策略 &#x1f3d7;️ 二、典型架构设计2.1 分布式事务最终一致…...