C语言-指针的基本知识(下)

news2024/11/17 23:39:05

四、指针的分类 

按指针指向的数据的类型来分

1:字符指针

字符型数据的地址

char *p;//定义了一个字符指针变量,只能存放字符型数据的地址编号

char ch;

p= &ch;

2:短整型指针

short int *p;//定义了一个短整型的指针变量p,只能存放短整型变量的地址

short int a;

p =&a;

3:整型指针

int *p;//定义了一个整型的指针变量p,只能存放整型变量的地址

int a;

p =&a;

注:多字节变量,占多个存储单元,每个存储单元都有地址编号, c语言规定,存储单元编号最小的那个编号,是多字节变量的地址编号。

4:长整型指针

long int *p;//定义了一个长整型的指针变量p,只能存放长整型变量的地址

long int a;

p =&a;

5:float 型的指针

float *p;//定义了一个float型的指针变量p,只能存放float型变量的地址

float a;

p =&a;

6:double型的指针

double *p;//定义了一个double型的指针变量p,只能存放double型变量的地址

double a;

p =&a;

7:函数指针

8、结构体指针

9、指针的指针

10、数组指针

总结:无论什么类型的指针变量,在32位系统下,都是4个字节,只能存放对应类型的变量的地址编号。

五、指针和变量的关系

指针可以存放变量的地址编号

在程序中,引用变量的方法

1:直接通过变量的名称

int a;

a=100;

2:可以通过指针变量来引用变量

int *p;//在定义的时候,*不是取值的意思,而是修饰的意思,修饰p是个指针变量

p=&a;//取a的地址给p赋值,p保存了a的地址,也可以说p指向了a

*p= 100;//在调用的时候*是取值的意思,*指针变量 等价于指针指向的变量

注:指针变量在定义的时候可以初始化

int a;

int *p=&a;//用a的地址,给p赋值,因为p是指针变量

指针就是用来存放变量的地址的。

*+指针变量 就相当于指针指向的变量

指针变量只能保存开辟好空间的地址,不能随意保存地址

1 #include <stdio.h>

2

3 int main(int argc, char *argv[])

4 {

5 int *p1,*p2,temp,a,b;

6 p1=&a;7 p2=&b;

8

9 printf("请输入:a b的值:\n");

10 scanf("%d %d", p1, p2);//p1p2指向的变量赋值

11

12 temp = *p1; //p1指向的变量(a)给temp赋值

13 *p1 = *p2; //p2指向的变量(b)给p1指向的变量(a)赋值

14 *p2 = temp;//tempp2指向的变量(b)赋值

15

16 printf("a=%d b=%d\n",a,b);

17 printf("*p1=%d *p2=%d\n",*p1,*p2);

18

19 return 0;

20 }

扩展:

对应类型的指针,只能保存对应类型数据的地址,

如果想让不同类型的指针相互赋值的时候,需要强制类型转换

1 #include <stdio.h>

2

3 int main(int argc, char *argv[])

4 {

5 int a=0x1234,b=0x5678;

6 char *p1,*p2;

7 printf("%#x %#x\n",a,b);

8 p1=(char *)&a;

9 p2=(char *)&b;

10 printf("%#x %#x\n",*p1,*p2);

11 p1++;

12 p2++;

13 printf("%#x %#x\n",*p1,*p2);

14

15 return 0;

16 }

注意:

1:*+指针 取值,取几个字节,由指针类型决定的指针为字符指针则取一个字节,

指针为整型指针则取4个字节,指针为double型指针则取8个字节。

2:指针++ 指向下个对应类型的数据

字符指针++ ,指向下个字符数据,指针存放的地址编号加1

整型指针++,指向下个整型数据,指针存放的地址编号加4

6.1 数组元素与指针的基本关系

变量存放在内存中,有地址编号,咱们定义的数组,是多个相同类型的变量的集合,每个变量都占内存空间,都有地址编号。指针变量当然可以存放数组元素的地址。

1 int a[10];

2 //int *p =&a[0];

3 int *p;

4 p=&a[0]; //指针变量p保存了数组a中第0个元素的地址,即a[0]的地址

6.2 数组元素的引用方法

方法1: 数组名[下标]

int a[10];

a[2]=100;

方法2:指针名加下标

int a[10];

int *p;

p=a;

p[2]=100;//因为p和a等价

补充:c语言规定:数组的名字就是数组的首地址,即第0个元素的地址,是个常量。

注意:p和a的不同,p是指针变量,而a是个常量。所以可以用等号给p赋值,但不能给a赋值。

例如:int a[10]; a++就是错误的,因为a是数组名是一个地址常量

方法3:通过指针运算加取值的方法来引用数组的元素

int a[10];

int *p;

p=a;

*(p+2)=100;//也是可以的,相当于a[2]=100

解释:p是第0个元素的地址,p+2是 a[2]这个元素的地址。

对第二个元素的地址取值,即a[2]

1 #include <stdio.h>

2

3 int main(int argc, char *argv[])

4 {

5 int a[5]={0,1,2,3,4};

6 int *p;

7 p=a;

8

9 //只要将数组名赋值给同类型的指针变量,则此时的指针变量与数组名可

10 //以用相同的方法操作数组

11 printf("a[2]=%d\n",a[2]);

12 printf("p[2]=%d\n",p[2]);

13

14 //*(a + n) <==> *(p + n) <==> a[n] <==> p[n]

15 printf("*(p+2) = %d\n",*(p+2));

16 printf("*(a+2) = %d\n",*(a+2));

17

18 printf("p=%p\n",p);

19 printf("p+2=%p\n",p+2);

20 printf("&a[0] = %p\n", &a[0]);

21 printf("&a[2] = %p\n", &a[2]);

22 return 0;

23 }

七、指针的运算

7.1 指针可以加一个整数

往下指几个它指向的变量,结果还是个地址

前提:指针指向数组的时候,加一个整数才有意义

1 //指针可以加一个整数,往下指几个它指向的变量,结果还是个地址

2 void test1()

3 {

4 int a[10];

5 int *p, *q;

6 //pq间隔8个字节,意味着加一个整数最终移动的字节数与指针变量的类型也有关系

7 p = a;

8 q = p + 2;

9

10 printf("p = %p\n", p);

11 printf("q = %p\n", q);

12

13 return ;

14 }

7.2 两个相同类型指针可以比较大小

前提:只有两个相同类型的指针指向同一个数组的元素的时候,比较大小才有意义

指向前面元素的指针 小于 指向后面 元素的指针

1 void test2()

2 {

3 int a[10];

4 int *p,*q;

5 p=&a[1];

6 q=&a[6];

7 if(p<q)

8 {

9 printf("p < q\n");

10 }

11 else if(p>q)

12 {

13 printf("p > q\n");

14 }

15 else

16 {

17 printf("p = q\n");

18 }

19 }

7.3 两个相同类型的指针可以做减法

前提:必须是两个相同类型的指针指向同一个数组的元素的时候,做减法才有意义

做减法的结果是,两个指针指向的中间有多少个元素

1 void test3()

2 {

3 int a[10];

4 int *p,*q;

5 p=&a[0];

6 q=&a[3];

7 printf("%d\n",qp);

8 }

7.4 两个相同类型的指针可以相互赋值

注意:只有相同类型的指针才可以相互赋值(void *类型的除外)

1 void test4()

2 {

3 int a = 100;

4 int *p, *q;

5 p = &a;

6

7 printf("a = %d %d\n", a, *p);

8

9 q = p;

10 printf("*q = %d\n", *q);

11

12 *q = 999;

13 printf("a = %d\n", a);

14 }

八、指针数组

1、指针和数组的关系

1:指针可以保存数组元素的地址

2:可以定义一个数组,数组中有若干个相同类型指针变量,这个数组被称为指针数组

指针数组的概念:

指针数组本身是个数组,是个指针数组,是若干个相同类型的指针变量构成的集合

注意:一般遇到这样的叠词,本质就是后者

2、指针数组的定义方法:

类型说明符 * 数组名 [元素个数];

1 int * p[10];//定义了一个整型的指针数组p,有10个元素p[0]~p[9],每个元素都是int

*类型的变量

2 int a;

3 p[1]=&a;

4 int b[10];

5 p[2]=&b[3];

6 p[2]*(p+2)是等价的,都是指针数组中的第2个元素。

3、指针数组的分类

字符指针数组char *p[10]、短整型指针数组、整型的指针数组、长整型的指针数组

float型的指针数组、double型的指针数组

结构体指针数组、函数指针数组

1 #include <stdio.h>

2

3 int main(int argc, char *argv[])

4 {

5 //大多数情况下,指针数组都用来保存多个字符串

6 char *name[5] = {"Follw me","BASIC","Greatwall","FORTRAN","Computer"};

7 int i;

8 for(i=0;i<5;i++)

9 {

10 printf("%s\n",name[i]);

11 }

12

13 return 0;

14 }

15

九、指针的指针 -- 二级指针

指针的指针,即指针的地址,咱们定义一个指针变量本身指针变量占4个字节,指针变量也有地址编号。

int a;

int *p;

p=&a;

*p === a

int **q;

q=&p;

*q === p

**q === *p === a

int ***m;

m=&q;

*(*(*m)) === a

注意:

p q m都是指针变量,都占4个字节,都存放地址编号,只不过类型不一样而已

1 #include <stdio.h>

2

3 int main(int argc, char *argv[])

4 {

5 int a = 100;

6

7 //定义一个一级指针

8 //一级指针用于保存普通变量的地址

9 int *p = &a;

10

11 //定义一个二级指针12 //二级指针用于保存一级指针的地址

13 int **q = &p;

14

15 printf("a = %d %d %d\n", a, *p, **q);

16 printf("&a = %p %p %p\n", &a, p, *q);

17 printf("&p = %p %p\n", &p, q);

18 printf("&q = %p\n", &q);

19

20 return 0;

十、字符串和指针

字符串的概念:

字符串就是以’\0’结尾的若干的字符的集合

字符串的存储形式: 数组、字符串指针、堆

1、 char string[100] = “I love C!”

定义了一个字符数组string,用来存放多个字符,并且用”I love C!”给string数组初始化字符串“I love C!”存放在string中

2、 char *str = “I love C!”

定义了一个指针变量str,只能存放字符地址编号,

所以说I love C! 这个字符串中的字符不能存放在str指针变量中。

str只是存放了字符I的地址编号,“I love C!”存放在文字常量区

3、 char *str =(char*)malloc(10*sizeof(char));

动态申请了10个字节的存储空间,首地址给str赋值。

strcpy(str,"I love C");//将字符串“Ilove C!”拷贝到str指向的内存里

总结:

字符数组:

在内存(栈、静态全局区)中开辟了一段空间存放字符串

字符串指针:

在文字常量区开辟了一段空间存放字符串,将字符串的首地址付给str

堆:

使用malloc函数在堆区申请空间,将字符串拷贝到堆区

注意:

可修改性:

1. 栈和全局区内存中的内容是可修改的

char str[100]=”I love C!”;

str[0]=‘y’;//正确可以修改的

2. 文字常量区里的内容是不可修改的

char *str=”I love C!”;

*str =’y’;//错误,I存放在文字常量区,不可修改

3. 堆区的内容是可以修改的

char *str =(char*)malloc(10*sizeof(char));

strcpy(str,"I love C");

*str=’y’;//正确,可以,因为堆区内容是可修改的

注意:str指针指向的内存能不能被修改,要看str指向哪里。

str指向文字常量区的时候,内存里的内容不可修改

str指向栈、堆、静态全局区的时候,内存的内容是可以修改

初始化:

字符数组、指针指向的字符串:定义时直接初始化

char buf_aver[]="hello world";

char *buf_point="hello world";

堆中存放的字符串不能初始化、只能使用strcpy、scanf赋值

char *buf_heap;

buf_heap=(char *)malloc(15);

strcpy(buf_heap,"hello world");

scanf(“%s”,buf_heap);

使用时赋值

字符数组:使用scanf或者strcpy

char buf_aver[128];

buf_aver="hello kitty"; 错误,因为字符数组的名字是个常量

strcpy(buf_aver,"hello kitty"); 正确

scanf("%s",buf_aver); 正确

指向字符串的指针:

char *buf_point;

buf_point="hello kitty"; 正确,buf_point指向另一个字符串

strcpy(buf_point,"hello kitty"); 错误,只读,能不能复制字符串到buf_piont指向

的内存里

取决于buf_point指向哪里。

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

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

相关文章

unity微信小游戏——排行榜

1.微信公众平台配置排行榜 设置时记住排行榜唯一标识 2.微信公众平台配置获取微信好友信息权限 同登录篇第一步Unity微信小游戏——登录 获取用户头像名称-CSDN博客 3.Unity搭建排行榜UI 此处建议使用官方案例的UI进行修改 minigame-unity-webgl-transform: Unity WebGL 微…

[足式机器人]Part3 机构运动学与动力学分析与建模 Ch01-2 完整定常系统——杆组RRR

本文仅供学习使用,总结很多本现有讲述运动学或动力学书籍后的总结,从矢量的角度进行分析,方法比较传统,但更易理解,并且现有的看似抽象方法,两者本质上并无不同。 2024年底本人学位论文发表后方可摘抄 若有帮助请引用 本文参考: 《空间机构的分析与综合(上册)》-张启先…

基于springboot+微信小程序+vue实现的校园二手商城项目源码

介绍 校园二手商城&#xff0c;架构&#xff1a;springboot微信小程序vue 软件架构 软件架构说明 系统截图 技术选型 技术版本说明Spring Boot2.1.6MVC核心框架Spring Security oauth22.1.5认证和授权框架MyBatis3.5.0ORM框架MyBatisPlus3.1.0基于mybatis&#xff0c;使用…

JavaScript的冒泡与捕获

1.概念。 冒泡事件&#xff1a;微软公司提出的&#xff0c;事件由子元素传递到父元素的过程叫做冒泡&#xff08;false&#xff09;。 捕获事件&#xff1a;网景公司提出的&#xff0c;事件由父元素传递到子元素的过程叫做事件捕获&#xff08;ture&#xff09;。 2.冒泡事件与…

【每日一题】5.LeetCode——环形链表

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有限&#xff0c;欢迎各位大佬指点&…

Qt6入门教程 13:QPushButton

目录 一.QPushButton 1.多选 2.互斥 3.设置菜单 4.图标按钮 4.1给按钮添加图标 4.2异形按钮 二.设置Qt样式表 一.QPushButton QPushButton是与QAbstractButton最接近的完全体按钮&#xff0c;它具备QAbstractButton的所有特性&#xff0c;并且支持设置菜单。 1.多选 …

pytest 8.0 重磅发布!2条弃用规则,7项重大变更,多项优化改进

&#xff08;全文约3200字&#xff0c;阅读约需7分钟&#xff0c;建议先收藏后阅读。首发于公众号&#xff1a;测试开发研习社&#xff0c;欢迎关注&#xff09; pytest 版本遵循 ( <major>.<minor>.<patch>) 语义控制。 昨天发布的 pytest 8.0 是全新的 maj…

使用WAF防御网络上的隐蔽威胁之反序列化攻击

什么是反序列化 反序列化是将数据结构或对象状态从某种格式转换回对象的过程。这种格式通常是二进制流或者字符串&#xff08;如JSON、XML&#xff09;&#xff0c;它是对象序列化&#xff08;即对象转换为可存储或可传输格式&#xff09;的逆过程。 反序列化的安全风险 反序…

外汇天眼:国外汇民遭遇黑平台TO FOREX,损失惨重!

大家都知道&#xff0c;判断外汇平台是否靠谱&#xff0c;并不单单只依靠交易收益情况&#xff0c;而是需要从多方面的情况进行总结&#xff0c;特别是在外汇交易前&#xff0c;就要对外汇平台进行检验&#xff0c;比如检验平台是否有正规监管牌照、口碑评价、资质、创建时间以…

C语言第十二弹--扫雷

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 扫雷 1、扫雷游戏分析和设计 1.1、扫雷游戏的功能说明 1.2 游戏的分析和设计 1.2.1、数据结构的分析 1.2.2、文件结构设计 2、扫雷游戏的结构分析 2.1、用…

静态分析Golang语言生成函数调用关系的利器——go-callvis

目录 升级go删除旧版本安装新版本配置环境变量载入环境修改当前环境修改之后进入的环境 分析安装go-callvis分析其他包总结 导出文件总结 清晰主体脉络总结 其他 参考资料 不同于之前分析C语言项目的工具&#xff0c;go-callvis还是很方便使用。只要把两项工作做好就能顺利的使…

Android 基础技术——Bitmap

笔者希望做一个系列&#xff0c;整理 Android 基础技术&#xff0c;本章是关于 Bitmap Bitmap 内存如何计算 占用内存 宽 * 缩放比例 * 高 * 缩放比例 * 每个像素所占字节 缩放比例 设备dpi/图片所在目录的dpi Bitmap加载优化&#xff1f;不改变图片质量的情况下怎么优化&am…

HX711压力传感器学习一(STM32)

目录 原理图&#xff1a;​ 引脚介绍&#xff1a; HX711介绍工作原理: 程序讲解&#xff1a; 整套工程&#xff1a; 发送的代码工程&#xff0c;与博客的不一致&#xff0c;如果编译有报错请按照报错和博客进行修改 原理图&#xff1a; 引脚介绍&#xff1a; VCC和GND引…

Leetcode刷题笔记题解(C++):1117. H2O 生成(多线程)

思路&#xff1a; 解法二&#xff1a;生产者-消费者解法 1.把 hydrogen 线程看作生产者&#xff0c;oxygen 线程看作消费者&#xff0c;缓冲队列大小为2。 2.hydrogen 把生成的氢放入队列&#xff1b;oxygen 线程每次从队列里消费两个氢元素。 3.生产者生产两个氢元素后会因为…

openGauss学习笔记-209 openGauss 数据库运维-常见故障定位案例-共享内存泄露问题

文章目录 openGauss学习笔记-209 openGauss 数据库运维-常见故障定位案例-共享内存泄露问题209.1 共享内存泄露问题209.1.1 问题现象209.1.2 原因分析209.1.3 处理方法 openGauss学习笔记-209 openGauss 数据库运维-常见故障定位案例-共享内存泄露问题 209.1 共享内存泄露问题…

精通Python第20篇—数据之美:用Pyecharts打造引人入胜的多维度仪表盘与图表联动

引言 在数据可视化领域&#xff0c;仪表盘图是一种直观而强大的工具&#xff0c;用于展示关键指标的实时状态。Pyecharts是一个基于Echarts的Python图表库&#xff0c;提供了丰富的图表类型&#xff0c;其中包括了仪表盘图。本文将介绍如何使用Pyecharts绘制多种炫酷的仪表盘图…

05.领域驱动设计:认识领域事件,解耦微服务的关键

目录 1、概述 2、领域事件 2.1 如何识别领域事件 1.微服务内的领域事件 2.微服务之间的领域事件 3、领域事件总体架构 3.1 事件构建和发布 3.2 事件数据持久化 3.3 事件总线 (EventBus) 3.4 消息中间件 3.5 事件接收和处理 4、案例 5、总结 1、概述 在事件风暴&a…

SpringBoot内置工具类

Collections java.util包下的Collections类&#xff0c;该类主要用于操作集合或者返回集合 一、排序 List<Integer> list new ArrayList<>();list.add(2);list.add(1);list.add(3);Collections.sort(list);//升序System.out.println(list);Collections.reverse(…

vue实践:构建高效的电子签名功能

前言 在现代数字化时代&#xff0c;电子签名成为了一种方便、高效且安全的签署文件的方式。本文将介绍电子签名的原理和实现方法&#xff0c;帮助你快速掌握这一重要的工具。 电子签名是什么&#xff1f; 电子签名是一种数字化的签名方式&#xff0c;用于验证和确认电子文档、…

GitLab16.8配置webhooks、Jenkins2.4配置GitLab插件实现持续集成、配置宝塔面板实现持续部署(其三)

看本篇文章的前提是已经部署完GItlab和Jenkins服务器&#xff0c;已经可以手动构建成功&#xff0c;并且经过了很多次实践&#xff0c;对这两款软件基本熟悉。 建议大家按以下顺序看 前端自动化&#xff08;其一&#xff09;部署gitlab 前端自动化&#xff08;其二&#xff0…