指针概念及应用

指针的相关概念

1.指针是什么?

指针是内存中的一个最小单元的编号,其实就是指地址,对于我们平时口中所讲述的指针,通常指的是指针变量,指针变量是用来存放内存地址的变量。

2.地址与指针

一个32位机器在一个进程中可以一次操控4G的内存空间,并对这4GB的连续内存空间进行编码,得到2^32种编号,这个编号就是内存地址,一个编号(地址)对应一个内存单元。

指针,是内存中最小单元的编号,而内存中最小单元指的就是内存单元,内存单元的编号指的就是上述的2^32种编号,所以我们可以这样说:编号-地址-指针,这三种其实所指相同。

如图8.3地址1000是变量i的指针。

例如,将变量i的地址存放在指针变量p中,p就指向i。如图8.4

如图8.5

在地址2000上的变量是指向地址2005上的那个变量,在地质2000上该变量的内容是2005.同理,在地质2001上的变量是指向地址2004上的那个变量,在地址2001上该变量的内容是2004.

3.指针变量

一般格式:类型声明*变量名;

其中,“*”表示这是一个指针变量;“变量名”即为定义的指针变量名;“类型声明”表示本指针变量所指向的变量的数据类型。

在前面,我们学过许多种操作符,其中有个取地址操作符(&)以及解引用操作符(*)(又称为间接访问操作符)。

我们知道在创建一个变量时,当程序执行到创建变量,那么相应的会在内存空间内分配一个内存空间给这个变量,用于存储这个变量的值。

如果对一个变量使用取地址操作符,也那么就是取出这个变量的地址,通过之前的章节我们知道,例如一个int类型的变量,在创建变量时,内存会分给这个变量4个字节的空间大小,而一个字节对应着一个内存空间,对应一个内存地址,而四个字节就对应四个内存地址,而通常来说,我们口中的变量的地址指的是这个变量所占内存空间的低地址,也就是分配给这个变量的由低到高的地址中的第一个地址。

而当我们对一个变量使用取地址操作符时,取出的就是这个对应内存空间的第一个内存单元的地址。
如果我们取出这个变量的地址之后把它存放在另一个变量中,那么这个变量就是指针变量。

4.指针类型

指针变量,它也是一种变量,那么指针变量也是有类型的。

在代码中取出a的地址存放在pa中,pa是一个指针变量,这个指针变量的类型如普通变量一样,变量名的前面就是其类型,所以指针变量pa的类型是int*。
相对于普通的变量类型,指针变量的类型只是在类型后加上了*号,这个星号可和我们之前了解的解引用操作符不是一个作用(含义),这个星做作用是,与星号前面的类型进行结合,表明这个类型是一个指针类型,这个指针类型所定义的变量是指针变量。*的个数表示这个指针的级数。

5.定义指针

而定义一个指针变量的语法格式是:

type*name=NULL;

其中type位类型,name是你要创建的指针变量的变量名。

要注意的是,当你创建一个指针变量时,你需要给其进行初始化,如果你不知道或者说暂时不需要赋值,你可以先赋值为NULL。绝对不允许不进行初始化创建指针变量,不初始化会出现野指针,这是很危险的行为。

NULL在C语言中你可以理解为空指针,是计算机内存中保留的值。虽然C语言标准没有明确指出NULL空指针与指向内存地址为0x00000000的指针相同,但是在实际情况中,基本就是这样。

另外虽然在初始化时可以赋给指针变量NULL,但是解引用空指针,这种操作是不允许存在的,是C语言为定义的行为

6.指针类型的意义

  1. 指针类型决定了,在对指针进行解引用时,可以访问的内存大小,可以访问多少个字节大小的内存空间。或者说可以对多大的内存空间进行操作。
  2. 指针类型决定了指针的步长。

7.指针的赋值

一般格式:&变量名;

指针变量同普通变量一样,使用之前不仅要定义,而且必须赋予具体的值。未经赋予的值不能使用

给一个指针变量赋值可以有以下两种方法:

1.定义指针变量的同时就进行赋值。

int a;

int*p=&a;

2.先定义指针变量,然后再赋值。

int a;

int*p;

p=&a;

注意:如果在定义完指针变量之后再赋值,注意不要加*”。

p中存储的是a的地址,*p就是通过p中存放的地址,找到内存中对应这个地址编号的一块空间,并直接对空间进行操作。这就是解引用操作符。

8.大小端字节序

字节序

字节序又称端序或尾序,在计算机领域中,指电脑内存中或在数字通信链路中,占用多个字节的数据的字节排列顺序。

字节的排列方式有两个通用规则:

大端序(Big-Endian)将数据的低位字节存放在内存的高位地址,高位字节存放在低位地址。这种排列方式与数据用字节表示时的书写顺序一致,符合人类的阅读习惯。

小端序(Little-Endian),将一个多位数的低位放在较小的地址处,高位放在较大的地址处,则称小端序。小端序与人类的阅读习惯相反,但更符合计算机读取内存的方式,因为CPU读取内存中的数据时,是从低地址向高地址方向进行读取的。

为什么会出现大小端呢?

当往内存中存放数据的时候,我们有很多种存放的顺序,正着放,反着放,随机存放等等等等,例如我们往内存中存放0x11223344,这只是演示。

如果是你让你从上述片段中快速的按顺序取出数据,你会选择哪种方法呢?所以就出现了大小端排序。

过这个大小端,为什么叫大小端而不是叫别的,据说是因为发明者当时在看格列夫游记,看到其中两个国家因为争论吃鸡蛋应该先从大头剥还是小投剥,发动了战争,而获得启发,起名大小端。

9.步长

10.野指针

野指针就是指针指向的位置是不可知的、随机的、甚至没有访问权限的。

为什么会存在野指针?
1.指针未初始化
#include <stdio.h>
int main()
{
    int* p;     //局部变量指针未初始化。默认为随机值
    *p = 10;

    return 0;
}

2.指针越界访问
就比如,对于一个数组,只有十个元素,而我非要去访问这个数组的第十一个元素,这就是数组越界访问。
指针也是,当指针指向的地址不在数组所拥有的内存空间范围时,指针就成为了野指针。
#include<stdio.h>
int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    int* p = arr;
    int i = 0;
    
    for (i = 0; i <= 10; i++)
    {
        printf("%d ", *(p+i));
    }

    return 0;
}
3.指针指向的空间释放
局部变量的作用域是有限的,当出了变量所在的局部范围,变量就自动销毁了,其所分配的空间就还给内存了。这个时候,如果主函数内部有指针指向这个局部变量销毁之前所指向的地址,那么局部变量自动销毁之后,这个指针就变成了野指针。
#include<stdio.h>
int* test()
{
    int a = 10;
    return &a;          //&a=0x0012ff40
}
int main()
{
    int* p = test();
    return 0;
}
规避野指针
1.指针初始化
2.小心指针越界访问
3.指针指向空间释放,及时置NULL
4.避免返回局部变量的地址
5.指针使用之前检查有效性

11.二级指针

一级指针,创建一个指针变量用于存放一个普通类型变量的地址。例如

int a = 10;
int* pa = &a;  // 其中pa是一级指针变量。
而指针变量也是变量,是变量在创建是就会分配内存空间,所以一个指针变量在内存中也是有一块内存空间的。那么也就存在相应的地址编号。

int a = 10;
int* pa = &a;  // 其中pa是一级指针变量。

int** ppa = &pa;  //ppa是二级指针变量

a的地址存放在一级指针变量pa中,pa的地址存放在二级指针变量ppa中。
解引用ppa通过存储在ppa内的地址,找到pa,再对pa进行解引用,找到a。

int a; 变量a的类型是int类型

int * pa ,这个*表示这个pa是一个指针变量,int表示pa存储的地址指向的内存空间中存储的是int类型的值

int* *pa ,第二个*表示,pa是一个指针变量,int*表示ppa存储的地址指向的内存空间中存储的是int*类型的。

指针运算关系

对于指向地址的指针,可以进行下列的运算:

1.指针 +/- 整数

通过一个小例题来理解
使用指针,将一个数组内的所有元素赋值为0

*p++;与(*p)++;*++p;的区别

*p++  ===  *(p++)----->>先p++再*p

(*p)++;---->>先对p解引用,再++。

*++p;----->>先++,再解引用。

一元运算符*和++的优先级相同,但结合律是从右往左(其他大部分是从左往右)。

2.指针 - 指针

使用指针-指针,运算时,前提是两个指针需要指向同一块内存空间。例如同时指向一个数组中的不同元素。
指针-指针得到的值的绝对值是两个指针之间的元素的个数。

3 比较两个指针大小

指针与数组

1.int a[] = {1,2}; int *p = a

数组类似于指向位置固定的指针
即a除了不能 进行a++,其他用法和指针差不多

2. *(p+i) = p[i] = a[i] = *(a+i)

p+i = &p[i] = a+i = &a[i]

假设 p=200 则 p+n =200+n*size
size = p所指向的类型的大小

3.数组作为参数传入函数

数组作为参数传入函数时,函数只会生成一个指针来保存传入数组的首地址
即 fun(int a[ ]) = fun(int* a)
数组作为参数传入函数被修改后,main中也会被修改。

4.字符串数组

字符串必须以\0结束,计算字符串长度计算到 \0 为止

sizeof

用于计算变量本身所占用的字节数,而不是变量指向的地址所占用的空间大小

strlen

用于计算以 NULL (\0)结尾的字符串中字符的个数

5.两种定义方式

char w[] = “hi” 被定义在栈区,可以被修改
char *w = “hi” 被定义在常量区,不能修改

6.int a[ ][3]={1,2,3,4,5,6}

int a[2][3]; int (* p)[3] = a;
不能写成int **p= a, 指针类型不同

7.a[i][j] = *(a[i]+j) = *( *(a+i)+j)

8.c[i][j][k] = *( *( *(c+i)+j)+k)

c[i][j][k] = *((c[i][j]+k) = *(*(c[i]+j)+k)

原理与上一条相似。

感谢:https://blog.csdn.net/2201_75314884/article/details/127992565

感谢:https://blog.csdn.net/m0_60292931/article/details/123981539

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

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

相关文章

多线程原理和常用方法以及Thread和Runnable的区别

文章目录 &#x1f366;多线程原理&#x1f367;随机性打印&#x1f368;多线程内存图解 &#x1f369;Thread类的常用方法&#x1f36a;获取线程名称 getName()&#x1f382;设置线程名称 setName() 或者 new Thread("线程名字")&#x1f370;使当前正在执行的线程以…

python 交互模式和命令行模式的问题

python 模式的冲突 unexpected character after line continuation character 理论上 ide里&#xff0c;输入 python 文件路径\文件.py 就可以执行 但是有时候却报错 unexpected character after line continuation character 出现上述错误的原因是没有退出解释器&#x…

JMeter从入门到精通

1、 jmeter的介绍 jmeter也是一款接口测试工具&#xff0c;由java语言开发的&#xff0c;主要进行性能测试。 2、jmeter安装 jmeter官网下载链接&#xff1a; https://jmeter.apache.org/download_jmeter.cgi &#xff0c;查看是否安装成功【jmeter -v】 下载 java jdk1.8&…

计算一个4+4+1的队形变换问题

2 2 1 1 2 2 2 2 1 1 2 2 3 3 A A 3 3 4 4 A 12 4 4 4 4 12 A 4 4 2 2 1 1 2 2 操场上有4个人以4a1的结构在6*6的平面上运动&#xff0c;行分布是0&#xff0c;0&#xff0c;0&#xff0c;1&#xff0c;1&#xff0c;2&#xff0c;列分布…

[Android] c++ 通过 JNI 调用 JAVA函数

如何使用&#xff1a; Calling Java from C with JNI - CodeProject c里的 JNI 类型 和 JAVA 类型的映射关系&#xff1a; JNI Types and Data Structures Primitive Types and Native Equivalents Java TypeNative TypeDescriptionbooleanjbooleanunsigned 8 bitsbytejbyt…

局域网协议:以太网(Ethernet)详解

文章目录 Ethernet的组成以太网和 Wi-Fi以太网应用场景以太网的发展历程以太网数据链路层CSMA/CD (载波侦听多路访问/冲突检测)推荐阅读 以太网&#xff08;Ethernet&#xff09;是一种局域网&#xff08;LAN&#xff09;技术&#xff0c;用于在局域网范围内传输数据。它是最常…

【深度学习】gan网络原理生成对抗网络

【深度学习】gan网络原理生成对抗网络 GAN的基本思想源自博弈论你的二人零和博弈&#xff0c;由一个生成器和一个判别器构成&#xff0c;通过对抗学习的方式训练&#xff0c;目的是估测数据样本的潜在分布并生成新的数据样本。 1.下载数据并对数据进行规范 transform tran…

《ChatGPT实操应用大全》探索无限可能

&#x1f5e3;️探索ChatGPT&#xff0c;开启无限可能&#x1f680; 文末有免费送书福利&#xff01;&#xff01;&#xff01; ChatGPT是人类有史以来最伟大的发明。他能写作、绘画、翻译、看病、做菜、编程、数据分析、制作视频、解高等数学题…&#xff0c;他会的技能…

《2023开发者生态系统现状》:ChatGPT 是最常用的 AI 工具,60%开发者使用代码生成工具辅助编程

在前有编程语言历经 80 年的迭代&#xff0c;后有 GitHub Copilot、ChatGPT 等 AI 辅助编程工具的层出不穷&#xff0c;开发者的开发方式发生了什么样的变化&#xff1f;行业中领头的 Java IDE IntelliJ IDEA、Kotlin 编程语言背后的软件工具开发公司 JetBrains 基于全球 26,34…

【Java 基础】09 封装 继承 多态

我们都知道 Java 是以面向对象而著称&#xff0c;最著名的当然就是面向对象的三大特性啦&#xff0c;接下来就逐一举例说明一下。 1. 封装 封装指的是将类的内部细节隐藏起来&#xff0c;只对外提供必要的访问方式。 例如&#xff1a; 我们使用的计算器做一个乘法运算&#x…

[原创]Delphi的SizeOf(), Length(), 动态数组, 静态数组的关系.

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XXQQ: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、Delphi…

SQL Sever 复习笔记【一】

SQL Sever 基础知识 一、查询数据第1节 基本 SQL Server 语句SELECT第2节 SELECT语句示例2.1 SELECT - 检索表示例的某些列2.2 SELECT - 检索表的所有列2.3 SELECT - 对结果集进行筛选2.4 SELECT - 对结果集进行排序2.5 SELECT - 对结果集进行分组2.5 SELECT - 对结果集进行筛选…

【前端】多线程 worker

VUE3 引用 npm install worker-loader 在vue.config.js文件的defineConfig里加上配置参数 chainWebpack: config > {config.module.rule(worker-loader).test(/\.worker\.js$/).use({loader: worker-loader,options: {inline: true}}).loader(worker-loader).end()}先在…

C语言错误处理之 “<errno.h>与<error.h>”

目录 前言 错误号处理方式 errno.h头文件 error.h头文件 参数解释&#xff1a; 关于的”__attribute__“解释&#xff1a; 关于“属性”的解释&#xff1a; 实例一&#xff1a; 实例二&#xff1a; error.h与errno.h的区别 补充内容&#xff1a; 前言 在开始学习…

后仿真 ERROR

后仿真 error ERROR (SFE-23): "input.scs" 252: The instance _57_D32_noxref is referencing an undefined model or subcircuit, parasitic_nwd. Either include the file containing the definition of parasitic_nwd, or define parasitic_nwd before running t…

VUE2+THREE.JS点击事件

THREE.JS点击事件 1.增加监听点击事件2.点击事件实现3.记得关闭页面时 销毁此监听事件 1.增加监听点击事件 renderer.domElement.addEventListener("click", this.onClick, false); 注:初始化render时监听 2.点击事件实现 onClick(event) {const raycaster new …

LV.12 D21 PWM实验 学习笔记

一、PWD简介 1.1 蜂鸣器工作原理 有源蜂鸣器 有源蜂鸣器只要接上额定电源就可以发出声音 无源蜂鸣器 无源蜂鸣器利用电磁感应原理&#xff0c;为音圈接入交变电流后形成的电磁铁与永磁铁相吸或相斥而推动振膜发声 1.2 使用GPIO控制 while(1) { GPX2.DATGPX2.D…

Python中用于机器学习的Lazy Predict库

Python是一种多功能语言&#xff0c;你可以用它来做任何事情。Python的一个伟大之处在于&#xff0c;有这么多的库使它变得更加强大。Lazy Predict就是其中一个库。它是机器学习和数据科学的一个很好的工具。在本文中&#xff0c;我们将了解它是什么&#xff0c;它做什么&#…

matlab 无迹卡尔曼滤波

1、内容简介 略 26-可以交流、咨询、答疑 2、内容说明 无迹卡尔曼滤波 无迹卡尔曼滤波 无迹卡尔曼滤波 3、仿真分析 %该文件用于编写无迹卡尔曼滤波算法及其测试 %注解&#xff1a;主要子程序包括&#xff1a;轨迹发生器、系统方程 % 测量方程、UKF滤波器 %----…

LeetCode Hot100 31.下一个排列

题目&#xff1a; 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。 例如&#xff0c;arr [1,2,3] &#xff0c;以下这些都可以视作 arr 的排列&#xff1a;[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。 整数数组的 下一个排列 是指其整数的下一个字典序更大的排列…