【C语言】指针的入门篇2,深入理解指针和数组的关系

这篇具有很好参考价值的文章主要介绍了【C语言】指针的入门篇2,深入理解指针和数组的关系。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

欢迎来CILMY23的博客喔,本期系列为【C语言】指针的入门篇2,深入理解指针和数组的关系,图文讲解指针和数组关系的知识,带大家理解指针和数组的关系,以及指针+数组的用法,感谢观看,支持的可以给个赞哇。

前言

在上一篇博客中,我们了解了指针就是地址,并且把地址存放的变量叫做指针变量,以及指针用法,并且为了防止野指针,我们还学习了assert断言等等来防止野指针的产生,本期博客将用strlen函数的模拟实现来回顾先前知识,并学习指针和数组之间的关系。 

目录

 一、strlen的模拟实现

 二、数组名和数组首元素

二、指针访问数组 

三、一维数组的传参

 四、冒泡排序

五、二级指针

六、指针数组

七、指针数组模拟二维数组


 一、strlen的模拟实现

strlen函数,我们可以在cplusplus网站查询cplusplus.comhttps://cplusplus.com/

【C语言】指针的入门篇2,深入理解指针和数组的关系,C语言,c语言,开发语言

它的功能是获取字符串的长度,返回字符串的长度。那字符串的特点是在“”的末尾有一个\0,所以我们可以采取计数的方式来统计字符串的长度。所以我们可以写出以下代码:

int my_strlen(char* str)
{
	int len = 0;
	while (*str != '\0')
	{
		len++;
		str++;
	}
	return len;
}
int main()
{
	char str[] = "hello SILMY23";
	printf("%d",my_strlen(str));
	return 0;
}

 我们可以看到结果:

 【C语言】指针的入门篇2,深入理解指针和数组的关系,C语言,c语言,开发语言

但当我们在模拟实现的时候,往往可以发现一些问题,如果外界传入的是空指针呢?其次我们并不希望修改指针所指向的内容,因此可以加const修饰我们的形参str。 因为assert检测的时候,如果表达式为真,就不影响程序,如果为假,就停止程序并进行报错。最后,因为字符串长度是不可能有负数的,所以我们可以用size_t来代替int。

#include<stdio.h>
#include<assert.h>

size_t my_strlen(const char* str)
{
	assert(str);
	int len = 0;

	while (*str != '\0')
	{
		len++;
		str++;
	}
	return len;
}

int main()
{
	char str[] = "hello SILMY23";
	printf("%d",my_strlen(str));

	return 0;
}

 这样一个strlen字符函数的模拟实现就完成了,当然主体我们也可以不采取计数的方式,可以采取指针-指针的写法。

让一个指针找到尾巴,然后利用指针相减指针是元素的个数,返回指针减去指针就可以了。前提是仍然需要对str断言,如果str不为空我们再赋值给tail指针。

#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
	assert(str);
	const char* tail = str;
	while (*tail != '\0')
	{
		tail++;
	}
	return tail - str;
}
int main()
{
	char str[] = "hello SILMY23";
	printf("%d",my_strlen(str));
	return 0;
}

 二、数组名和数组首元素

在上一篇文章中,我们用了以下代码

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

我们发现在用指针访问数组的时候,我把数组名赋值给了指针,那是否意味着所有情况下的数组名都是数组首元素的地址呢?

我们接下来看以下代码:

#include<stdio.h>

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);

	printf("%d ", sizeof(arr));
	printf("%d ", sizeof(arr[0]));

	return 0;
}

我们发现结果是40 4,那说明并不是所有情况下的数组名都是数组首元素的地址。

数组名就是数组首元素的地址,但是有两个例外:

1.sizeof(),在sizeof的关键字后面单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小, 单位是字节。

2.&arr,这里表示的也是整个数组,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)

那arr,&arr,&arr[0]的联系和区别又在哪里呢?我们看以下代码:

#include<stdio.h>

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };

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

 结果如下:

 【C语言】指针的入门篇2,深入理解指针和数组的关系,C语言,c语言,开发语言

  我们看指针走的步长是指针类型,前四个反应的是arr和&arr[0],几乎无差别,而最后一个&arr它所走的空间大小是整个数组的大小。

二、指针访问数组 

 在上一篇文章我们初步写了指针访问数组,并打印数组的值,那如果我们想要输入呢?


#include<stdio.h>

int main()
{
	int arr[10] = {0};
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* p = arr;
	for (int i = 0; i < sz; i++)
	{
		scanf("%d", p + i);
	}
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}

	return 0;
}

当我们输入1 -10的时候,打印的也是如此。

 【C语言】指针的入门篇2,深入理解指针和数组的关系,C语言,c语言,开发语言

当编译器处理的时候,打印的时候,其实arr[i] == *(arr+i), 它们之间是等价的。同时我们也可以写成p[i] == *(p+i)

甚至可以写成以下形式

arr[i]  == *(arr+i) == *(i+arr) == i[arr],感兴趣的读者可以自己敲一下验证验证

三、一维数组的传参

 我们看以下代码:

#include<stdio.h>

void print(int arr[])
{
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}

}

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10};
	print(arr);
	return 0;
}

【C语言】指针的入门篇2,深入理解指针和数组的关系,C语言,c语言,开发语言

当我们运行之后发现,结果并没有像我们预期的那样打印出1到10,而是只打印了1.这就涉及一维数组传参的本质了,一维数组传参实际上传入的是数组首元素地址,所以在函数内部计算sz的时候,sizeof(arr)是计算了指针变量的大小,四个字节,而后面计算出的也是四个字节,最后sz只计算出了1。 

 所以要修改代码我们可以在没有传参之前把数组长度计算出来,然后去传参,arr[]它实际还是指针变量,所以我们可以写成int *p.

void print(int *p,int sz)
{
	int i = 0;
	for (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 sz = sizeof(arr) / sizeof(arr[0]);
	print(arr,sz);
	return 0;
}

 四、冒泡排序

冒泡排序作为练习我也写过这篇啦,可以跳转细看,这里我粗略讲解练习。

冒泡排序,假设有一个数组,我们需要把一个有序数组排序为升序。其核心思想是两两相邻的元素进行交换。

五、二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里呢?再存放在一个指针里,这就是二级指针

#include<stdio.h>

int main()
{
	int a = 10;
	int* pa = &a;
	int** ppa = &pa;
	
	printf("%p\n", &a);
	printf("%p\n", &pa);
	printf("%p\n", &ppa);
	return 0;
}

在以上代码中,a是整型变量,占据四个字节的空间,pa和ppa都是指针变量,占据4或者八个字节的空间,a,pa,ppa三个变量都有对应的地址。 我们把pa叫做一级指针,ppa叫做二级指针。

【C语言】指针的入门篇2,深入理解指针和数组的关系,C语言,c语言,开发语言 

 【C语言】指针的入门篇2,深入理解指针和数组的关系,C语言,c语言,开发语言

如果我们要通过ppa找到a,我们就需要两层的解引用, 

 【C语言】指针的入门篇2,深入理解指针和数组的关系,C语言,c语言,开发语言

六、指针数组

 什么是指针数组呢?我们回想一下,整型数组是用来存放整型数据的,字符数组是用来存放字符的,所以指针数组就是用来存放指针的。

#include<stdio.h>

int main()
{
	int a = 10;
	int* arr[] = { &a };
	printf("%d ", *arr[0]);
	return 0;
}

我们开辟一个指针数组来存放a的地址,我们需要对数组元素解引用来获得a的值。 

【C语言】指针的入门篇2,深入理解指针和数组的关系,C语言,c语言,开发语言 

七、指针数组模拟二维数组

假设我们现在有三个数组,arr1,arr2,arr3,我们将它放到指针数组parr中,我们在用parr[]的时候,得到的是三个数组的地址,再对其解引用,我们就得到三个数组中具体的数值。 

#include<stdio.h>

int main()
{
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[5] = { 2,3,4,5,6 };
	int arr3[5] = { 3,4,5,6,7 };
	int* parr[3] = { arr1,arr2,arr3 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", parr[i][j]);
		}
		printf("\n");
	}

	return 0;
}

结果如下: 

【C语言】指针的入门篇2,深入理解指针和数组的关系,C语言,c语言,开发语言 

这就是指针数组的用法。 上述代码的分布图如下:

【C语言】指针的入门篇2,深入理解指针和数组的关系,C语言,c语言,开发语言 

感谢各位同伴的支持,本期指针入门篇2就讲解到这啦,如果你觉得写的不错的话,可以给个赞,若有不足,欢迎各位在评论区讨论。 文章来源地址https://www.toymoban.com/news/detail-830442.html

到了这里,关于【C语言】指针的入门篇2,深入理解指针和数组的关系的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 深入理解指针——C语言

    在讲内存和地址之前,我们想有个生活中的案例: 假设有⼀栋宿舍楼,把你放在楼里,楼上有100个房间,但是房间没有编号,你的⼀个朋友来找你玩,如果想找到你,就得挨个房子去找,这样效率很低,但是我们如果根据楼层和楼层的房间的情况,给每个房间编上号,如:

    2024年03月14日
    浏览(65)
  • 深入理解指针(c语言)

    可以使用指针来访问数组元素。例如,可以声明一个指针变量并将其指向数组的第一个元素,然后通过递增指针的方式来访问数组的其他元素: 输出结果: 在C语言中, 数组名有时代表数组中首元素的地址,有时代表整个数组 ,视情况而定。 1、数组首元素的地址 例1: 定义

    2024年02月22日
    浏览(36)
  • C语言——深入理解指针(3)

    目录 1. 字符指针 2. 数组指针 2.1 数组指针变量 2.2 数组指针变量的初始化 3.二维数组传参(本质) 4. 函数指针 4.1 函数指针变量的创建 4.2 函数指针的使用 4.3 typedef  5. 函数指针数组 6. 转移表(函数指针数组的使用) 在指针的类型中有一种指针类型为字符指针  char*    举例

    2024年02月05日
    浏览(50)
  • 【C语言:深入理解指针二】

    我们知道,指针变量也是变量,它也有自己的地址,使用什么来存放它的地址呢?答案是:二级指针。 关于二级指针的运算 *pp先解引用,对pp中的地址进行访问,访问的就是p **pp, 先通过*pp找到p,再对p进行解引用,访问的就是a 指针数组,顾名思义,它应该是一个数组,是用

    2024年02月04日
    浏览(105)
  • 【C语言】指针篇-深入探索数组名和指针数组- 必读指南(2/5)

    🌈个人主页:是店小二呀 🌈C语言笔记专栏:C语言笔记 🌈C++笔记专栏: C++笔记 🌈喜欢的诗句:无人扶我青云志 我自踏雪至山巅 在数组篇章,我们得到一个结论: 数组名是首元素的地址 验证环节 : 问题 :既然数组名是首元素的地址,那么为什么下面输出却不是预想的结果呢

    2024年04月28日
    浏览(24)
  • 【C语言基础】:深入理解指针(三)

    指针系列回顾 : 【C语言基础】:深入理解指针(一) 【C语言基础】:深入理解指针(二) 一、冒泡排序 冒泡排序的核心思想就是:两两相邻的元素进行比较。 可以看到,这段代码对arr数组进行了排序,但这个代码还有一些缺陷,那就是无论数组内部的元素是否有序,他都会循

    2024年03月10日
    浏览(35)
  • C语言——从头开始——深入理解指针(1)

     一.内存和地址 我们知道计算上CPU(中央处理器)在处理数据的时候,是通过地址总线把需要的数据从内存中读取的,后通过数据总线把处理后的数据放回内存中。如下图所示: 计算机把内存划分为⼀个个的 内存单元 ,每个内存单元的大小取1个字节( 1个字节(Byte)=8个比特

    2024年02月21日
    浏览(42)
  • C语言深入理解指针(非常详细)(一)

    在将内存和地址时我们先举一个生活中的例子: 假设有⼀栋宿舍楼,把你放在楼里,楼上有100个房间,但是房间没有编号,你的⼀个朋友来找你玩, 如果想找到你,就得挨个房子去找,这样效率很低,但是我们如果根据楼层和楼层的房间的情况,给每个房间编上号,如: 有

    2024年02月10日
    浏览(33)
  • C语言深入理解指针(非常详细)(二)

    指针的基本运算有三种,分别是: • 指针±整数 • 指针-指针 • 指针的关系运算 因为数组在内存中是连续存放的,比如int类型的数组,每个元素相差4个字节,因此我们只需要知道首元素的地址就可以通过加减的方式找到后面元素的地址 。 概念:野指针就是指针指向的位置

    2024年02月10日
    浏览(37)
  • C语言深入理解指针(非常详细)(四)

    字符指针在之前我们有提到过,(字符)(指针)前面的字符代表着存储的元素为字符类型,而指针则是表示这存储的方式。 写法为char * 一般使用的方式如下: 还有一种使用方式如下: 值得注意的是: 代码 const char pstr = “hello jack.”; 特别容易以为是把字符串 hello jack 放到

    2024年02月09日
    浏览(34)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包