指针(1)-学习笔记

news2024/9/22 1:56:44

指针(1)-学习笔记

  • 1.内存
    • 1.1内存
  • 2.指针变量和地址
    • 2.1取地址操作符(&)
    • 2.2指针变量和解引用操作符(*)
      • 2.2.1 指针变量
      • 2.2.2解引用操作符
  • 3 指针变量类型的意义
    • 3.1指针的解引用
    • 3.2指针+-整数
    • 3.3 void*指针
  • 4.const修饰指针
    • 4.1 const修饰变量
  • 5.指针运算
    • 5.1 指针+-整数
    • 5.2 指针-指针
    • 5.3 指针的关系运算

1.内存

1.1内存

内存就像一个房间号,有了房间号,就可以快速的找到,就可以提高效率。我们知道CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,其实就是把内存划分为一个个的内存单元,每个内存单元的大小取1个字节

计算机常见的单位:

bit - 比特位
Byte - 字节
KB
MB
GB
TB
PB

单位换算:

1Byte = 8bit
1KB = 1024Byte
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
1PB = 1024TB

其中,每个内存单元,相当于一个学生宿舍一个字节空间里面能放8个比特位,就相当于,一个宿舍有八个人,每个人是一个比特位

每个内存单元也都有⼀个编号(这个编号就相当于宿舍房间的⻔牌号),有了这个内存单元的编号,CPU就可以快速找到⼀个内存空间。

在计算机中把内存单元的编号叫做地址,C语言中给地址起了一个新名字指针
所以我们可以理解为内存单元的编号== 地址==指针

2.指针变量和地址

变量创建的本质是什么?
是向内存申请空间
int a=10,是向内存申请4个字节的空间,因为int类型在内存中占四个空间。

2.1取地址操作符(&)

我们可以写一段代码来观察一下地址:
在VS中逐句运行开始后,才可以打开观察内存的页面。
在这里插入图片描述

#include<stdio.h>
int main()
{
	int a = 10;
	printf("%p\n",&a);//&--取地址操作符
	return 0;
}

在这里插入图片描述
比如,上述的代码就是创建了整型a,内存中申请4个字节,用于存放整数10,其中每个字节都是有地址的,上图4个字节的地址分别是:

0x0069FEA0
0x0069FEA1
0x0069FEA2
0x0069FEA3

&a取出的是a所占4个字节中地址较小字节的地址。虽然整型变量占用4个字节,我们只要知道了第一个字节地址,顺藤摸瓜访问到4个字节的数据也是可⾏的。

2.2指针变量和解引用操作符(*)

2.2.1 指针变量

我们通过取地址操作符(&)拿到的地址是一个数值,这个数值有时候也是需要存储起来,方便后期再使用,我们就把这个存放在:指针变量中。将数值的地址存放在指针变量中。比如:

int main()
{
	int n = 20;
	int* pn = &n;
	return 0;
}

在这里int*是指针变量的类型。pn就被称为指针变量

int n=20;类型是 int
char ch=‘w’;类型是char
int * pn=&n;类型是int *

指针变量是指向了一个变量,比如,上面的代码pn(指针变量)就执行了n(变量)。int中的说明pn是指针变量,int说明pn指向的对象(就是n)是int类型。

2.2.2解引用操作符

在C语言中,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针)指向的对象,这里就必须来了解一下*(解引用操作符)。

int main()
{
	int n = 20;
	int* pn = &n;
	//解引用操作符-间接访问操作符
	*pn = 30;//*pn就是n
	printf("%d", *pn);
	return 0;
}

这里可以看到n的20被改为了30
在这里插入图片描述
这里是把n的修改交给了pn来操作,这样对n的修改,就多了一种途径,写代码就会更加灵活。
指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的。

3 指针变量类型的意义

3.1指针的解引用

指针可以接收与自己不同类型的地址
对比,下面两段代码,观察内存的变化。
代码一:

int main()
{
	int n = 0x11223344;
	int* pi = &n;
	*pi = 0;
	return 0;
}

在这里插入图片描述
代码二:

int main()
{
	int n = 0x11223344;
	char* pc = (char*)&n;//强制转换类型
	*pc = 0;
	return 0;
}

在这里插入图片描述

在第二段代码中,强制将n的地址从int类型转换到char类型,可以发现,存储在内存中的字节发生了改变,从4个字节变为1个字节。
结论:指针的类型决定了,对指针解引用的时候有多大的权限(一次能操作几个字节)。
比如:char的指针解引用就只能访问一个字节,而int的指针的解引用就能访问四个字节。

3.2指针±整数

观察下面一段代码:

int main()
{
	int n = 10;
	char* pc = (char*)&n;
	int* pi = &n;
	printf("%p\n", pc);
	printf("%p\n", pc + 1);
	printf("%p\n", pi);
	printf("%p\n", pi + 1);
	return 0;
}

代码运行结果如下:

在这里插入图片描述
我们可以看出,char类型的指针变量+1跳过1个字节,int类型的指针变量+1跳过了4个字节。这就是指针变量的类型差异带来的变化。指针+1,其实跳过1个指针指向的元素。指针可以+1,那么也可以-1.
结论:指针的类型决定了指针向前或者向后走一步有多大(距离)。

3.3 void*指针

void* 是无具体类型的指针(或者叫泛型指针),这种类型的指针可以用来接受任意类型地址。但是也有局限性,void类型的指针不能直接进行指针±整数和解引用的运算
在3.1中说:指针可以接收与自己不同类型的地址,是对的,但是会编译器会报警告,所以这时候就可以使用void
来接收不同类型的地址。
void*的局限性:
在这里插入图片描述

当我们试图改变void类型下的数值,就会报错,所以这里我们就可以看到,void类型的指针可以接受不同类型的地址,但是无法直接进行指针计算。

4.const修饰指针

4.1 const修饰变量

const是常属性-被const修饰后就具有常属性,不能被修改。
1.const修饰普通变量
2.const修饰指针变量
变量是可以修改的,如果把变量的地址交给一个指针变量,通过指针变量的也可以修改这个变量。

在这里插入图片描述
当const修饰了num后,再改变,编译器提示报错;再C语言中,这里的num是常变量,num的本质还是变量,因为有const修饰,编译器在语法上不允许修改这个变量。
接下来,我们看一段代码:

int main()
{
	const int num = 0;
	int* pn = &num;
	*pn = 20;
	printf("%d", num);
	return 0;
}

结果是:20.
我们绕过num,使用num的地址,去修改num,这样结果是可以的。但是,这是不合理的,我们本来的想法就是希望num不要被修改,接下来应该怎么做呢?那我们可以对pn也做一个修饰,也就是const修饰指针。
const修饰指针可以分为三种情况:
① const放在的左边
②const放在
的右边
③const同时放在*两边

第一种:

int main()
{
	const int num = 10;
	int n = 100;
	const int* p = &num;
	p = &n;//没有错误
	*p = 20;//发生错误
}

意思:表示指针指向的内容,不能通过指针来改变了。但是指针变量本身的值是可以改的,p是可以改的。

第二种:

int main()
{
	const int num = 10;
	int n = 100;
	int* const p = &num;
	p = &n;//错误
	*p = 20;//没有错误
}

意思:表示指针变量p本身不可以修改了,但是指针指向的内容,是可以通过指针变量来改变的。

第三种:

int main()
{
	const int num = 10;
	int n = 100;
	const int* const p = &num;
	p = &n;//错误
	*p = 20;//错误
}

意思:指针变量p不能被修改,指针变量p指向的内容也不能被修改。

5.指针运算

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

5.1 指针±整数

因为数组在内存中是连续存放的,只要知道第一个元素的地址,顺藤摸瓜就能找到后面的所有元素。

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 这里就是指针+整数
	}
	printf("\n");
	for (i = sz-1; i >= 0; i--)//倒叙
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

也可以用下面的形式来写:

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);
		p++;//p=p+1,p是int类型,一次跳过4个字节
	}
	return 0;
}

上面代码的弊端就是p一直在变化。

5.2 指针-指针

指针-指针后得到的绝对值是指针和指针之间的元素个数。
这种运算的前提条件是:两个指针指向同一块空间
下面的代码就是错误的。

int main()
{//第一个就是好不确定两个数组是不是连续的。
	//第二是不知道是按照char类型来算还是int类型来算
	char arr1[10];
	int arr2[10];
	&arr2[8] - arr2[5];//错误的
	return 0;
}

注释:
sizeof的返回值是size_t;头文件是#include<string.h>,strlen统计的是字符串中“\0”之前的字符的个数
我们现在可以来自己实现以下计算字符串的长度,不使用strlen

#include<string.h>
size_t my_strlen(char* s)
//传过来的是地址,我们也应该用地址来接受,所以就是指针
//要统计字符串的长度,现在就要看s指向的内容如果不等于\0,就++
{
	size_t count = 0;
	while (*s != '\0')
	{
		count++;
		s++;
	}
	return count;
}
int main()
{
	char arr[] = "abcdef";
	//数值名其实是数组首元素地址
	size_t len = my_strlen(arr);//arr==arr[0]
	printf("%d", len);
	return 0;
}

另一种方法:指针-指针得到的是指针和指针之间的元素个数。

size_t my_strlen(char* s)
{
	char* start = s;//将s的起始地址给start
	while (*s != '\0')//找到\0之前的地址
	{
		s++;
	}
	return s - start;
}

5.3 指针的关系运算

其实就是两个地址比较大小。
使用数组的关系运算来打印数组的内容
我们可以拿出来数组中最后一个元素的地址,然后让p取遍历,如果小于最后一个元素的地址,那么就++

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

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

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

相关文章

PyTorch深度学习实战(7)—— 线性回归

线性回归是机器学习的入门内容&#xff0c;应用十分广泛。线性回归利用数理统计中的回归分析来确定两种或两种以上变量间相互依赖的定量关系&#xff0c;其表达形式为$y wxbe$。其中&#xff0c;$x$和$y$是输入输出数据&#xff0c;$w$和$b$是可学习参数&#xff0c;误差$e$服…

Pod的调度机制

文章目录 一、Pod调度概述二、Pod调度策略实现方式三、kube-scheduler调度1、kube-scheduler调度的流程2、过滤阶段3、打分阶段4、kube-scheduler 调度示例4.1、创建 Deployment 资源清单4.2、应用Deployment4.3、查看被kube-scheduler自动调度的Pod 四、nodeName调度1、创建Po…

MySQL操作2——表的的操作(增删查改)

创建表; 样例&#xff1a; 注意不同的存储引擎创建出来的表在目录下的个数不同 显示此数据库下的所有表&#xff1a;show tables; show create table name \G ——查看创建表时的具体信息 查看某个表的结构&#xff1a;desc 表名&#xff1b; 查看表中储存的数据&…

阿里云与优酷联袂:Create@AI江湖创作大赛,探索AI创新边界

随着网剧《少年白马醉春风》的热播&#xff0c;许多人心中的江湖梦被唤醒&#xff0c;渴望踏入那个充满传奇色彩的影视世界&#xff0c;体验一段属于自己的江湖之旅。在 AIGC 技术日益成熟的今天&#xff0c;这一梦想变得触手可及。阿里云携手优酷&#xff0c;发起了 Create A…

Hadoop YARN:现代大数据集群资源管理与作业调度

1.Yarn的概述 1.1.解释Yarn的定义和基本概念 Hadoop YARN&#xff08;Yet Another Resource Negotiator&#xff09;是 Hadoop 2.x 版本引入的一种资源管理器&#xff0c;用于管理和调度大数据集群中的资源&#xff0c;是 Hadoop 集群的核心组件之一。YARN 的设计目标是提高 H…

浅谈C语言动态内存分配

1、什么是动态内存分配 正常情况下&#xff0c;我们创建变量&#xff0c;都是向计算机内存中申请一个静态的内存&#xff0c;也就是说&#xff0c;一旦申请成功&#xff0c;这块内存的大小便不能再改变&#xff0c;并且能申请多少内存在一定程度上都是确定的。比如说&#xff…

【网络层】路由基础

文章目录 技术背景IP 路由工作原理IP路由表 技术背景 路由是能够让整个Internet持续运转的关键。回看之前的网络历史&#xff0c;最开始用一根网线将两台设备连接起来&#xff0c;面对面就能通信。到后面出现了交换机&#xff0c;能够让区域内的所有设备互相通信&#xff0c;形…

WPF篇(5)- Border控件(边框布局)+GridSplitter分割窗口

严格来说&#xff0c;Border并不是一个布局控件&#xff0c;因为它并不是Panel的子类&#xff0c;而是Decorator装饰器的子类&#xff0c;而Decorator继承于FrameworkElement。我们要先看看它的父类Decorator。 public class Decorator : FrameworkElement, IAddChild {public…

少儿编程 2024年6月scratch四级 电子学会图形化编程等级考试四级真题和答案解析(选择题)

2024年6月scratch编程等级考试四级真题 选择题&#xff08;共10题&#xff0c;每题2分&#xff0c;共20分&#xff09; 1、运行下列程序&#xff0c;输入单词“PLAY”最后角色说 A、LY4AP B、AP4LY C、YA4PL D、PL4AY 答案&#xff1a;B 考点分析&#xff1a;考查积木综合…

英伟达元宇宙平台Omniverse的学习,技术调研

NVIDIA Omniverse™ 是一个基于 USD (Universal Scene Description) 的可扩展平台&#xff0c;可使个人和团队更快地构建自定义 3D 工作流并模拟大型虚拟世界。 Omniverse&#xff1a;三维设计协同、模拟的开发平台&#xff0c;实现3D实时渲染&#xff0c;RTX光线追踪技术 协…

顺序表各种接口的实现(C)

线性表 线性表是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串…线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线。在物理结构上并不一定是连续的&#xff0c;线性表在物…

Qt 小功能:加载等待动画——转圈圈

加载等待动画实现——转圈圈 效果图&#xff1a;&#xff08;看封面最好&#xff09; 关键要点 流畅的动画&#xff1a; 使用 QTimer 每 50 毫秒更新一次动画&#xff0c;确保动画流畅。 视觉效果&#xff1a; 使用 QPainter 的平滑像素转换和抗锯齿选项&#xff0c;提高动画…

DHU OJ 循环结构 回文数字

思路及代码&#xff1a; 由于只考虑5位和6位回文数&#xff0c;3个 for 循环次数为9*10*10还可以&#xff0c;就直接遍历了 //input n int 10< <100 #include<iostream> using namespace std; int main(){int n;cin >> n;int ans 0; //solution //判断是…

HTML 元素提供的附加信息--属性 ——WEB开发系列03

HTML 属性是指用于描述 HTML 元素的额外信息&#xff0c;它们提供了元素的特定配置或行为&#xff0c;属性通常包含在 HTML 元素的开始标签中。 元素也可以拥有属性&#xff0c;属性看起来像这样&#xff1a; 属性是元素的附加信息&#xff0c;它们不会显示在实际内容中。在前述…

适合初学者的2024年数据恢复软件指南

现在大家应该经常会将数据存储在一些存储设备里。但这些设备可能会因为各种原因导致数据意外的丢失&#xff0c;这时候如果我们掌握了全免费的数据恢复工具的使用方式&#xff0c;就可以尽可能的避免数据丢失的情况。 1.福晰数据恢复 连接直达&#xff1a;https://www.pdf365…

跑腿代购app系统源码开发及功能分析

随着互联网技术的飞速发展和人们生活节奏的加快&#xff0c;跑腿代购服务作为一种便捷的生活方式&#xff0c;正逐渐渗透到我们日常生活的方方面面。从日常购物、餐饮外卖到文件传递、药品代购&#xff0c;跑腿服务以其高效、灵活的特点赢得了广大用户的青睐。而支撑这一服务高…

多进程架构关键技术之FileMapping技术应用

1. 前言 在多进程架构设计中&#xff0c;使用FileMapping技术是一种关键的技术选择。它能够显著提升多进程间数据共享和通信的效率&#xff0c;同时简化了复杂的进程间数据交互和同步管理。以下是FileMapping技术在多进程架构设计中的应用及其关键优势&#xff1a; 2. 共享数…

Linux项目自动构建工具 make/makefile

目录 0.前言 1.make/makefile是什么 2.makefile的语法 2.1基本语法 2.2依赖关系 2.3. 示例&#xff1a;一个简单的C程序 3.使用指令自动构建与清除 3.1自动构建 3.2自动清除 3.3自动化工作流 3.4扩展&#xff1a;更多伪目标 4.make的工作原理 5.使用make/makefile的优势 6.小结…

高质量WordPress下载站模板5play主题源码

5play下载站是由国外站长开发的一款WordPress主题&#xff0c;主题简约大方&#xff0c;为v1.8版本&#xff0c; 该主题模板中包含了上千个应用&#xff0c;登录后台以后只需要简单的三个步骤就可以轻松发布apk文章&#xff0c; 我们只需要在WordPress后台中导入该主题就可以…

Spring配置

1.Spring的两大核心思想IOC和AOP思想 1.1类注解 1.Controller, Service, Configuration, Component, Repository 1.2方法注解 bean&#xff08;这个方法搭配上面的五大注解进行使用&#xff09; 2.Bean的名称 2.1.类注解名称 &#xff08;1&#xff09;默认首字母小写驼…