07:指针

news2024/10/6 6:28:18

指针

  • 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];//OK
 int 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);//10
	f(p);
	printf("%d\n",*p);//垃圾值:-572662307

	return 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.coloradmin.cn/o/1446482.html

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

相关文章

Ubuntu 23.10通过APT安装Open vSwitch

正文共&#xff1a;888 字 8 图&#xff0c;预估阅读时间&#xff1a;1 分钟 先拜年&#xff01;祝各位龙年行大运&#xff0c;腾跃展宏图&#xff01; 之前在介绍OpenStack的时候介绍过&#xff08;什么是OpenStack&#xff1f;&#xff09;&#xff0c;OpenStack是一个开源的…

Go+:一种简单而强大的编程语言

Go是一种简单而强大的编程语言&#xff0c;它是在Go语言之上构建的&#xff0c;旨在提供更加强大、灵活和易于使用的编程体验。Go与Go语言共享大部分语法和语义&#xff0c;因此Go开发人员可以很快上手Go&#xff0c;同时也可以使用Go来编写更加简洁和高效的代码。在本文中&…

WinCC、LabVIEW、InTouch组态软件比较,看后秒懂,超简洁。

WinCC、LabVIEW和InTouch是三种常见的组态软件&#xff0c;用于工业自动化和人机界面开发。以下是它们之间的比较和区别&#xff1a; 功能和应用领域&#xff1a; WinCC&#xff1a;WinCC是西门子公司的组态软件&#xff0c;主要用于监控和控制工业过程。它提供了丰富的功能&a…

OpenCV-37 最小外接矩形和最大外接矩形

一、外接矩形 外接矩形分为最小外接矩形和最大外接矩形。 下图中红色矩形为最小外接矩形&#xff0c;绿色矩形为最大外接矩形。 1. 最小外接矩形 minAreaRect(points) --- 最小外接矩形 point为轮廓&#xff1b; 返回值为元组&#xff0c;内容是一个旋转矩形(RotatedRect…

《Linux 简易速速上手小册》第5章: 用户与群组管理(2024 最新版)

文章目录 5.1 管理用户账户5.1.1 重点基础知识5.1.2 重点案例&#xff1a;创建一个新的开发者账户5.1.3 拓展案例 1&#xff1a;禁用用户登录5.1.4 拓展案例 2&#xff1a;设置账户到期 5.2 群组概念与管理5.2.1 重点基础知识5.2.2 重点案例&#xff1a;为项目团队设置群组5.2.…

HTML 超文本标记语言

超文本标记语言 HTML 在一个客户程序主窗口上显示出的万维网文档称为页面 (page)。 页面制作的标准语言&#xff1a;HTML。 超文本标记语言 HTML (HyperText Markup Language) 是一种制作万维网页面的标准语言&#xff0c;它消除了不同计算机之间信息交流的障碍&#xff0c…

分享89个jQuery特效,总有一款适合您

分享89个jQuery特效&#xff0c;总有一款适合您 89个jQuery特效下载链接&#xff1a;https://pan.baidu.com/s/1krmOd12n09u2vROfeEL2KQ?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理…

蓝桥杯2023真题(2)

1.硬币兑换 #include <iostream> using namespace std; int main() {int a[5000] {0}, ans 0;//coin1for(int i 1; i < 2023; i){//coin2for(int j i 1; j < 2023; j){a[i j] i;ans max(ans, a[i j]);}}cout<<ans;return 0; }2.更小的数 //暴力枚举…

idea中vue文件如何快捷打出html标签结构,不写<

例如写一个<button></button>标签&#xff1a;快捷键如下 先写一个button&#xff0c;然后再按tab键即可自动生成一对标签。 演示&#xff1a; 步骤一&#xff1a; 步骤二&#xff1a;

【Java程序设计】【C00271】基于Springboot的地方美食分享网站(有论文)

基于Springboot的地方美食分享网站&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的地方美食分享网站 本系统分为系统功能模块、管理员功能模块、以及用户功能模块。 系统功能模块&#xff1a;网站首页可以查看首…

揭秘外观模式:简化复杂系统的关键设计策略

前言 外观模式&#xff08;Facade Pattern&#xff09;是一种结构型设计模式&#xff0c;它隐藏了系统的复杂性&#xff0c;并向客户端提供了一个可以访问系统的接口。这种类型的设计模式向现有的系统添加一个接口&#xff0c;来隐藏系统的复杂性。这种模式涉及到一个单一的类…

Android的常用Drawable讲解

今天来讲讲Android开发中水都绕不开的东西----drawable。最常使用的莫过于通过XML所声明的Drawable作为View背景&#xff0c;通过代码创建的应用场景则较少。其有着使用简单&#xff0c;比自定义view的成本要低的特点。同时&#xff0c;非图片类型的drawable占用空间较小&#…

【项目日记(九)】项目整体测试,优化以及缺陷分析

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:项目日记-高并发内存池⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你做项目   &#x1f51d;&#x1f51d; 开发环境: Visual Studio 2022 项目日…

Linux|centos7下的编译|ffmpeg的二进制安装

Windows版本的ffmpeg&#xff1a; ###注意&#xff0c;高版本可能必须要windows10以及以上才支持&#xff0c;win7估计是用不了的 下载地址&#xff1a;Builds - CODEX FFMPEG gyan.dev 或者这个下载地址&#xff1a;https://github.com/BtbN/FFmpeg-Builds/releases 这两个…

如何升级至ChatGPT Plus:快速指南,ChatGPT的秘密武器GPT4.0是什么?

提到 ChatGPT。想必大家都有所耳闻。自从 2022 年上线以来&#xff0c;就受到国内外狂热的追捧和青睐&#xff0c;上线2个月&#xff0c;月活突破1个亿&#xff01;&#xff01;&#xff01; 而且还在持续上涨中。因为有很多人都在使用 ChatGPT 。无论是各大头条、抖音等 App、…

嵌入式Qt 第一个Qt项目

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

vue3 腾讯tdesign 后台管理框架的使用

1.介绍 TDesign 是具有包容性的设计体系&#xff0c;它强调为业务提供产品、服务等过程中&#xff0c;追求以人为本、人人受益的包容性&#xff0c;要求搭建过程中&#xff0c;了解业务底层&#xff0c;理解业务场景的多样性&#xff0c;并在繁杂的业务场景中寻找共性和特性&a…

论文阅读:GamutMLP A Lightweight MLP for Color Loss Recovery

这篇文章是关于色彩恢复的一项工作&#xff0c;发表在 CVPR2023&#xff0c;其中之一的作者是 Michael S. Brown&#xff0c;这个老师是加拿大 York 大学的&#xff0c;也是 ISP 领域的大牛&#xff0c;现在好像也在三星研究院担任兼职&#xff0c;这个老师做了很多这种类似的工…

unity2017 遇到visual studio 2017(社区版) 30日试用期到了

安装unity2017 遇到visual studio 2017 30日试用期到了&#xff0c;网上百度搜了好多方法都没有成功。 最后用了这个方法&#xff1a; 1)启动vs2017&#xff0c;在弹出要登录的窗口之前&#xff0c;迅速的点击工具-》选项-》账户&#xff0c;勾选在添加账户或对账户重新进行身…

Netty应用(九) 之 编解码器概念 Netty常见的编解码器

目录 22.编解码器 22.1 编解码的概念 22.2 netty中的编解码 22.3 序列化 23.编解码器在使用过程中的两部分核心内容 23.1 序列化协议&#xff08;编码格式&#xff09;&#xff08;传输数据的格式&#xff09; 23.1.1 Java默认的序列化与反序列化 23.1.2 XML的序列化与反…