指针进阶详解(上)

这篇具有很好参考价值的文章主要介绍了指针进阶详解(上)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

指针是检验学者对C语言掌握好与坏的重要标准之一,在指针初阶中,我们以及详细介绍了以下内容:

  1. 指针是一个变量,用来存放地址,地址唯一标识一块空间。
  2. 指针的大小固定为4/8个字节(32位平台/64位平台)
  3. 指针是有类型,指针的类型决定了指针±整数的步长,指针解引用时候的权限。
  4. 指针的运算。

接下来,我们将继续探讨指针的高级主题。

1. 字符指针

在指针的类型中我们知道有一种指针类型位字符指针 char*
一般用法:

int main()
{
	char ch = 'w';
	char* pc = &ch;
	*pc = 'a';
	return 0;
}

还有一种使用方法:

int main()
{
	const char* pstr = "hello world";
	printf("%s\n", pstr);
	return 0;

  • 代码const char* pstr = "hello world"特别容易让初学者以为把字符串 hello world放到字符指针pstr里,但本质上是把字符串 hello world的首字符的地址放到了pstr中。

1.1 相关面试题

题目:

int main()
{
	char str1[] = "hello world";
	char str2[] = "hello world";
	const char *str3 = "hello world";
	const char *str4 = "hello world";

	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 atr4 are not same\n");
	return 0;
}

运行结果:
指针进阶详解(上),c语言,c++,学习方法
代码解读:

**这里str3和str4指向的是同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,实际上他们会指向同一块内存。
但是用相同的常量字符串去初始化不同的数组时会开辟不同的内存块。
所以str1和str2不同;str3和str4相同。

2. 指针数组

在指针初阶中我们已经介绍了指针数组,指针数组是一个存放指针的数组。
在这里我们在简单复习一下,下面数组是什么意思?

int* p1[10];  //整型指针的数组
char *arr2[4];//一维字符指针的数组
char** arr3[5]; //二级字符指针的数组

3. 数组指针

3.1 数组指针的定义

首先说明数组指针是指针。
我们已经熟悉:
整型指针:int * pint; 能够指向整型数据的指针。
浮点数指针:float * pf; 能够指向浮点型数据的指针。
那么数组指针应该是:能过指向数组的指针。

下面代码那个是数组指针?

int* p1[10];
int(*p2)[10];
  • 要明白上面两个类型其实很简单,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其优先级和运算优先级一样,所以我总结了一下其原则:从变量名处起,根据运算符优先级结合,一步一步分析.(字符串优先级博客链接)

解读:

int* p1[10];
//解释:从p1开始,由于[]的优先级高于*,p1先后[]结合,所以p1是一个数组。
//		然后在与*结合,说明数组中的元素是指针类型;在和int结合说明指针所指向的内容的类型是指针类型
//		所以p1是由一个返回整型数据的指针所组成的数组(p1为指针数组)

int(*p2)[10];
//解释:由于()的优先级高于[]。所以从p2开始,先和*结合说明p2是一个指针。
//		在和[]结合,说明指针所指向的内容是一个数组;在和int结合,说明数组中的每一个元素是整型类型
//		所以p2是指向一个由整型数据组成的数组的指针。(p2是一个数组指针)

3.2 &数组名VS数组名

对于下面的数组:

int arr[10];

arr和&arr分别是什啥?
我们知道arr是数组名,数组名表示首元素地址。那&arr数组名到底是什么呢?
我们先来看下面几段代码:

代码一:

int main()
{
	int arr[10] = { 0 };
	printf("%p\n", arr);
	printf("%p\n", &arr);
	return 0;
}

运行结果:
指针进阶详解(上),c语言,c++,学习方法
在上面这段代码中,数组名和&数组名打印的地址是一样的。
难道两个真是一样的吗?
我们再来看下面这段代码:

代码一:

int main()
{
	int arr[10] = { 0 };
	printf("arr=%p\n", arr);
	printf("&arr=%p\n", &arr);

	printf("arr+1=%p\n", arr + 1);
	printf("&arr+1=%p\n", &arr + 1);
	return 0;
}

运行结果:
指针进阶详解(上),c语言,c++,学习方法

对比上面两端代码我们发现虽然arr和&arr值是一样的,但意义不同。

实际上:&arr 表示的是数组的地址,而不是数组首元素的地址。
本例中 &arr 的类型是:int (*)[10],是一种数组指针类型。
数组的指针+1,跳过整个数组的大小,所以 &arr 相对于 arr 的差值为40。

3.3 数组指针的使用

介绍完数组指针,那数组指针如何使用呢?
既然数组指针指向的是数组,那数组指针中存放的应该就是数组的地址。

一个数组指针的使用:

//void print_arr(int arr[3][5], int row, int col)
void print_arr(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[3][5] = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13} };
	print_arr(arr, 3, 5);
	//数组名arr,表示首元素地址
	//但二维数组的首元素是二维数组的第一行
	//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址,可以使用一维数组来接受
	return 0;
}

运行结果:
指针进阶详解(上),c语言,c++,学习方法

3.4 数组和数组指针类型实例解读

学习了数组和数组指针,接下来我们来看看下面这些代码的意思:

int arr[5];
//解读:arr先和[]结合,说明arr是一个数组;在和int结合,说明数组中的元素是int类型。
//	   所以arr是由整型数据组成的数组
int *parr1[10];
//解读:parr1先和[]结合,说明pass1是一个数组;在和*结合,说明数组的元素是指针类型;最后和int结合,说明指针指向的内容的类型是整型。
//	   所以pass1是有一个返回整型数据的指针所组成的数组。
int (*parr2)[10];
//解读:parr2先和*结合,说明parr2是一个指针;在和[]结合,说明指针所指向的内容是一个数组;最后和int结合,说明数组中的元素是整型类型。
//	   所以parr2是一个指向由整型数据组成的数组的指针。
int (*parr3[10])[5];
//解读:parrr3先和先和[]结合,说明parr3是一个数组;在和*结合,说明数组的元素是指针类型;在和[]结合,说明指针指向的是一个数组;最后和int结合说明,数组中的元素类型是整型。
//	   所以parr3是一个由指向整型数组的指针组成的数组。

其他各种复杂数据类型和上面一样,根据操作符优先级一步步分析即可得到答案!!

4. 数组参数和指针参数

在写代码时,难免要把数组或指针传个函数,那么函数的参数该如何设计呢?

4.1 一维数组传参

void test(int arr[])//ok 形参写成一维数组形式,可以不用指定大小
{}
void test(int arr[10])//ok
{}
void test(int *arr)//ok
{}
void test2(int *arr2[10])//ok
{}
void test2(int** arr)//ok arr2的地址时,传的是首元素地址。而首元素的类型为int *也是一个地址。
{}                  //所以arr2传的是一个二级指针

int main()
{
	int arr[10] = { 0 };
	int* arr2[10] = { 0 };

	test(arr);
	test2(arr2);
	return 0;
}
  • 一维数组传参,形参部分可以是数组,也可以是指针。
  • 传一维数组地址其实本质上是传的是指针。虽然语法上可以写成数组形式,但这仅是C语言为方便初学者理解而设计的,俗称挂羊头卖狗肉,并不会真正带内存中开辟一块空间来存放数组,本质上还是一个指针。所以参数写成数组形式时,[ ]中不仅可以不说明大小,即使给1000也没关系。编译器在编译参数时,会把它识别为一个指针,而非数组。

4.2 二位数组传参

//参数为二维数组时,形参部分,行可以省略,列不行
void test(int arr[3][5])//ok
{}
void test(int arr[][])//error 
{}
void test(int arr[][5])//ok
{}

//二维数组传参,参数为指针时,指针为数组指针,类型为int (*)[5]
void test(int *arr)//error  
{}
void test(int *arr[5])//error
{}
void test(int (*arr)[5])//ok
{}

int main()
{
	int arr[3][5] = { 0 };
	test(arr);
	return 0;
}
  • 二维数组传参,形参部分可以是数组,也可以是指针。
  • 二维数组传参时,函数参数设计只能省略第一个[ ]中的数字。因为对于一个二维数组来说,数据在内存中时连续存放的,所以可以不知道有多少行,但必须知道每=一行有多少个元素。

4.3 一级指针传参

void print(int* p, int sz)
{
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}
}

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	print(p, sz);//一级指针p,传给函数
	return 0;
}
  • 一级指针传参时,参数只能是指针形式。

4.4 二级指针传参

void tesy(char **p)
{}

int main()
{
	char n = 10;
	char* p = &n;
	char** pp = &p;

	test(pp);
	test(&p);
	return 0;
}
  • 二级指针传参时,参数只能是指针形式。

5.结尾

本篇文章到此就结束了。创作不易,如果对你有帮助记得点赞加收藏哦!感谢您的支持!!文章来源地址https://www.toymoban.com/news/detail-558091.html

到了这里,关于指针进阶详解(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C语言进阶】⑥函数指针详解

    1.概念 函数指针 :首先它是一个指针,一个指向函数的指针,在内存空间中存放的是函数的地址; 请看示例: 解析:parr是一个指向数组的指针,存放的是数组的地址; 所以: 数组指针 —存放数组地址的指针; 数组名 —得到的就是数组的地址; 那么我们可以不可以这么认

    2024年02月02日
    浏览(37)
  • 新手小白学习SWAT模型【建模方法、实例应用、高级进阶】

    目录 第一部分:SWAT模型实践部分 第二部分:SWAT模型【进阶部分】 更多推荐 【专家】: 刘老师【副教授】,北京重点高校资深专家,和美国SWAT软件开发方长期合作,拥有丰富的科研及工程技术经验,长期从事流域面源污染模拟及控制等领域的研究,具有资深的技术底蕴和

    2024年02月15日
    浏览(59)
  • 【C语言】进阶指针,超详解,含丰富代码示例

    这里是初阶的链接,方便大家对照查看!!!添加链接描述 大家好呀,今天和大家将指针进阶的知识进行分享,这块是指针的难点部分,希望博主对其的理解可以帮助到大家!!! 字符指针 数组指针 指针数组 函数指针 函数指针数组 指向函数指针数组的指针 在指针的类型

    2024年02月13日
    浏览(40)
  • 【Python】进阶学习:一文掌握resize方法,轻松调整图像大小

    【Python】进阶学习:一文带你使用resize方法调整image对象的图像大小 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程👈 希望得到您的订阅和支持~ 💡 创作高质量博文(平均质量分92+),分享更多

    2024年04月25日
    浏览(67)
  • 【Python】进阶学习:__len__()方法的使用介绍

    【Python】进阶学习: __len__() 方法的使用介绍 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程👈 希望得到您的订阅和支持~ 💡 创作高质量博文(平均质量分92+),分享更多关于深度学习、PyTorc

    2024年03月14日
    浏览(41)
  • 【Go进阶】详解方法的值类型和指针类型区别

    目录 值类型和指针类型 方法也有值类型的方法和指针类型的区别 ,也就是以下两种receiver: setname()方法中是值类型的receiver,setage()方法中是指针类型的receiver。它们是有区别的。 首先,setage()方法的p是一个指针类型的person实例,所以方法体中的 p.age 实际上等价于 (*p).age 。

    2023年04月10日
    浏览(39)
  • C语言-指针进阶-qsort函数的学习与模拟实现(9.3)

    目录 思维导图: 回调函数 qsort函数介绍 模拟实现qsort 写在最后: 什么是回调函数? 回调函数是一个通过函数指针调用的函数。 将一个函数指针作为参数传递给一个函数,当这个指针被用来调用所指向函数时, 我们就将此称为回调函数。 在举例之前,我们先学习一个C语言

    2024年02月15日
    浏览(54)
  • R语言机器学习方法在生态经济学领域

    近年来,人工智能领域已经取得突破性进展,对经济社会各个领域都产生了重大影响,结合了统计学、数据科学和计算机科学的机器学习是人工智能的主流方向之一,目前也在飞快的融入计量经济学研究。表面上机器学习通常使用大数据,而计量经济学则通常使用较小样本,

    2024年02月11日
    浏览(54)
  • 基于R语言、MATLAB、Python机器学习方法与案例分析

    目录   基于R语言机器学习方法与案例分析 基于MATLAB机器学习、深度学习在图像处理中的实践技术应用 全套Python机器学习核心技术与案例分析实践应用   基于R语言机器学习方法与案例分析 机器学习已经成为继理论、实验和数值计算之后的科研“第四范式”,是发现新规律,

    2024年02月07日
    浏览(32)
  • 问题:以下选项中,( )是不正确的C语言字符型常量. #学习方法#媒体

    问题:以下选项中,( )是不正确的C语言字符型常量. A、\\\"a\\\" B、\\\'101\\\' C、\\\'x4l\\\' D、\\\'a\\\' 参考答案如图所示

    2024年02月20日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包