【C语言】深入解开指针(三)

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

  🌈write in front :

🔍个人主页 : @啊森要自信的主页

真正相信奇迹的家伙,本身和奇迹一样了不起啊!

欢迎大家关注🔍点赞👍收藏⭐️留言📝>希望看完我的文章对你有小小的帮助,如有错误,可以指出,让我们一起探讨学习交流,一起加油鸭。 【C语言】深入解开指针(三),我爱C语言,c语言,开发语言


前言

本小节,我们继续深入理解指针,阿森将在本小节带你理解数组名,怎么使用指针访问数组,一维数组传参的本质,冒泡排序的方法,还有我们的二级指针创建,指针数组的,生命,创建和运用。接下来让我们启程!


▶️、 数组名的理解

  1. %d:用于打印整数。
  2. %f:用于打印浮点数。
  3. %c:用于打印单个字符。
  4. %s:用于打印字符串。
  5. %p:用于打印指针地址。
  6. %x:用于以十六进制格式打印整数。
  7. %o:用于以八进制格式打印整数。
  8. %e:用于以科学计数法打印浮点数。
  9. %u:用于以无符号整数格式打印整数。

对于数组名,我们在学习函数的时候,我们就了解到数组名arr就是数组首元素的地址,当然也可以取地址数组首元素&arr[0].

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("&arr[0]=%p\n", &arr[0]);//数组首元素
	printf("arr=    %p\n", &arr);//数组名
	return 0;
}

运行结果:
【C语言】深入解开指针(三),我爱C语言,c语言,开发语言
我们看到运行结果可以看出数组名和数组首元素的地址一模一样。因此,数组名就是数组首元素(第一个元素)的地址

既然arr是是首元素的地址,那sizeof(arr)计算的也应该是计算的是数组首元素的大小,单位字节。那么他应该计算的是首元素的大小,也就是4或者8(因为分别是32位或64位环境),事实真的如此吗?

sizeof是一个运算符,用于获取数据类型或变量的大小(以字节为单位)。它的语法如下:

sizeof(type)
sizeof(variable)

其中,type可以是任何数据类型,比如int、char、float等,而variable可以是任何变量名。

sizeof返回的是一个size_t类型的值,表示对应类型或变量所占用的字节数。在实际编程中,sizeof经常用于在程序中动态计算数组的大小,或者确保在处理内存分配和复制时不会出现越界的情况。
【C语言】深入解开指针(三),我爱C语言,c语言,开发语言
其实不然,并没有打印我们想要的? 那这怎么解释呢?
输出的结果是:40,如果arr是数组⾸元素的地址,那输出应该的应该是4/8才对。
其实数组名就是数组⾸元素(第⼀个元素)的地址是对的,但是有两个例外:

  • 1️⃣ sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰(整个数组),计算的是整个数组的⼤⼩,单位是字节
  • 2️⃣ &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素的地址是有区别的)
    除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。
    【C语言】深入解开指针(三),我爱C语言,c语言,开发语言
#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d\n", sizeof(arr));
	printf("%p\n", &arr[0]);
	printf("%p\n", arr);
	printf("%p\n", &arr);
	return 0;
}

运行结果:
【C语言】深入解开指针(三),我爱C语言,c语言,开发语言
打印结果⼀模⼀样,这时候⼜纳闷了,那arr&arr有啥区别呢?

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	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);
	printf("&arr =      %p\n", &arr);
	printf("&arr+1 =    %p\n", &arr + 1);
	return 0;
}

【C语言】深入解开指针(三),我爱C语言,c语言,开发语言
这⾥我们发现&arr[0]&arr[0]+1相差4个字节,arr和arr+1 相差4个字节,是因为&arr[0] 和 arr 都是⾸元素的地址,+1就是跳过⼀个元素。
但是&arr&arr+1相差40个字节,这就是因为&arr是数组的地址,+1 操作是跳过整个数组的。
在C语言中,arr&arr有着不同的含义和用法。

  1. arr:表示数组的名称,它代表数组的首元素的地址。在大多数情况下,当使用数组名arr时,它会被隐式转换为指向数组第一个元素的指针。因此,arr表示的是数组的地址,而不是整个数组的内容。

  2. &arr:表示对整个数组的取地址操作。它得到的是整个数组的地址,而不是数组的第一个元素的地址。因此,&arr表示的是整个数组的地址,而不是数组的内容。

总结来说,arr表示数组的首元素地址,而&arr表示整个数组的地址。在大多数情况下,当我们需要传递数组给函数时,实际上传递的是数组的首元素地址,因此arr&arr在传递参数时的用法可能会有所不同。

▶️、 使⽤指针访问数组

知道了数组名,数组的地址,那我们不就可以用指针访问数组了,遍历数组的元素了,好接下来,启动!

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	//输⼊
	int i = 0;//整个数组大小40/单个数组字节4=10
	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组元素个数
	//输⼊
	int* p = arr;
	printf("请输入数组元素:\n");
	for (i = 0; i < sz; i++)
	{
		/*scanf("%d", p + i);*///p每一次移动 i 个地址
		scanf("%d", arr+i);//既然数组名是首元素地址,理所应当也可以这样写
		//scanf("%d", &arr[0] + i);//那第一个地址也可以
	}
	//输出
	printf("输出:\n");
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));//解引找到指针变量的空间的值进行访问
	}
	return 0;
}

每个都进行验证一下:

  1. 数组名访问地址

【C语言】深入解开指针(三),我爱C语言,c语言,开发语言

  1. 数组首元素地址访问

【C语言】深入解开指针(三),我爱C语言,c语言,开发语言
3. 使用指针访问数组
【C语言】深入解开指针(三),我爱C语言,c语言,开发语言

  • ⚠️ 这段代码弄清楚后,我们再试一下,如果我们再分析一下,数组名arr是数组首元素的地址,可以赋值给p,其实数组名arrp在这里是等价的。那我们可以使用arr[i]可以访问数组的元素,p[i]是否也可以访问数组呢?测试一下!

【C语言】深入解开指针(三),我爱C语言,c语言,开发语言

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	//输⼊
	int i = 0;//整个数组大小40/单个数组字节4=10
	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组元素个数
	//输⼊
	int* p = arr;
	printf("请输入数组元素:\n");
	for (i = 0; i < sz; i++)
	{
		/*scanf("%d", p + i);*///p每一次移动 i 个地址
		scanf("%d", arr+i);//既然数组名是首元素地址,理所应当也可以这样写
		//scanf("%d", &arr[0] + i);//那第一个地址也可以
	}
	//输出
	printf("输出:\n");
	for (i = 0; i < sz; i++)
	{
		printf("%d ", i[arr]);//这样子是否也可以呢?
		printf("%d ", i[p]);//
	}
	return 0;
}

【C语言】深入解开指针(三),我爱C语言,c语言,开发语言
哎,为什么i[arr]可以打印,其实i[p]也可以打印

  1. 在C语言中,数组名和指针的运算符[]是可以互换使用的。这是因为在C语言中,a[b]*(a + b)是等价的,即数组下标运算和指针运算是等效的。当然,如果你不太明白,可以尝试使用交换律来理解
 *(i+arr)-->*(arr+i)-->arr[i]
 
 arr[i] == *(arr+i)
 *(i+arr) == i[arr]
 p[i] == *(p+i)
  1. 因此,当你使用i[arr]时,它实际上等同于arr[i]。这是因为arr本身就代表数组的首元素地址,而i[arr]会被解释为*(arr + i),即数组首元素地址加上偏移量i,得到第i个元素的地址。同样,i[p]也等同于p[i],因为指针p也可以进行类似的偏移量运算。
  2. 虽然i[arr]i[p]在语法上是合法的,但通常不推荐这样的写法,因为它会增加代码的可读性和理解难度。更好的做法是直接使用arr[i]p[i],这样可以更清晰地表达代码的意图。

➡️、⼀维数组传参的本质

首先,让我们从一个问题开始。我们之前一直在函数外部计算数组的元素个数,但是我们能否将函数传递给另一个函数,在函数内部计算数组的元素个数呢?

void test(int arr[])//int* arr
{					//4/4
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d\n", sz);//
}


int main()
{
	//数组传参的时候,传递的是并非是数组
	//传递的是数组首元素的地址
	int arr[12] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	int sz = sizeof(arr) / sizeof(arr[0]);

	test(arr);//这里的数组名就是数组首元素的地址

	return 0;
}
  1. 环境下debug,x86环境下,结果为1.

【C语言】深入解开指针(三),我爱C语言,c语言,开发语言

  1. 环境下debug,x64环境下,结果为2.

【C语言】深入解开指针(三),我爱C语言,c语言,开发语言
分析:

  • 当数组作为函数参数进行传递时,实际上传递的是数组的首元素地址,而不是整个数组。因此,在函数内部,无法通过sizeof操作符来获取数组的大小,因为此时的arr已经退化为指针

  • 在代码中,test函数的参数arr实际上是一个指针,因此在函数内部使用sizeof(arr)并不能得到数组的大小,而是得到指针的大小。因此,在32位环境下(x86),指针的大小为4字节,所以sizeof(arr) / sizeof(arr[0])的结果为1。(同理64位,指针大小字节为8字节)
    【C语言】深入解开指针(三),我爱C语言,c语言,开发语言

数组名是数组首元素的地址;因此在数组传参时,传递的是数组名,也就是说本质上数组传参本质上传递的是数组首元素的地址。

⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。
【C语言】深入解开指针(三),我爱C语言,c语言,开发语言

➡️、⼆级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪⾥?

在C语言中,二级指针是指一个指针变量,它存储的是另一个指针变量的地址。换句话说,它指向一个指针变量,而这个指针变量又指向某个数据的地址。在C语言中,我们通常使用二级指针来处理动态内存分配和多级数据结构。

下面是一个简单的示例,演示了如何声明和使用二级指针:

#include <stdio.h>

int main() {
    int num = 10;
    int *ptr1 = &num; // 一级指针,指向int类型的数据
    int **ptr2 = &ptr1; // 二级指针,指向int*类型的数据

    // 通过二级指针访问num的值
    printf("Value of num: %d\n", **ptr2);

    return 0;
}

在这个示例中,ptr1是一个一级指针,它指向一个整数类型的数据numptr2是一个二级指针,它指向一个一级指针ptr1。通过**ptr2可以访问num的值。

二级指针在C语言中通常用于动态内存分配,例如在使用malloc函数分配内存时,可以返回一个指向指针的指针,以便在程序中对内存进行操作。此外,在处理多级数据结构(如多级指针数组或多级链表)时,二级指针也非常有用。
举个简单的例子:

int main()
{
	int a = 10;
	int* p = &a;//取出a的地址
	//p是指针变量,是一级指针
	int * * pp = &p;//pp是二级指针
	return 0;
}

【C语言】深入解开指针(三),我爱C语言,c语言,开发语言

对于⼆级指针的运算有:
• *ppa 通过对ppa中的地址进⾏解引⽤,这样找到的是 pa , *ppa 其实访问的就是 pa .

int b = 20;
*ppa = &b;//等价于 pa = &b;

• **ppa 先通过 *ppa 找到 pa ,然后对 pa 进⾏解引⽤操作: *pa ,那找到的是 a .

**ppa = 88;
//等价于*pa = 88;
//等价于a = 88;

【C语言】深入解开指针(三),我爱C语言,c语言,开发语言

🔼、指针数组

指针数组是指针还是数组?
我们类⽐⼀下,整型数组,是存放整型的数组,字符数组是存放字符的数组。
那指针数组呢?是存放指针的数组。

在C语言中,指针数组是一个数组,其中的每个元素都是一个指针。这意味着每个数组元素都存储着另一个变量的地址,而这个变量可以是任何类型的数据,包括整数、浮点数、字符,甚至是其他指针。

下面是一个简单的示例,演示了如何声明和使用指针数组:

#include <stdio.h>

int main() 
{
    int num1 = 10, num2 = 20, num3 = 30;
    int *ptrArr[3]; // 声明一个包含3个指针的数组

    ptrArr[0] = &num1; // 将num1的地址存储在数组的第一个元素中
    ptrArr[1] = &num2; // 将num2的地址存储在数组的第二个元素中
    ptrArr[2] = &num3; // 将num3的地址存储在数组的第三个元素中

    // 通过指针数组访问num1、num2和num3的值
    printf("Value of num1: %d\n", *ptrArr[0]);
    printf("Value of num2: %d\n", *ptrArr[1]);
    printf("Value of num3: %d\n", *ptrArr[2]);

    return 0;
}

在这个示例中,ptrArr是一个包含3个指针的数组。每个数组元素都存储着一个整数类型变量的地址。通过ptrArr[i]可以访问第i个元素所指向的变量。

【C语言】深入解开指针(三),我爱C语言,c语言,开发语言

int main()
{
	//char ch = 'w';
	//char* pc = &ch;//pc就是字符指针

	const char* p = "abcdef";//不是把字符串abcdef\0存放在p中,而是把第一个字符的地址存放在p中
	//printf("%c\n", *p);//
	//1. 你可以把字符串想象为一个字符数组,但是这个数组是不能修改的
	//2. 当常量字符串出现在表达式中的时候,他的值是第一个字符的地址

	printf("%c\n", "abcdef"[3]);
	printf("%c\n", p[3]);
	//p[3] = 'q';//err

	return 0;
}

在C语言中,字符指针数组是一个数组,其中的每个元素都是一个指向字符的指针。这种数组通常用于存储字符串数组,其中每个元素指向一个以null结尾的字符数组。

下面是一个简单的示例,演示了如何声明和使用字符指针数组:

#include <stdio.h>

int main() {
    char *strArr[3]; // 声明一个包含3个字符指针的数组

    strArr[0] = "Hello"; // 将指向字符串"Hello"的指针存储在数组的第一个元素中
    strArr[1] = "World"; // 将指向字符串"World"的指针存储在数组的第二个元素中
    strArr[2] = "C";     // 将指向字符串"C"的指针存储在数组的第三个元素中

    // 通过字符指针数组访问存储的字符串
    printf("String 1: %s\n", strArr[0]);
    printf("String 2: %s\n", strArr[1]);
    printf("String 3: %s\n", strArr[2]);

    return 0;
}

在这个示例中,strArr是一个包含3个字符指针的数组。每个数组元素都存储着一个指向以null结尾的字符数组的指针。通过strArr[i]可以访问第i个元素所指向的字符串。

但是也有例外
比如这个代码:


int main()
{


  //char ch = 'w';
  //char* pc = &ch;//pc就是字符指针
	const char* p = "abcdef";//不是把字符串abcdef\0存放在p中,而是把第一个字符的地址存放在p中
	//printf("%c\n", *p);
//1. 你可以把字符串想象为一个字符数组,但是这个数组是不能修改的
//2. 当常量字符串出现在表达式中的时候,他的值是第一个字符的地址

printf("%c\n", "abcdef"[3]);
printf("%c\n", p[3]);
//p[3] = 'q';//err

return 0;
}

【C语言】深入解开指针(三),我爱C语言,c语言,开发语言

如果强行修改,他就会报错:
【C语言】深入解开指针(三),我爱C语言,c语言,开发语言


🅿️总结

本小节我们的学习总结:

1️⃣. 数组名的理解:

  • 数组名实际上是指向数组第一个元素的指针。在大多数情况下,数组名可以被解释为指向数组首元素的指针常量。
  • 例如,对于int arr[5]arr可以被视为指向arr[0]的指针。

2️⃣. 使用指针访问数组:

  • 数组名可以被解释为指向数组首元素的指针,因此可以使用指针算术或指针解引用来访问数组元素。
  • 例如,*(arr + i)或者arr[i]都可以用来访问数组arr的第i个元素。

3️⃣. 一维数组传参的本质:

  • 在C语言中,当将数组传递给函数时,实际上传递的是数组的首元素的地址。
  • 因此,函数参数声明中的数组形参实际上被解释为指向数组首元素的指针。

4️⃣. 二级指针:

  • 二级指针是指向指针的指针。它们用于处理指针的指针,通常用于动态内存分配和多级数据结构。
  • 例如,int **ptr是一个指向指向整数的指针的指针。

5️⃣. 指针数组:

  • 指针数组是一个数组,其中的每个元素都是一个指针。这些指针可以指向不同类型的数据,包括其他指针。
  • 例如,int *ptrArr[5]是一个包含5个整数指针的数组。

感谢你的收看,如果文章有错误,可以指出,我不胜感激,让我们一起学习交流,如果文章可以给你一个帮助,可以给博主点一个小小的赞😘文章来源地址https://www.toymoban.com/news/detail-754620.html

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

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

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

相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    2024年02月10日
    浏览(43)
  • C语言之指针篇【超详细讲解,带你层层深入理解指针】

    目录 一、关于指针 二、指针类型 1、整型指针的访问权限说明: 2、字符指针的访问权限说明: 3、指针的类型决定向前或向后一步走了多大距离 三、野指针相关知识 1、野指针的成因 ①指针未初始化 ②指针的越界访问 ③指针所指向的空间释放了 2、如何规避野指针 ①指针

    2024年02月02日
    浏览(39)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包