学习C语言之 深入了解指针1

深入了解指针

前面已了解到

        1)指针就是个变量,用来存放地址,地址是唯一的,可以标识一块内存空间。

        2)指针的大小是固定的4/8个字节(32位平台/64位平台)。

        3)指针是有类型的,指针的类型决定了指针的 +/- 整数的步长,指针解引用操作时候的权限。

        4)指针的运算。

        以此为基础,深入了解指针。

1、字符指针

        在指针的类型中有一种指针类型为字符指针 char* 。

示例如下:

//字符数组
int main()
{char* pc = "hello";		//字符指针printf("%c\n", *pc);	//打印结果 h 。对指针解引用得到指针指向的字符。printf("%s\n", pc);		//打印结果 hello 。 字符串打印,提供第一个字符串的地址即可。char arr[] = "hello";	//字符数组arr[0] = 'w';			//将字符数组第一个元素改为 w 。return 0;
}

        一般使用演示:

//字符指针用法一
int main()
{char a[] = "hello";char* pa = &a;		//定义字符指针,指向数组地址,数组地址与数组首元素地址一致//即此处pa指向的是数组a[]中首元素。printf("%s\n", pa);	//打印结果 hello 。*pa = 'w';			//对pa解引用,得到的是a[0],将a[0]改成w。printf("%s\n", pa);	//打印结果 wello 。return 0;
}

        另一种使用演示:.

//字符指针用法二
int main()
{char* pstr = "hello";printf("%s\n", pstr);	//打印结果 hello 。 *pstr = 'w';	//报错,因为pstr此时指向的是常量字符串。//实际代码一般写成 const char* pstr = "hello" 。return 0;
}

        代码 const char* pstr = "hello." 本质上是把字符串 “hello.” 首字符的地址放到了pstr中。即把一个常量字符串的首字符 h 的地址存放到指针变量 pstr 中。

        C/C++ 会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。

2、指针数组

        指针数组是一个存放指针的数组。

演示如下:

//指针数组用法一
int main()
{int a = 0;int b = 2;int c = 3;int* arr[3] = { &a,&b,&c };	//定义数组,数组含3个指针变量int i = 0;for (i = 0; i < 3; i++){printf("%d ", *(arr[i]));	//打印结果0 2 3 。//即对数组某个元素解引用,该元素为地址,解引用得到地址中的数据。}return 0;
}

还可模拟实现二维数组,演示如下:

//指针数组用法二
int main()
{int a[] = { 1,2,3,4,5 };int b[] = { 2,3,4,5,6 };int c[] = { 3,4,5,6,7 };int* arr[3] = { a,b,c };	//将三个数组的首元素地址放进指针数组中。int i = 0;for (i = 0; i < 3; i++)	//循环三次,每次进入一个数组{int j = 0;for (j = 0; j < 5; j++)	//循环五次,每次打印数组中的一个元素。{printf("%d ", *(arr[i]+j));	//打印结果//1 2 3 4 5 //2 3 4 5 6//3 4 5 6 7}printf("\n");}return 0;
}

3、数组指针

        3.1、数组指针的定义

        整型指针:int * pint 是能够指向整型数据的指针。

        浮点型指针:float * pf 是能够指向浮点型数据的指针。

        数组指针:int (*p) [10] 是能够指向数组的指针。

        int (*p) [10] 中,p 先和 * 结合,说明p是一个指针变量,然后指针指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。

        需要注意,[ ] 的优先级要高于 * ,所以必须加上()来保证 p 先和 * 结合。

演示如下:

//数组名和数组指针
int main()
{int a = 0;		//定义整型变量 aint* pa = &a;	//定义整型指针 pachar b = '1';	//定义字符变量 bchar* pb = &b;	//定义字符指针 pbfloat c = 1.2;	//定义浮点型变量 cfloat* pc = &c;	//定义浮点型指针 pcint arr[5] = { 1,2,3,4,5 };	//定义数组		arr[5]int(*parr)[5] = &arr;		//定义数组指针	parrprintf("%d\n", *(*parr+1));	//打印结果 2 。//*parr 得到的是数组名 arr 。//数组名 arr 代表数组首元素地址,对其 +1,得到数组第二个元素地址。//对 *parr+1 解引用,得到该地址上的元素 2 。return 0;
}

        3.2、&数组名 VS 数组名

        对于数组 int arr[10] ,arr 是数组首元素的地址,&arr 是数组的地址。arr +1 得到的是数组第二个元素的地址,&arr +1得到的是下一个数组(或数据)的地址。

        &arr 的类型是 int (*) [10] ,是一种数组指针类型,&arr+1会跳过整个数组的大小,即 &arr+1 与 &arr 的差值是40(数组是10个整型,占40个字节)。

        注意:

        1)sizeof (数组名),这里的数组名表示整个数组,计算的是整个数组的大小。

        2)&数组名,这里的数组名表示整个数组,取出的是整个数组的地址。

        3)除此之外,所有的数组名都表示首元素的地址。

演示如下:

//数组指针使用
int main()
{int arr[5] = { 1,2,3,4,5 };int* parr1= arr;			//定义整型指针 parr1,值为数组首元素地址。int(*parr2)[5] = &arr;		//定义数组指针 parr2,值为数组地址。printf("%p\n", parr1);		//打印结果 00D6F838printf("%p\n", parr1+1);	//打印结果 00D6F83C 差值为 4 。printf("%p\n", parr2);		//打印结果 00D6F838printf("%p\n", parr2+1);	//打印结果 00D6F84C 差值为 14(十六进制,转换为十进制是20)。//可以看到parr1代表的容量是1个整型,parr2代表的容量是整个数组(5个整型长度是20)。return 0;
}

        3.3、数组指针的使用

        数组指针中存放的是数组的地址。

数组指针在一维数组中的使用(感觉没优点),演示如下:

//数组指针在一维数组中的使用
int main()
{int arr[5] = { 1,2,3,4,5 };int(*parr)[5] = &arr;		//定义数组指针 parr,值为数组地址。int i = 0;for (i = 0; i < 5; i++){printf("%d ", *(*parr + i));	//打印结果 1 2 3 4 5 。//*parr 得到的是数组名 arr 。//数组名 arr 代表数组首元素地址,对其 +i,得到数组第i+1个元素地址。//对 *parr+i 解引用,得到该地址上的元素 arr[i+1] 。}return 0;
}

数组指针在二维数组中的使用,演示如下:


//数组指针在二维数组中的使用
int main()
{int arr[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };	//定义二维数组,三行,每行四列。int(*parr)[4] = arr;			//定义数组指针,指向二维数组的首元素。//二维数组的首元素是第一行数组,所以要用数组指针。int i = 0;int j = 0;for (i = 0; i < 3; i++){for (j = 0; j < 4; j++){printf("%d ", *(*(parr + i) + j));	//数组指针+i(parr+i),得到第 i+1 行数组的地址,对其解引用 *(parr + i) 得到这一行数组,即数组名。//数组名就是数组首元素地址,对这一行数组名+j (*(parr + i) + j),得到该行数组第 j+1 个元素的地址。//对第 j+1 个元素的地址解引用 *(*(parr + i) + j) 得到该地址中的数据 。//打印结果//1 2 3 4 //2 3 4 5 //3 4 5 6 }printf("\n");}return 0;
}

4、数组参数、指针参数

        4.1、一维数组传参

演示如下:

//一维数组传参
//void test(int arr)	//以整型类型传参,无法得到数组
//{
//	printf("%d\n",arr);		//打印结果 16709412 ,为数组地址。
//}//void test(int arr[])	//以数组类型传参,可以得到数组
//{
//	printf("%d\n",arr[1]);		//打印结果 0 。
//}//void test(int arr[5])	//以数组类型传参,可以得到数组
//{
//	printf("%d\n", arr[0]);		//打印结果 0。
//}void test(int* arr)	//以指针类型传参,可以得到数组
{printf("%d\n", *arr);		//打印结果 0 。
}//void test2(int* arr)	//以指针类型传参,可以得到数组
//{
//	printf("%d\n", *arr);	//打印结果 0 。
//}void test2(int** arr)	//以二级指针类型传参,可以得到数组
{printf("%d\n", *arr);	//打印结果 0 。
}int main()
{int arr[5] = { 0 };int* arr2[5] = { 0 };test(arr);test2(arr2);return 0;
}

        4.2、二维数组传参

演示如下:

//二维数组传参
//void test(int arr[][4])		//以二维数组类型传参,写明列数,可以得到数组元素
//{
//	printf("%d\n", arr[2][1]);	//打印结果 4 。
//}//void test(int arr[3][4])		//以二维数组类型传参,写明行数和列数,可以得到数组元素
//{
//	printf("%d\n", arr[2][1]);	//打印结果 4 。
//}//void test(int arr[3][])		//以二维数组类型传参,不写明列数,报错
//{
//	printf("%d\n", arr[2][1]);	//打印结果 4 。
//}//void test(int* arr)		//以整型指针类型传参,无法得到数组
//{
//	;
//}//void test(int* arr[4])		//以整型指针数组类型传参,无法得到数组
//{
//	;	
//}//void test(int (*arr)[4])		//以数组指针类型传参,可以得到数组
//{
//	printf("%d\n", (*arr+1)[2]);	//打印结果 4 。这里是第二行的第三个元素。
//}void test(int** arr)		//以二级指针类型传参,无法得到数组
{;
}int main()
{int arr[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };test(arr);return 0;
}

        4.3、一级指针传参

演示如下:

级指针传参void test(int* x)
{(*x) = (*x) + 1;
}int main()
{int a = 0;int* pa = &a;test(pa);printf("%d\n", a);	//打印结果 1 。//说明一级指针传参,可以通过指针变量传参。test(&a);printf("%d\n", a);	//打印结果 2 。//说明一级指针传参,可以通过取变量地址形式传参。return 0;
}

        4.4、二级指针传参

演示如下:

//二级指针传参
void test(int** x)
{(**x) = (**x) + 1;
}int main()
{int a = 0;int* pa = &a;int** ppa = &pa;int* arr[10] = { &a };int* (*parr)[10] = &arr;test(ppa);printf("%d\n", a);	//打印结果 1 。//说明二级指针传参,可以通过二级指针变量传参。test(&pa);printf("%d\n", a);	//打印结果 2 。//说明二级指针传参,可以通过取一级指针变量地址形式传参。test(parr);printf("%d\n", a);	//打印结果 3 。//说明二级指针传参,可以通过一级指针数组的指针传参。test(&arr);printf("%d\n", a);	//打印结果 4 。//说明二级指针传参,可以通过取一级指针数组地址的形式传参。//注:这里其实传的是数组地址,严格来说格式不规范。test(arr);printf("%d\n", a);	//打印结果 4 。//说明二级指针传参,可以通过一级指针数组名的形式传参。//这是因为数组名就是数组首元素地址。return 0;
}

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

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

相关文章

Linux中如何用ida调试fork后的子进程

原文链接 > https://redqx.github.io/linux/2024/07/24/linux-debugfork.html 本文的一些图片引用可能有一些问题, 比如数据不对劲,但无伤大雅 自己懒得粘贴图片了 环境: wsl-kali-2024 ida-7.7 插件: Lazy_ida, 还有一个什么插件不知道什么名字, 可以把汇编转字节码 …

mac安装Whisper

Whisper 官方git https://github.com/openai/whisper?tabreadme-ov-file 基本上参考官方的安装流程 pip3 install -U openai-whisper pip3 install githttps://github.com/openai/whisper.git pip3 install --upgrade --no-deps --force-reinstall githttps://github.com/…

牛客周赛52--E小红的图上加边(联通块)

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 \,\,\,\,\,\,\,\,\,\,小红有一张 nnn 个点 mmm 条边的无向图&#xff0c;每个节点的权值是 aia_iai​。           \,\,\,\,\,\,\,\,\,\,现在小红希望加边把这个图连成连通…

Elasticsearch概念及ELK安装

1、Elasticsearch是什么 它是elastic技术栈中的一部分。完整的技术栈包括&#xff1a; Elasticsearch&#xff1a;用于数据存储、计算和搜索 Logstash/Beats&#xff1a;用于数据收集 Kibana&#xff1a;用于数据可视化 整套技术栈被称为ELK&#xff0c;经常用来做日志收集…

ansible的role目录结构及用法

目录 目录结构介绍案例 目录结构介绍 可以通可以通过使用 ansible-galaxy 命令再当前目录自动生成 role 的基本目录结构。 myrole为文件名&#xff08;角色名&#xff09; ansible-galaxy init myrole如果没有安装Ansible Galaxy&#xff0c;你可以使用以下命令安装&#xff…

Python 函数的参数形式

Python 函数的参数形式 Python 函数的参数有多种形式&#xff0c;每种形式在不同的场景下使用。我们主要介绍以下几种&#xff1a; 位置参数关键字参数默认参数可变位置参数&#xff08;*args&#xff09;可变关键字参数&#xff08;**kwargs&#xff09; 1. 位置参数 位置…

python题解

宽度与对齐 输出455、-123、987654&#xff0c;宽度为5&#xff0c;分别左对齐和右对齐 格式 输入格式&#xff1a; 无 输出格式&#xff1a; 输出为整型&#xff0c;空格分隔。每个数的输出占一行 样例 1 输入&#xff1a; 无 复制 输出&#xff1a; 455 455 -123 -123 98…

Vue的SSR和预渲染:提升首屏加载速度与SEO效果

引言 在现代Web应用开发中,首屏加载速度和搜索引擎优化(SEO)是衡量应用性能的重要指标。Vue.js 作为流行的前端框架,提供了服务器端渲染(SSR)和预渲染(prerendering)两种技术来提升这些指标。本文将深入探讨如何使用 Vue 的 SSR 和预渲染技术,提供详细的代码示例和最…

FFmpeg源码:av_probe_input_format3函数分析

一、av_probe_input_format3函数的声明 av_probe_input_format3函数声明在FFmpeg源码&#xff08;本文演示用的FFmpeg源码版本为5.0.3&#xff09;的头文件libavformat/avformat.h中&#xff1a; /*** Guess the file format.** param is_opened Whether the file is already…

Go语言的数据结构

数据结构 数组 支持多维数组&#xff0c;属于值类型&#xff0c;支持range遍历 例子&#xff1a;随机生成长度为10整数数组 package main import ("fmt""math/rand" ) // 赋值 随机获取100以内的整数 func RandomArrays() {var array [10]int //声明var…

【MySQL进阶篇】锁:全局锁、表级锁以及行级锁

一、锁的概述 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中除传统的计算资源&#xff08;CPU、RAM、I/O&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须要解决的一个问题&am…

C语言11 结构体、共用体、枚举和重定义

目录 结构体&#xff08;Struct&#xff09; 定义结构体 声明和初始化结构体变量 访问结构体成员 嵌套结构体 指向结构体的指针 共用体&#xff08;Union&#xff09; 定义共用体 声明和使用共用体 重定义&#xff08;Typedef&#xff09; 定义类型别名 使用类型别…

Person Re-Identification(Re-ID)的分类

行人重识别&#xff08;Person Re-Identification, Re-ID&#xff09;是计算机视觉和深度学习中的一个重要任务&#xff0c;旨在通过图像或视频中的行人外观信息来识别和追踪同一个人在不同摄像头视角下的出现。根据任务的不同&#xff0c;行人重识别可以分为以下几类&#xff…

室内消防逃生通道占用检测AI算法:科技筑防,守护生命通道

随着城市化进程的加快&#xff0c;高层建筑和大型公共场所的数量急剧增加&#xff0c;消防安全问题愈发凸显。其中&#xff0c;室内消防逃生通道的畅通性直接关系到火灾发生时人员的安全疏散。然而&#xff0c;由于各种原因&#xff0c;如杂物堆放、车辆停放等&#xff0c;消防…

nacos 2.3.2 若依使用mysql

1&#xff09;从官网下载 nacos&#xff0c;如果下载慢&#xff0c;关注从本人发布上传下载也可以 2&#xff09;修改配置文件 【config】-【application.properties】 ### Deprecated configuration property, it is recommended to use spring.sql.init.platform replaced.…

SpringBoot实现定时任务-@Scheduled

在Java编程中&#xff0c;Scheduled 注解是 Spring Framework 提供的一个用于定时任务的注解。 Scheduled可以将一个方法配置为定时执行的任务。 以下是一些基本用法&#xff1a; 1.固定速度 fixedRate指两次任务的开始时间间隔。所以存在第二次任务开始时&#xff0c;第一…

LeetCode 2844.生成特殊数字的最少操作(哈希表 + 贪心)

给你一个下标从 0 开始的字符串 num &#xff0c;表示一个非负整数。 在一次操作中&#xff0c;您可以选择 num 的任意一位数字并将其删除。请注意&#xff0c;如果你删除 num 中的所有数字&#xff0c;则 num 变为 0。 返回最少需要多少次操作可以使 num 变成特殊数字。 如…

mysql各个参数调整

innodb_lock_wait_timeout 事务锁释放时间

前端知识--前端访问后端技术Ajax及框架Axios

一、异步数据请求技术----Ajax Ajax是前端访问后端的技术&#xff0c;为异步请求&#xff08;不刷新页面&#xff0c;请求数据&#xff0c;只更新局部数据&#xff09;。 例如&#xff1a;在京东网站中搜索电脑&#xff0c;就会出现一些联想搜索&#xff0c;但此时页面并没有…

【技术支持】canvas转换为图片或PDF保存电脑

注意&#xff1a;有些网站可能由于canvas跨域污染问题&#xff0c;无法使用toBlob&#xff0c;所以无法转换 开发者工具中&#xff0c;选中需要转换的canvas元素&#xff08;使其可以使用$0语法&#xff09; 控制台输入如下代码 $0.toBlob(function (blob) {var link document…