目录
🤩前言🤩:
一、字符指针🤯:
1.字符指针的使用🦝:
2.常量字符串🦊:
3.相关面试题分析🐣:
二、指针数组🧐:
三、数组指针🤠:
1.数组指针的定义🦌:
2.&数组名VS数组名🦏:
3.数组指针的使用🦨:
四、总结🥳:
🛰️博客主页:✈️努力学习的銮同学
🛰️欢迎关注:👍点赞🙌收藏✍️留言
🛰️系列专栏:💐【进阶】C语言学习
🏡🏡本文重点 🏡🏡:
🚅 字符指针 🚃 指针数组 🚃 数组指针 🚏🚏
🤩前言🤩:
在之前的初阶学习中,相信各位小伙伴们已经对指针有了相当的了解。那么从今天开始,我们将继续探讨指针的更高级主题,希望对大家的学习能够有所帮助!
一、字符指针🤯:
1.字符指针的使用🦝:
在一众指针类型中,我们知道存在着字符指针这种类型,并且我们一般这样去使用它:
int main()
{
//第一种形式:
char ch = 'w';
char* pc = &ch;
*pc = 'w';
printf("%c\n", *pc);
//第二种形式:
const char* pstr = "hello bit.";
//这里不是把一个字符串放到pstr指针变量里
///其本质是把字符串 hello bit.的首字符的地址放到了pstr中,即将一个常量字符串的首字符' h '的地址存放到指针变量 pstr 中。
printf("%s\n", pstr);
return 0;
}
这里第二种用法的本质是把常量字符串 ' hello bit. ' 的首字符 ' h ' 的地址放到了pstr中。
2.常量字符串🦊:
并且我们要注意,上面说到的常量字符串作为常量,它们不可被修改:
int main()
{
char* p = "abcdef";
//使指针指向常量区的常量字符串abcdef
*p = 'A';
//按照我们的理解,*p中存放的是首元素a的地址,我们尝试改变它
//我们运行起来发现无法完成编译运行,程序会直接卡住
//于是我们可以得出,当使用常量字符串时,常量字符串abcdef不可修改
return 0;
}
这些常量字符串中的常量字符,是原本就储存在常量区(只读数据区)的一些常量,不同于需要我们输入的字符变量。所以当使用字符指针直接指向常量字符串时,可以直接进行调用但无法对其进行修改。
当出现这种错误时,程序往往是可以正常编译运行但会卡住而得不出结果,我们往往很难发现问题的所在,会给我们的代码书写造成很大的困扰。为了尽可能的避免这种情况的发生,我们通常在指向常量字符串时,使用 const 对指针变量进行修饰,进行这样的书写操作之后,当我们试图对常量字符串进行改动时,将会直接报错而无法进行编译运行, 便于我们找到问题的所在:
3.相关面试题分析🐣:
我们再来看下面这道经典的面试题:
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;
}
这道面试题中定义了两个字符型数组和两个字符型指针变量,将两个字符型数组进行对比,又将两个字符型指针变量尽行了对比,目的是为了验证它们在存储时内存的开辟。
这里 str3 和 str4 指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域(在我们的内存中存在着常量区用于存放一些常量),当几个指针指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4不同:
二、指针数组🧐:
在前面我们已经学习过的的《初阶指针》章节中,我们已经对指针数组有了一定程度的了解和认识。这里我们仅做回顾。
在之前的学习中我们都知道,指针数组的本质是数组,是用于存放指针变量的数组:
int main()
{
//创建变量:
int a = 1;
int b = 2;
int c = 3;
//创建指针数组,用于存放指针(即变量的地址):
int* arr[3] = { &a,&b,&c };
//打印验证内容:
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%p\n", arr[i]);
}
//也可以通过指针数组(存放的是各个变量的地址)来访问变量内容:
for (i = 0; i < 3; i++)
{
printf("%d\n", *(arr[i]));
}
return 0;
}
以上这是我们所知道的,所学习过的最普通的使用方式,而我们以后在工作中更常用的却是另外一种情况:
int main()
{
//创建数组:
int arr1[3] = { 1,2,3 };
int arr2[3] = { 4,5,6 };
int arr3[3] = { 7,8,9 };
//创建指针数组:
int* parr[3] = { arr1,arr2,arr3 };
//我们都知道,数组名即为数组内首元素地址
//即此处的数组名为地址,故可以存放在指针变量内
//验证指针数组内存放数据:
int i = 0;
for (i = 0; i < 3; i++)
{
printf("整型数组arr%d[3]首元素地址为:%p\n", i + 1, parr[i]);
}
printf("\n");
//通过指针数组访问整型数组内的数据:
for (i = 0; i < 3; i++)
{
printf("arr%d[3]中存储的数据为:", i + 1);
int j = 0;
for (j = 0; j < 3; j++)
{
printf("%d ", *(parr[i] + j));
}
printf("\n");
}
return 0;
}
要注意的是,这样的形式与前面的基础示例存储和访问原理完全相同。
三、数组指针🤠:
1.数组指针的定义🦌:
各位小伙伴们千万千万区别于指针数组,数组指针的本质是指针。不同于其他指针,数组指针指向的不是地址而是数组:
int main()
{
int* p1[10];
//p1是数组,数组指针
int(*p2)[10];
//p2是指针。数组指针
return 0;
}
上面的示例中,p2先和*进行结合,说明p2是一个指针变量,再指向大小为10的整型数组。即p2是一个指向数组的指针,叫做数组指针。简单来说,数组指针就是专门用来存放一个数组的地址的指针。
2.&数组名VS数组名🦏:
我们都知道,除一些特殊情况外,大多数的数组名都表示数组首元素的地址,那么既然数组名已经是地址了,&+数组名的组合又代表着什么呢?我们来看一段代码:
int main()
{
int arr[5] = { 0 };
printf("arr :%p\n", arr);
printf("&arr:%p\n", &arr);
return 0;
}
我们如果通过打印,会发现 arr 的打印结果与 &arr 相同:
难道它们真的是一回事吗?那么 &arr 的存在又有什么意义呢?
我们说,不是这样的,arr 与 &arr 不一样。我们将上面这段代码进行改写:
int main()
{
int arr[5] = { 0 };
printf("arr :%p\n", arr);
printf("&arr:%p\n", &arr);
printf("\n");
printf("arr+1 = %p\n", arr + 1);
printf("&arr+1= %p\n", &arr + 1);
return 0;
}
我们使 arr 与 &arr 同时向后走一步,这时我们看到了不一样的结果:
实际上,&arr 表示的是整个数组的地址,而 arr 仅表示其中首元素的地址,这就导致了我们在使它们在向后走的时候,它们向后走的步幅不同,&arr 跨过了整个数组的长度而 arr 仅仅只跳过了一个数据元素。
3.数组指针的使用🦨:
在上面的介绍中,我们看到了数组指针的最基础用法:
int arr[10] = { 0 };
int (*p2)[10] = &arr;
但是事实上,我们在真正的工程项目中却很少会这样去使用它。更多的是在我们进行函数调用,进行数组传参时,可以通过数组指针来进行接收:
void print_arr1(int arr[3][5], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("%02d ", arr[i][j]);
}
printf("\n");
}
}
//使用数组指针来进行接收:
void print_arr2(int(*arr)[5], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("%02d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
print_arr1(arr, 3, 5);
//数组名arr,表示首元素的地址
//但是二维数组的首元素是二维数组的第一行,所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
printf("\n");
//可以使用数组指针来进行接收:
print_arr2(arr, 3, 5);
return 0;
}
我们很明显可以看到,
四、总结🥳:
今天我们对指针的知识又有了新的了解,只要大家踏实肯学,我相信到最后,所有的小伙伴都一定会有所收获、有所成就,也衷心的祝愿各位小伙伴们在不久的将来能够拿到一份让自己满意的大厂offer🎉🎉
😠😠有一种落差是,你配不上自己的野心,也辜负了所受的苦难!!!😠😠
辛苦各位小伙伴们动动小手,三连走一走 ~ ~ ~ 最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!