C语言进阶——指针(一)

news2024/9/28 21:27:57

目录

一.   字符指针

二.   指针数组

三.   数组指针

四.   数组参数、指针参数

1.一维数组传参

2.二维数组传参

3.一级指针传参

4.二级指针传参


一.   字符指针

在之前,我们就了解到过字符指针

int main()
{
    char a='W';//字符变量
    char* pa=&a;//字符指针
    *pa='w';
    return 0;
}

而除此之外,字符指针还有一种使用方法

char* pstr="abcdef";

我们可以看到,我们似乎是将一串字符串赋给了字符指针pstr

而事实上,我们是将abcdef这个常量字符串的首字符的地址放在了pstr中

而abcdef作为一个常量字符串,本身应该不能被改变,因此我们可以使用const来修饰pstr

const char* pstr="abcdef";

实例

#include <stdio.h>
int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    const char *str3 = "hello bit.";
    const char *str4 = "hello bit.";
    if(str1 ==str2)
        printf("str1 and str2 are same\n");
    else
        printf("str1 and str2 are not same\n");
    if(str3 ==str4)
        printf("str3 and str4 are same\n");
    else
        printf("str3 and str4 are not same\n");
    return 0;
}

 

上述代码中,由于str1,str2两个数组分别开辟了两个空间分别来存储字符串,所以str1和str2的地址固然不相同。

而常量字符串是存储在静态存储区的,str3和str4都是取静态区中abcdef的首元素地址,所以地址相同。



二.   指针数组

无非就是存储指针的数组。

而在上面的字符指针中,我们可以赋予字符串的首地址,因此,指针数组也可以这样操作

char* arr[3]={"abcd","bcde","cdef"};

同样,数组名是该数组首元素的地址,因此,我们也可以将数组名作为指针存放在指针数组中

int nums1[]={1,2,3,4};
int nums2[]={2,3,4,5};
int nums3[]={3,4,5,6};
int nums4[]={4,5,6,7};
int* nums[]={nums1,nums2,nums3,nums4};


三.   数组指针

同样,数组指针也是存放数组地址的指针

在考虑数组指针前,我们可以先来了解一下数组名和&数组名的区别

首先,我们知道,数组名是该数组首元素的地址

那么,将数组名取地址得到的也必然是一个地址,那么这个地址代表的是什么呢?

在我们直接打印两个地址时, 可以发现是相同的。但指针还存在步长,我们可以从步长来了解两者之间的差别

可以看到,这时两者出现了差别,nums与nums+1之间差距4个字节, 也就是int类型的大小,而&nums与&nums+1之间差距16个字节,也就是4个int类型所占的大小,当然也就是整个数组所占内存大小。

因此我们可以得知,不同于数组名所代表的的首元素地址,&数组名所代表的整个数组的地址

在我们了解到数组名与&数组名的差别后,我们也就可以来实现数组指针

数组指针理所应当存储整个数组的地址,因此我们要选择&数组名,同时(以整形数组为例)数组指针的类型应该为int (*) [10],其中int 指的是数组中的元素类型,而*表示这是一个指针类型,而[10]则代表数组的大小为10;因此我们就可以实现数组指针

int nums[4]={1,2,3,4};
int(*p)[4]=&nums;
printf("%d", (*p)[0]);
printf("%d",nums[0]);//效果相同

而在使用中,我们很少将一维数组的地址存储为数组指针,因为比较的鸡肋,我们可以在二维数组中使用到它

void print_arr1(int arr[3][5], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
void print_arr2(int(*arr)[5], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf("%d ", (*(arr + i))[j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
	print_arr1(arr, 2, 5);
	print_arr2(arr, 2, 5);
	return 0;
}

二维数组在传参时,数组名同样是首元素的地址,而二维数组首元素的地址指的是第一行的地址
,而第一行其实是一个一维数组,因此可以使用数组指针来接受



四.   数组参数、指针参数

1.一维数组传参

#include <stdio.h>
void test(int arr[])
{}
void test(int arr[10])
{}
void test(int* arr)
{}
void test2(int* arr[20])
{}
void test2(int** arr)
{}
int main()
{
	int arr[10] = { 0 };
	int* arr2[20] = { 0 };
	test(arr);
	test2(arr2);
}

一维数组传参其实都比较简单,我们可以知道,上面几种传参方法都是正确的


2.二维数组传参

void test(int arr[3][5])//ok?
{}
void test(int arr[][])//ok?
{}
void test(int arr[][5])//ok?
{}


void test(int* arr)//ok?
{}
void test(int* arr[5])//ok?
{}
void test(int(*arr)[5])//ok?
{}
void test(int** arr)//ok?
{}

int main()
{
	int arr[3][5] = { 0 };
	test(arr);
}

首先我们先看一下前三种传参方式,由于二维数组的行可以忽略,而列不能忽略,我们可以知道第一种和第三种是正确的,而第二种是违规的

而后面四种则和指针相关。首先我们在上面提到过,二维数组的数组名代表二维数组第一行的地址,而第一种写法中使用整形指针显然不行。                                                                                而第二种的参数为一个指针数组,也不可以。                                                                                第三种写法在我们上面提到过类似的,是一个数组指针,因此可以。                                                最后一种写法作为一个二级整形指针,固然也不可以

而经常刷题的老铁会发现一个问题

类似于这样的题目,在二维数组传参时使用的是就是char** board,而这种方法我们在前面已经被否定了,这又是为什么呢?

 这是因为,在leetcode中,所传入的“二维数组”其实是由一维数组模拟而来的

char** board = (char**)malloc(sizeof(char*) * m);
for (int i = 0; i < m; i++)
{
	board[i] = (char*)malloc(sizeof(char) * n);
}

而malloc我们会在后面的动态内存管理中学到,这里就不过度展开


3.一级指针传参

#include <stdio.h>
void print(int* p, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d\n", *(p + i));
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	print(p, sz);
	return 0;
}

指针的传参实现是比较简单的,我们主要考虑函数参数部分为指针时能接受什么参数

一级指针所能接受的参数我们目前常见的有数组名、&变量、指针变量


4.二级指针传参

#include <stdio.h>
void test(int** ptr)
{
	printf("num = %d\n", **ptr);
}
int main()
{
	int n = 10;
	int* p = &n;
	int** pp = &p;
	test(pp);
	test(&p);
	return 0;
}

同样,二级指针所能接受的参数有二级指针变量、&一级指针变量、指针数组的数组名等。

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

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

相关文章

1.3日报

今天优化了getMobileByScene接口&#xff0c; 测试accountadd接口 遇到的问题与解决 在升级安装python3时&#xff0c;由于操作失误&#xff0c;导致系统错误&#xff0c;在同事帮助下重装了系统&#xff0c;好在保住了文件。但是软件还得重新配置。 getMobileByScene接口在…

精益|什么是价值流图分析(VSM)?

在精益生产管理中&#xff0c;价值流研究主要是指利用制作价值流图&#xff0c;进行价值流图研究可以发现并消除浪费、降低成本&#xff0c;改进企业运营状况&#xff0c;提升企业竞争力。因此进行价值流研究离不开价值流图。 价值流图&#xff08;Value Stream Mapping&#x…

基于KT6368A蓝牙芯片开发智能抖音翻页翻页笔总结

一、功能简介 KT6368A蓝牙芯片也是基于 HID 开发&#xff0c;主要用于浏览当下火爆的抖音等小视频的上下翻页、左右菜单切换、暂停等操作。打开手机蓝牙进行连接&#xff0c;进入视频浏览界面操作对应按键即可。包含一个蓝牙的指示灯&#xff0c;表示是否连接 。同时支持adkey按…

HBase面试题汇总

1、请描述HBse的&#xff1f; 答&#xff1a; Memstore级别&#xff1a;当MemStore的大小达到设置阈值&#xff08;默认128M&#xff09;&#xff0c;会触发flush操作。 1、HBase中Memstore在何时进行数据的flush操作&#xff1f; 答&#xff1a; Memstore级别&#xff1a…

uniapp 填坑之旅---udb微信小程序端显示异常

功能描述&#xff1a;A页面展示列表a&#xff0c;点击a&#xff0c;进入B页面&#xff0c;展示a对象关联的子对象b。在B页面中&#xff0c;通过unicloud-db组件manual模式加载&#xff0c;具体代码按照官网示例来写。问题描述&#xff1a;代码实现后&#xff0c;一直在H5调试&a…

Jmeter安装配置使用超详细教程(亲测有效)

文章目录1、Jmeter下载2、JDK安装3、Jmeter环境部署4、验证jmeter5、修改语言6、接口测试1、Jmeter下载 1.1、下载地址 http://jmeter.apache.org/download_jmeter.cgi 1.2、选择对应版本&#xff0c;本文以windows版本为例&#xff0c;版本号为5.5。 2、JDK安装 jmeter安装…

到底为什么那么多大厂在开始疯狂裁员?

最近几年大家都听到了好多大厂公司开始裁员&#xff0c;比如鹅厂、狗厂、鸟厂、熊厂等。 接下来给大家讲个故事&#xff0c;希望故事看完&#xff0c;你就会懂了&#xff01; 外国的神父呆了不久 留下几个 P 就走了&#xff0c; 一个 P 叫 BPR&#xff0c; 一个 P 叫 ERP。 …

作业1/4 设备树总结

1.什么是设备树 设备树&#xff08;Device Tree)是用来描述&#xff08;存储&#xff09;硬件信息的一种树形结构&#xff0c;设备树在linux内核启动的时候传递给内核被内核解析&#xff0c;用来描述设备信息的一种方式&#xff08;地址&#xff0c;中断号...&#xff09;。设备…

《收获,不止Oracle》表的设计之五朵金花

表设计主要强调什么场合该选择什么技术&#xff0c;没有最高级的技术&#xff0c;只有最适合的技术。 1.表的特性 普通堆表的不足之处 1.查看产生多少日志 [oracleoracle-db-19c ~]$ sqlplus / as sysdbaSQL*Plus: Release 19.0.0.0.0 - Production on Wed Jan 4 14:27:13 20…

电商数据监测的应用价值——国内吸尘器行业数据浅析

随着科技的发展与居民生活水平的提高&#xff0c;吸尘器进入日常生活&#xff0c;成为了常见家用清洁用具之一。2022年上半年&#xff0c;吸尘器市场零售额达145亿元&#xff0c;同比增速达14.0%&#xff0c;零售量1008万台&#xff0c;同比下跌2.8%。&#xff08;数据来源&…

Hadoop HA高可用

文章目录Hadoop HA高可用1.1 HA概述1.2 HDFS-HA工作机制1.2.1 HDFS-HA工作要点1.2.2 HDFS-HA自动故障转移工作机制1.3 HDFS-HA集群配置1.3.1 环境准备1.3.2 规划集群1.3.3 配置Zookeeper集群1&#xff09;集群规划2&#xff09;解压安装3&#xff09;配置zoo.cfg文件4&#xff…

药品需求加大,蒸汽发生器等制药设备该如何快速有效地进行维护?

一、行业背景药品的生产与制造的每一道关卡都是十分严格的&#xff0c;一方面&#xff0c;涉及到化工污染问题&#xff0c;制药的废气一旦没有得到妥善处理&#xff0c;则会危及到周边居民以及企业工作人员的健康。另一方面&#xff0c;药品本着治病救人的原则&#xff0c;其品…

[Android]序列化原理Serializable

引入 我们知道&#xff0c;当一个程序终止时&#xff0c;这个程序创建的对象也会随着程序终止&#xff0c;那么我需要如何做才能不受其他程序的状态影响并且可以得到其他程序创建的对象状态呢&#xff1f;这时候我们就可以使用Serializable来进行序列化把对象持久化到存储设备上…

【服务器数据恢复】断电导致服务器故障的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌服务器&#xff0c;12块硬盘组成raid5磁盘阵列&#xff0c;存储普通文件。 服务器故障&#xff1a; 机房供电不稳定导致服务器断电&#xff0c;管理员重启服务器后发现服务器无法正常使用。 根据用户描述&#xff0c;北亚服务器数据恢复工…

使用vscode在CMake工程中集成gtest共享库进行单元测试

使用vscode在CMake工程中集成gtest共享库做单元测试一、概述二、工程内容清单三、CMakeLists.txt内容说明四、构建工程一、概述 本文主要介绍如何在一个多层次目录结构的CMAKE工程中以共享库的形式集成gtest进行单元测试。 关于如何使用CMake管理多层次目录结构的CMake工程&a…

FFmpeg 解复用实战

1.封装格式相关函数 avformat_alloc_context()&#xff1a;负责申请一个AVFormatContext结构的内存,并进行简单初始化&#xff0c;这个函数可以不用手动调用&#xff0c;内部会自动调用。 avformat_free_context()&#xff1a;释放该结构里的所有东西以及该结构本身&#xff0…

再学C语言24:分支和跳转——逻辑运算符和条件运算符

一、多重选择else if 功能&#xff1a;在两个以上的语句中作出选择 示例代码&#xff1a; #include <stdio.h> int main(void) {float score;printf("Please enter your score: \n");scanf("%f", &score);if(score < 60)printf("不及…

SSM基础整合

SSM基础整合 文章目录SSM基础整合[toc]SSM基础整合SSM整合流程表现层数据封装设置统一数据返回结果类定义code类优化Controller优化后的返还结果异常处理器异常处理项目异常处理方案项目异常分类处理SSM基础整合 SSM整合流程 创建工程 SSM整合 Spring SpringConfig Configur…

CAS 的使用场景 CAS的ABA问题的优化 以及 synchronized 的三大优化

目录 &#x1f388;专栏链接:多线程相关知识详解 一.什么是CAS 二.CAS最常用的两个场景 Ⅰ.实现原子类 Ⅱ.实现自旋锁 三.CAS的ABA问题 四.优化解决CAS的ABA问题 五.synchronized的优化 Ⅰ.锁升级/锁膨胀 Ⅱ.锁消除 Ⅲ.锁粗化 一.什么是CAS CAS&#xff08;Compar…

p2深度学习基本概念简介下笔记

3. 第 1 讲&#xff1a;深度学习基本概念简介下_哔哩哔哩_bilibili 线性模型太简单&#xff0c;我们需要比较复杂的模型。 不管怎样弄&#xff0c;蓝色描述不出红色的线 强调model bias 无法模拟真实的状况 写出一个有未知参数更复杂的model 观察红色的曲线 &#xff1a;可…