07:指针

指针

  • 1、什么是指针
    • 1.1、地址的定义
    • 1.2、指针的作用
  • 2、指针的分类
    • 2.1、基本类型指针
    • 2.2、指针和数组
      • 2.2.1、指针和一维数组
        • 2.2.1.1、一维数组名
        • 2.2.1.2、下标和指针的关系
        • 2.2.1.3、确定一维数组需要几个参数
        • 2.2.1.4、指针变量的运算
        • 2.2.1.5、指针变量占用几个字节
      • 2.2.2、动态内存分配
    • 2.3、多级指针
  • 3、跨函数使用内存

1、什么是指针

…指针简单来说就是地址(内存单元的编号)
例如:

#include <stdio.h>int main(void)
{int i = 3;int * p;//定义指针变量p,p只能存放整型变量的地址。p = &i;printf("%d\n",*p);return 0;
}

3

1、int * p表示定义一个指针变量p,类型为int *代表存放整型变量的地址,p用来存放整型变量的地址。
2、p = &i表示把i的地址存放在p变量里面,则p指向i。这就是指针。
3、当p指向i时,则*p代表取值,指取出p指向的地址的变量i的值(所有出现*p的地方都可以用i替换)。

1.1、地址的定义

什么是地址?
    内存单元的编号,从0开始的非负整数。
在这里插入图片描述

范围:
一个地址单元就是一个字节(8位二进制)下面是32位的
在这里插入图片描述则一共有2^32个字节。
1kB = 2^10B(字节)
1MB = 2^10KB
1GB = 2^10MB
所以1GB = 2^30B(字节)
2^32B = 4GB

1.2、指针的作用

(1)表示一些复杂的数据结构快速的传递数据
(2)使函数返回一个以上的值能直接访问硬件
(3)能够方便的处理字符串
(4)是理解面向对象语言中引用的基础
  总结:指针是C语言的灵魂

2、指针的分类

2.1、基本类型指针

什么的列子就是基本类型的指针。
下列是常见的一些错误
代码①:

# include<stdio.h>int main(void)
{int* p;int i = 5;*p = i;printf("%d\n",*p);return 0;
}

我们定义了一个存放整型变量的指针变量p,但是p没有指向,所以里面存放的是垃圾值(即p指向的是一个不知名的单元,我们将整数5存放在这个不知名的单元里面,这样是错误的,因为这个不知名的单元不是我们控制的,类似于病毒)

代码②:

# include<stdio.h>int main(void)
{int* p;int* q;int i = 5;p = &i;p =q;printf("%d\n",*p);return 0;
}

错误和上面一样,q里面的地址是垃圾值,把垃圾值给了p。
改为:

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

经典指针程序互换
代码①:

# include<stdio.h>void HuHuang(int m,int n)
{int t;t = m;m = n;n = t;
}int main(void)
{int a = 5,b = 3;HuHuang(a,b);printf("a = %d,b = %d\n",a,b);return 0;
}
a = 5,b = 3

调用互换函数时,将a的值赋给了m,将b的值赋给了n。在函数里面实现只是形式参数m和n的值的互换,但printf打印出来的值依然是主函数里面a和b的值。

改进代码②:

# include<stdio.h>
/*void HuHuang1(int* m,int* n)
{int* t;t = m;m = n;n = t;
}*/
//将a的地址赋给m,b的地址赋给n,函数里面交换的只是变量m和n里面的值。void HuHuang2(int* m,int* n)
{int t;t = *m;*m = *n;*n = t;
}
/*将a的地址赋给m,b的地址赋给n,*m指向a等同于实参a里面的值(假设a地址为F,I*m代表以F为地址的变量的值)
*n指向b等同于实参b里面的值。*/
int main(void)
{int a = 5,b = 3;// HuHuang1(&a,&b);HuHuang2(&a,&b);printf("a = %d,b = %d\n",a,b);return 0;
}
a = 3,b = 5

在这里插入图片描述

2.2、指针和数组

2.2.1、指针和一维数组

2.2.1.1、一维数组名

    是指针常量,他存放的是一维数组第一个元素的地址。

# include <stdio.h>int main(void)
{int a[3] = {1,2,3};printf("%#X\n",&a[0]);printf("%#X\n",a);return 0;
}
0X19FF24
0X19FF24
2.2.1.2、下标和指针的关系

    如果a是一个指针变量,则a[ i ]等价于*(a+i)。

# include <stdio.h>int main(void)
{int a[3] = {1,2,3};printf("%d\n",a[1]);printf("%d\n",*(a+1));return 0;
}
2
2
2.2.1.3、确定一维数组需要几个参数

    需要数组第一个元素的地址
    需要数组的长度
代码①:

# include <stdio.h>void f(int* m,int len)//第一个元素的地址和长度
{int i;for(i=0 ;i<len ;i++)printf("%d",*(m+i));//也可以写为m[i],等价于a[i]/b[i],也等价于*(a+i)/*(b+i)printf("\n");
}int main(void)
{int a[3] = {1,2,3};int b[5] = {1,5,6,8,90};f(a,3);f(b,5);return 0;
}
123
156890

代码②:

# include <stdio.h>void f(int* m,int len)
{*(m+2) = 11;
}int main(void)
{int b[5] = {1,5,6,8,90};printf("%d\n",b[2]);f(b,5);printf("%d\n",b[2]);return 0;
}
6
11

总结
可以利用指针,在函数中操作主函数的变量的值,等同于在主函数里面进行操作,进而改变主函数里面变量的值。

2.2.1.4、指针变量的运算

    指针变量不能相加不能相乘也不能相除
    如果两个指针变量指向的是同一块连续空间中的不同存储单元
    则这两个指针变量才可以相减

# include <stdio.h>int main(void)
{int b[5] = {1,5,6,8,90};int* m;int* n;m = &b[1];n = &b[3];printf("%d\n",&b[3]-&b[1]);return 0;
}
2
2.2.1.5、指针变量占用几个字节
# include <stdio.h>int main(void)
{char ch = 'a';int i = 9;double j = 6.3;char* m = &ch;int* n = &i;double* h = &j;printf("%d,%d,%d\n",sizeof(m),sizeof(n),sizeof(h));return 0;
}
4,4,4

在这里插入图片描述

2.2.2、动态内存分配

传统数组的缺点:
(1)数组长度必须事先制定,且只能是常整数,不能是变量
例子:

 int a[5];//OKint len = 5; int a[len]; //error

(2)传统形式定义的数组,该数组的内存程序员无法手动释放,在一个函数运行期间,系统为该函数中数组所分配的空间会一直存在,直到该函数运行完毕时,数组的空间才会被系统释放
(3)数组的长度一旦定义,其长度就不能在更改,数组的长度不能在函数运行的过程中动态的扩充或缩小
(4)A函数定义的数组,在A函数运行期间可以被其它函数使用,但A函数运行完毕之后,A函数中的数组将无法在被其他函数使用,传统方式定义的数组不能跨函数使用

为什么需要动态分配内存
动态数组很好的解决了传统数组的这4个缺陷,传统数组也叫静态数组

malloc函数的引入

# include <stdio.h>
# include <malloc.h>//调用了malloc函数int main(void)
{int i = 5;//分配了4个字节的静态内存(命名为i)int* p = (int*)malloc(4);//动态分配4个字节的空间(只是这个空间没有命名),然p指向这个空间,return 0;/*注意:1、要使用malloc函数,必须要添加头文件2、malloc函数只能有一个形式参数,并且只能为整型3、4表示请求系统分配4个字节的空间4、malloc函数只能返回第一个字节的地址,前面加int*,表示这个空间是分配给整型变量用的。所以用4个字节5、p本身所占的内存是静态分配的(4个字节,用于存放动态分配的空间第一个字节的编号),p所指向的内存是动态分配的*/*p = 5;//*p代表就是一个整型变量,只是这个空间是动态分配的free(p);//表示把p所指向的内存给释放掉,即动态内存释放掉
}

代码①:

# include <stdio.h>
# include <malloc.h>void f(int* q)
{*q = 20;free(q);
}int main(void)
{int* p = (int*)malloc(4);*p = 10;printf("%d\n",*p);//10f(p);printf("%d\n",*p);//垃圾值:-572662307return 0;
}

在这里插入图片描述

构造动态一维数组

# include <stdio.h>
# include <malloc.h>int main(void)
{int len,i;printf("请输入数组元素的个数:");scanf("%d",&len);int* p = (int*)malloc(4 * len);//类似于int p[len];printf("请输入数组的元素,中间以空格隔开:");//对数组元素的输入for(i=0 ;i<len ;i++)scanf("%d",&p[i]);//也可以用*(p+i)//对数组元素的输出for(i=0 ;i<len ;i++)printf("%d ",p[i]);//也可以用*(p+i)printf("\n");return 0;
}
请输入数组元素的个数:5
请输入数组的元素,中间以空格隔开:3 2 5 6 4
3 2 5 6 4

2.3、多级指针

    纯纯套娃

# include <stdio.h>int main(void)
{int i = 5;int* p = &i;int** q = &p; //q是int**类型,用于存放指针变量p的地址(二级指针)int*** r = &q; //r是int***类型,用于存放二级指针变量的地址(多级指针)printf("%d\n",***r);printf("%d\n",**q);printf("%d\n",*p);return 0;
}

3、跨函数使用内存

#include <stdio.h>void f(int** m)
{int i = 5;*m = &i;//*m等于p,p指向i
}int main(void)
{int* p;f(&p);printf("%d\n",*p);//此行代码存在逻辑上的问题。return 0;
}

调用f函数结束后,f函数里面的变量值将会被释放,所以*p不能在访问i空间里面的内容。这就是静态变量不能跨函数使用。

动态内存跨函数使用

#include <stdio.h>
#include <malloc.h>void f(int** m)//二级指针
{//int i = 5;//静态分配内存//*m = &i;//*m等于p,p指向i*m = (int*)malloc(sizeof(int));//动态分配4个字节(用于存放整型变量)//的内存,//等价于p = (int*)malloc(sizeof(int));**m = 5;//等价于*p = 5
}int main(void)
{int* p;f(&p);//f终止后,空间没有被释放printf("%d\n",*p);return 0;
}

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

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

相关文章

2024-02-08 Unity 编辑器开发之编辑器拓展1 —— 自定义菜单栏

文章目录 1 特殊文件夹 Editor2 在 Unity 菜单栏中添加自定义页签3 在 Hierarchy 窗口中添加自定义页签4 在 Project 窗口中添加自定义页签5 在菜单栏的 Component 菜单添加脚本6 在 Inspector 为脚本右键添加菜单7 加入快捷键8 小结 1 特殊文件夹 Editor ​ Editor 文件夹是 …

[职场] 公安管理学就业方向及前景 #媒体#笔记#笔记

公安管理学就业方向及前景 公安管理学是中国普通高等学校本科专业。本专业文理兼收&#xff0c;学制4年&#xff0c;授予法学学士学位。本专业培养掌握马克思主义基本原理&#xff0c;政治坚定&#xff0c;坚持党和国家的路线、方针、政策&#xff0c;具有良好职业素养、科学素…

嵌入式Qt 第一个Qt项目

一.创建Qt项目 打开Qt Creator 界面选择 New Project或者选择菜单栏 【文件】-【新建文件或项目】菜单项 弹出New Project对话框&#xff0c;选择Qt Widgets Application 选择【Choose】按钮&#xff0c;弹出如下对话框 设置项目名称和路径&#xff0c;按照向导进行下一步 选…

应急响应实战笔记01入侵排查篇(5)

第5篇&#xff1a;勒索病毒自救指南 前言 经常会有一些小伙伴问&#xff1a;中了勒索病毒&#xff0c;该怎么办&#xff0c;可以解密吗&#xff1f; 第一次遇到勒索病毒是在早几年的时候&#xff0c;客户因网站访问异常&#xff0c;进而远程协助进行排查。登录服务器&#x…

Python算法题集_排序链表

Python算法题集_排序链表 题148&#xff1a;排序链表1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【冒泡大法】2) 改进版一【列表排序】3) 改进版二【数值归并排序】4) 改进版三【快慢指针归并排序】 4. 最优算法 本文为Python算法题集之一的…

Confluence CVE-2023-22527利用工具

介绍 Confluence CVE 2021&#xff0c;2022&#xff0c;2023 利用工具&#xff0c;支持命令执行&#xff0c;哥斯拉&#xff0c;冰蝎 内存马注入 支持 Confluence 版本&#xff1a;CVE-2021-26084&#xff0c;CVE-2022-26134&#xff0c;CVE_2023_22515&#xff0c;CVE-2023-2…

中年中产程序员从西安出发到海南三亚低成本吃喝万里行:西安-南宁-湛江-雷州-徐闻-博鳌-陵水-三亚-重庆-西安(2.游玩过程)

文章大纲 出发时间&#xff1a;Day1-1月25日星期四&#xff0c;西安飞南宁路途中&#xff1a;Day2-1月26日星期五&#xff0c;南宁-湛江-住雷州&#xff08;曾经支教过的地方&#xff09;【晚上买徐闻到海安新港】路途中&#xff1a;Day3-1月27日星期六&#xff0c;雷州-徐闻渡…

前端JavaScript篇之Promise解决了什么问题、Promise.all和Promise.race的区别的使用场景

目录 Promise解决了什么问题Promise.all和Promise.race的区别的使用场景 Promise解决了什么问题 Promise 解决了 JavaScript 中回调地狱的问题。在传统的回调函数中&#xff0c;如果需要依次执行多个异步操作&#xff0c;就需要使用嵌套的回调函数&#xff0c;这样会导致代码难…

UE5 播放本地MP3、MP4

1.创建一个媒体播放器 2.如创建视频&#xff0c;勾选。 它会多一个媒体纹理给你 3.1 设置音频 在一个actor上添加“媒体音频组件” “音频媒体播放器”赋值给它 3.2播放音频 添加一个音频媒体播放器变量&#xff0c; 赋值 地址使用绝对地址 4.1设置视频 UI上创建一个imag…

图表自动化开篇

目录 前言&#xff1a; 使用 Canvas 或者 SVG 渲染 选择哪种渲染器 代码触发 ECharts 中组件的行为 前言&#xff1a; 图表自动化一直以来是自动化测试中的痛点&#xff0c;也是难点&#xff0c;痛点在于目前越来越多公司开始构建自己的BI报表平台但是没有合适的自动化测试…

[JavaWeb玩耍日记]Maven的安装与使用

目录 一.作用 二.安装 三.使用 2.对项目使用compile命令进行编译,看看新的文件会在哪里产生&#xff1f; 3.需要认识的命令 4.Maven对项目执行不同命令的生命周期特点&#xff1f; 5.如何导入工程外的Maven&#xff1f; 6.如何直观地查看Maven导入了哪些工程或哪些jar包…