【新手入门必看】从零开始学指针

我使用VS CODE+MSYS2的编译环境进行学习,想使用VS CODE进行C/C++代码编写的小伙伴参考这篇文章进行环境配置VS Code 配置 C/C++ 编程运行环境(保姆级教程)

一、指针的引入

指针==地址

#include <stdio.h>int main() {int a = 10;printf("The value of a is: %d\n", a);printf("The address of a is: %p\n", &a);printf("The value of a is: %d\n", *(&a));//取值运算符,把后面内存地址内的数据“取出来”return 0;
}

变量:int a=10;  (四要素:类型int、变量名a、内存地址、值10)

变量访问的两种方式:
1、通过变量名访问:

printf("The value of a is: %d\n", a);

2、通过地址访问:

&取地址运算符   *将地址内的值读出运算符printf("The value of a is: %d\n", *(&a));

二、指针变量的引入

指针变量==存放地址的变量

#include <stdio.h>int main() {//什么是整型变量,存放整型数的变量//什么是字符型变量,存放字符型数据的变量//什么是指针变量,存放指针的变量//指针==地址:指针变量就是存放地址的变量int a = 10;int *p;//这里*是一个标识符,告诉系统我是一个指针变量,用来保存别人的地址,和14行运算符不同p=&a;//p=a的地址printf("The value of a is: %d\n", a);printf("The address of a is: %p\n", &a);printf("The value of a is: %d\n", *(&a));//取值运算符,把后面内存地址内的数据“取出来”printf("pointer-The value of a is: %d\n", *p);return 0;
}

如何定义一个指针变量—— * 的标识作用——只用于指针变量定义或者声明的时候

如何使用一个指针变量—— * 的运算作用——把地址内的数据取出

#include <stdio.h>int main() {int a = 0x1234;int *i = &a;char *c = &a;printf("*i:a=%x\n", *i);printf("*c:a=%x\n", *c);printf("*i:addr=%p\n", i);printf("*c:addr=%p\n", c);printf("++i=%p\n", ++i);printf("++c=%p\n", ++c);
}

int类型占用4个字节(byte),一个字节占用8位(bit)————32bit

char类型占用1个字节,一个字节占用8位————8bit

三、为什么要使用指针

1、场景一之变量值交换

#include <stdio.h>int main(){int a=10;int b=20;int temp;	printf("before:");printf("a=%d\t",a);printf("b=%d\n",b);temp=a;a=b;b=temp;printf("after:");printf("a=%d\t",a);printf("b=%d\n",b);return 0;
}

当我们想把main函数里面的值交换封装到函数里面却发现交换后的a和b的值并没有改变

#include <stdio.h>void changeData(int a,int b){int temp;temp=a;a=b;b=temp;
}int main(){int a=10;int b=20;printf("before:");printf("a=%d\t",a);printf("b=%d\n",b);changeData(a,b);printf("after:");printf("a=%d\t",a);printf("b=%d\n",b);return 0;
}

 

原因是应为数据发生交换的内存空间和main函数里变量的内存空间不在同一内存空间 ,解决办法将changeData函数的参数变为指针,调用changeData函数时将变量a和b的地址传入

#include <stdio.h>void changeData(int *a,int *b){int temp;temp=*a;*a=*b;*b=temp;
}int main(){int a=10;int b=20;printf("before:");printf("a=%d\t",a);printf("b=%d\n",b);changeData(&a,&b);printf("after:");printf("a=%d\t",a);printf("b=%d\n",b);return 0;
}

2、场景二之指针指向固定的内存地址

#include <stdio.h>int main(){unsigned int *p=(unsigned int *)0x0019FF11;printf("p = 0x%p\n",p);return 0;
}

四、通过指针引用数组

1、定义一个指针变量指向数组

在C语言中,数组名(不包括形参的数组名,形参数组并不占用实际的内存单元)和数组中的首元素都可以代表数组的首地址

2、指针偏移遍历数组

我们之前访问数组元素用的都是下标法printf("arr[0]=%d\n",arr[0]); 系统在使用数组下标对数组成员进行访问时开销比较大,指针的访问效率远远大于数组名的访问效率但普通工程代码量小影响微乎其微。

在数组中所有元素的地址是连续的,第一个元素是a,那么第二个就是a+1,第三个就是a+2......但这个1并不是数组一而是字节数,比如int类型的数组第二个元素就比第一个元素的地址多了四个字节(32位)参考本文 二、指针变量的引入理解

每次重新编译运行后数组的首地址都会改变,因为局部数组是放在栈区的,由编译器自动进行分配和释放

#include <stdio.h>int main(){int arr[3]={1,2,3};printf("arr address:%p\n",arr);printf("arr[0] address:%p\n",&arr[0]);int *p,*q;p=arr;q=&arr[0];printf("a[0]=%d\t",*(p));//指针变量p存放了数组的首地址,通过取值符号*将地址内的值取出printf("a[0] address:%p\n",p);printf("a[1]=%d\t",*(p+1));printf("a[1] address:%p\n",p+1);printf("a[2]=%d\t",*(p+2));printf("a[2] address:%p\n",p+2);printf("a[0]=%d\t",*(q));    printf("a[1]=%d\t",*(q+1));   printf("a[2]=%d",*(q+2));   return 0;
}

通过for循环遍历可节省代码量

#include <stdio.h>int main(){int arr[3]={1,2,3};int len=sizeof(arr)/sizeof(int);//或者int len=sizeof(arr)/sizeof(arr[0])printf("arr address:%p\n",arr);printf("arr[0] address:%p\n",&arr[0]);for(int i=0;i<len;i++){printf("arr[%d]=%d\t",i,arr[i]);}printf("\n\n");int *p,*q;p=arr;q=&arr[0];for(int i=0;i<len;i++){printf("arr[%d]=%d\t",i,*(p+i));printf("address=%p\n",p+i);}printf("\n");for(int i=0;i<len;i++){printf("arr[%d]=%d\t",i,*(q+i));printf("address=%p\n",q+i);}return 0;
}

3、指针当做数组名来用

4、指针常量和指针变量的区别

int *p是指针变量,它所保存的地址是可变的

数组名arr是指针常量,它的地址是确定的

#include <stdio.h>int main(){int arr[3]={1,2,3};int *p=arr;for(int i=0;i<3;i++){printf("%d ",*p++);}
/*for(int i=0;i<3;i++){printf("%d ",*arr++);//编译不通过,指针常量}
*/for(int i=0;i<3;i++){printf("%d ",*(arr+i));}printf("\n\n");return 0;
}

 5、sizeof计算大小的区别

在32位操作系统中指针占4字节,64位操作系统中指针占8字节

6、小练习

(1)通过指针的方式实现数组的初始化和遍历

#include <stdio.h>void initArray(int *p,int len);
void printArray(int *p,int len);int main(){int arr[3];int len=sizeof(arr)/sizeof(int);initArray(arr,len);printArray(arr,len);return 0;
}void initArray(int *p,int len){for(int i=0;i<len;i++){printf("please enter %d number:",i+1);scanf("%d\n",p++);}
}void printArray(int *p,int len){for(int i=0;i<len;i++){printf("arr[%d]=%d\t",i,*(p+i));//printf("arr[%d]=%d\t",i,*p++)}
}

(2)实现数组翻转

#include <stdio.h>void Array1(int *p,int len);
void Array2(int *p,int len);
void printArray(int *p,int len);int main(){int arr1[5]={5,4,3,2,1};int arr2[6]={6,5,4,3,2,1};int len1=sizeof(arr1)/sizeof(int);int len2=sizeof(arr2)/sizeof(int);printf("before:\n");printArray(arr1,len1);printf("\n");printArray(arr2,len2);printf("\nafter:\n");Array1(arr1,len1);printArray(arr1,len1);printf("\n");Array2(arr2,len2);printArray(arr2,len2);return 0;
}void Array1(int *p,int len){int temp;for(int i=0;i<(len/2);i++){//前2个数,中间那个数不变for(int j=len-i-1;j<=len-i-1;j++){//后2个数/*形式1*/temp=p[i];p[i]=p[j];p[j]=temp;/*形式2*/// temp=*(p+i);// *(p+i)=*(p+j);// *(p+j)=temp;    }}
}void Array2(int *p,int len){int temp;for(int i=0;i<=(len/2);i++){//前3个数for(int j=len-i-1;j<=(len-i-1);j++){//后3个数/*形式1*/// temp=p[i];// p[i]=p[j];// p[j]=temp;    /*形式2*/temp=*(p+i);*(p+i)=*(p+j);*(p+j)=temp;    }}
}void printArray(int *p,int len){for(int i=0;i<len;i++){printf("arr[%d]=%d\t",i,*(p+i));//printf("arr[%d]=%d\t",i,*p++)}
}

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

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

相关文章

Git的操作和使用

一、基本操作 1、创建git本地仓库 &#xff08;1&#xff09;创建目录&#xff1a;mkdir gitcode &#xff08;2&#xff09;进入目录&#xff1a;cd gitcode/ &#xff08;3&#xff09;查询目录内容&#xff1a;ls &#xff08;4&#xff09;在当前目录下创建git本地仓库…

java算法day3

移除链表元素设计链表翻转链表两两交换链表中的结点 移除链表元素 ps&#xff1a;有时候感觉到底要不要写特判&#xff0c;你想到了就写&#xff01;因为一般特判有一劳永逸的作用。 解法有两种&#xff0c;一种是不用虚拟头结点&#xff0c;另一种就是用虚拟头结点。 这里我…

React-基础语法学习

1、教程&#xff1a;井字棋游戏 本教程将引导你逐步实现一个简单的井字棋游戏&#xff0c;并且不需要你对 React 有任何了解。在此过程中你会学习到一些编写 React 程序的基本知识&#xff0c;完全理解它们可以让你对 React 有比较深入的理解。 1.1、教程分成以下几个部分&am…

3D感知生成对抗网络的高斯溅射解码器

Gaussian Splatting Decoder for 3D-aware Generative Adversarial Networks 3D感知生成对抗网络的高斯溅射解码器 Florian Barthel1, 2  Arian Beckmann1  Wieland Morgenstern1  Anna Hilsmann1  Peter Eisert1,2 Florian Barthel 1, 2 阿里安贝克曼Wieland晨星Anna Hils…

【Godot4自学手册】第三十九节利用shader(着色器)给游戏添加一层雾气效果

今天&#xff0c;主要是利用shader给游戏给地宫场景添加一层雾气效果&#xff0c;增加一下气氛&#xff0c;先看一下效果&#xff1a; 一、新建ParallaxBackground根节点 新建场景&#xff0c;根节点选择ParallaxBackground&#xff0c;命名为Fog&#xff0c;然后将该场景保…

不要小看在线文档编辑工具,它才是提高工作效率的法宝

在数字化的今天&#xff0c;工作方式正变得越来越灵活&#xff0c;远程办公和团队协作已成日常。这个时候&#xff0c;传统的文档处理方式已经无法满足快速发展的业务需求。在线文档编辑工具&#xff0c;正逐渐成为提高团队工作效率的秘密武器。它能够让团队成员无论身处何地&a…

从预训练损失的角度,理解语言模型的涌现能力

原文&#xff1a;Understanding Emergent Abilities of Language Models from the Loss Perspective 摘要 本文从预训练损失的角度重新审视语言模型的涌现能力&#xff0c;挑战了以往以模型大小或训练计算量为标准的观念。通过实验&#xff0c;作者发现预训练损失是预测下游任…

【剪映专业版】15绿幕抠图:应用技巧、注意事项

视频课程&#xff1a;B站有知公开课【剪映电脑版教程】 1.绿幕抠图 背景为绿色的素材&#xff08;其他颜色也可以扣取&#xff0c;只是绿色背景更普遍、抠图效果更好&#xff09; 选择色度抠图&#xff0c;通过取色器选取背景颜色&#xff0c;调整强度实现抠图 剪映的色度抠…

“我舍不得”用英语怎么说?柯桥日常英语口语培训

“我舍不得”用英语怎么说&#xff1f; “舍不得”的英文表达是&#xff1a;Cant bear to 不忍心&#xff0c;不舍得 例句&#xff1a; Time flies. I cant bear to leave you. 时间过的好快啊&#xff0c;我真舍不得离开你。 I cant bear to see you cry. 我真舍不得你…

《QT实用小工具·三十四》Qt/QML使用WebEngine展示的百度ECharts图表Demo

1、概述 源码放在文章末尾 该项目实现了百度ECharts图表的样式&#xff0c;效果demo如下所示&#xff1a; 项目部分代码如下所示&#xff1a; #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QtWebEngine>int main(int argc, ch…

小成本搏大流量:微信/支付宝小程序搜索排名优化

随着移动互联网的快速发展&#xff0c;小程序已成为企业和个人开发者重要的流量入口和业务承载平台。而小程序搜索排名则是影响小程序曝光量、用户获取及业务转化的关键因素。小柚在本文和大家探讨如何制定有效的优化方案&#xff0c;提升小程序在搜索结果中的排名。 首先跟我…

基于docker的Jenkin的服务平台搭建

项目拓扑图 项目环境: jenkins-2.440 sonarqube-9.9.4 apache-maven-3.9.6 gitlab-ce-12.4.2 java17 docker20 harbor.v2.6.0 centos7.9 项目目的: 模拟企业构建一个流行的持续集成和持续部署环境,可以更轻松地创建和管理构建环境&#xff0c;实现自动化构建和部署应用程序的…

Ubuntu 微调训练ChatGLM3大语言模型

Ubuntu 微调训练ChatGLM3大语言模型 LLaMA Factory 的 LoRA 微调提供了 3.7 倍的加速比&#xff0c;同时在广告文案生成任务上取得了更高的 Rouge 分数。结合 4 比特量化技术&#xff0c;LLaMA Factory 的 QLoRA 微调进一步降低了 GPU 显存消耗。 https://github.com/hiyouga…

累加(C语言)

一、题目&#xff1b; 二、N-S流程图&#xff1b; 三、运行结果&#xff1b; 四、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int i 0;int j 0;int n 5;int result 0;int sum 0;//运算&#…

牛客-小乐乐与欧几里得

目录 题目 描述 输入描述&#xff1a; 输出描述&#xff1a; 示例1 示例2 解题 题目 描述 小乐乐最近在课上学习了如何求两个正整数的最大公约数与最小公倍数&#xff0c;但是他竟然不会求两个正整数的最大公约数与最小公倍数之和&#xff0c;请你帮助他解决这个问题。 …

进程控制第二弹(进程程序替换)

文章目录 代码现象基本原理多进程版本实例基本原理 使用所有的替换方法&#xff0c;并且认识函数的参数含义execlexecvexeclp、execvpexecvpe 总结 代码现象 #include<stdio.h> #include<unistd.h> int main() { printf("testexec begin! ...\…

数据安全全面防护

what 通过采用各种有效技术和管理措施来保护网络系统的正常运行&#xff0c;从而保证数据的可用性&#xff0c;机密性&#xff0c;完整性。 ---网络安全防护体系建设三同步--规划 建设 运行 数据安全的三大基本特征 可用性 数据在需要时可用且可访问&#xff0c;为实现可用…

算法课程笔记——STL键值对map

map当下标无限的数组 重点是对应关系&#xff0c;一般不修改compare 类比set 没有lowerbound&#xff0c;因为遍历是无序的 ; map不能用sort函数排序 但可用vector转化为map使用 std::set<std::pair<TKEY, mutable TVAL> > ≈ std::map<TKEY, TVAL>

【剪映专业版】13快速为视频配好音:清晰、无噪声、对齐

视频课程&#xff1a;B站有知公开课【剪映电脑版教程】 使用场景&#xff1a;视频无声音或者视频有声音但是需要更改声音 时间指示器在哪里&#xff0c;就从哪里开始 红色按钮&#xff1a;开始录音 声音波纹&#xff1a;蓝色最佳&#xff0c;黄色或红色声音太大&#xff0c;…

Unity UGUI透明区域点击无效

是这样的&#xff0c;我有一张图&#xff0c;客户给的是1920*1080&#xff0c;但只有中间部分是按钮&#xff0c;是有效像素。为了让空白区域点击无效。需要设置如下 并且加上下面这句 this.GetComponent<Image>().alphaHitTestMinimumThreshold 0.1f;