指针的学习又开始辣~ 大家也要保持好乐观的心态哦
继续加油!!!
我的主页:optimistic_chen
我的专栏:c语言
点击主页:optimistic_chen和专栏:c语言,欢迎大家访问我的其他博客,希望有所帮助
前言
经过上一篇博客的学习,我们已经初步了解了指针的相关概念(快速理解指针原理!!!),这篇博客将深入学习指针与数组的”恩怨“,一起来吧。
文章目录
一、指针与数组的关系
我们知道指针就是地址,地址就存放在指针变量中,但是,这又与数组有什么关系?
这就到了这篇博客的重点之一:使用指针访问数组。
1.数组名的理解
之前写过一篇只针对数组的博客,感兴趣的大佬可以看看:浅浅理解c语言之数组大佬
通常我们使用取地址操作符(&)获得我们所需要的地址,但是针对数组名我们可以做一个实验:
代码示例:
#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);//整个数组地址
printf("arr = %p\n", arr);//数组名
return 0;
}
大胆猜测一下,输出结果会是怎么样呢?
我们发现三者的地址一模一样,那么&arr[0]、&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("\n");
printf("&arr=%p\n",&arr);//整个数组地址
printf("&arr+1=%p\n",&arr+1);
printf("\n");
printf("arr = %p\n", arr);//数组名
printf("arr+1= %p\n", arr+1);
return 0;
}
原理在上篇博客中有提到,根据输出结果大家可以计算一下:
&arr[0]和&arr[0]+1相差4个字节,arr和arr+1相差4个字节,是因为&arr[0]和arr都是⾸元素的地址,+1就是跳过⼀个元素,也就是一个整形,4个字节
但是&arr和&arr+1相差40个字节,这就是因为&arr是数组的地址,+1操作是跳过整个数组的。
总结:
arr与&arr[0]都是首元素地址,指向数组第一个元素。
&arr以首元素地址表示,但是指向的是整个数组。
2.特殊的sizeof(数组名)
首先,sizeof是C语言的一种单目操作符,其次,sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定。
代码示例:
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", sizeof(arr));
return 0;
}
如果按照刚刚的正常想法去做,那么输出的结果应该是8(不同机器的答案不同)我们让程序运行一下:
结果为40。
为了便于总结,我们特意提出这个例外,第二个例外就是我们刚刚说的&arr
• sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩,单位是字节
• &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素的地址是有区别的)
除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。
3.使用指针访问数组
int main()
{
int arr[10] = { 0 };
int sz = sizoof(arr) / sizeof(arr[0]);
int* p = arr;
int i=0;
for (i = 0; i < sz; i++)
{
scanf("%d", p + i);
}
for (i = 0; i < sz; i++)
{
//指针访问
printf("%d ", *(p + i));//arr[i]==*(arr+i)==*(p+i)==p[i]
}
printf("\n");
for (i = 0; i < sz; i++)
{
//数组访问
printf("%d ", arr[i]);
}
}
**arr[i]== * (arr+i)==*(p+i)==p[i]**这个等价关系使我们深层次的理解指针的奥妙
4.数组传参
概念:数组传参就是把数组当作参数传给函数。
4.1一维数组传参
那么传参时,是把整个数组传给函数,还是只传递一部分?其次,我们可以把数组传给⼀个函数后,函数内部求数组的元素个数吗?
#include <stdio.h>
void test(int arr[])
{
int sz2 = sizeof(arr)/sizeof(arr[0]);
printf("sz2 = %d\n", sz2);//函数内部计算数组大小
}
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int sz1 = sizeof(arr)/sizeof(arr[0]);
printf("sz1 = %d\n", sz1);//函数外部计算数组大小
test(arr);
return 0;
}
第一⼩节我们学习了:数组名是数组⾸元素的地址;
那么在数组传参的时候,传递的是数组名,也就是说本质上数组传参本质上传递的是数组⾸元素的地址。
既然传递的是地址,那我就可以直接传递指针
void test(int* arr) //参数写成指针形式
{
printf("%d\n", sizeof(arr)); //计算⼀个指针变量的⼤⼩
}
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
test(arr);
return 0;
}
那么在函数内部我们写sizeof(arr) 计算的是⼀个地址的⼤⼩(单位字节)⽽不是数组的⼤⼩。
4.2二维数组传参
二维数组大家可以参考之前写的博客,这里不再介绍。
根据数组名是数组⾸元素的地址这个规则,⼆维数组的数组名表⽰的就是第⼀⾏的地址,是⼀维数组的地址。
代码示例:
#include <stdio.h>
void test(int (*p)[5], int r, int c)
{
int i = 0;
int j = 0;
for(i=0; i<r; i++)
{
for(j=0; j<c; j++)
{
printf("%d ", *(*(p+i)+j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};
test(arr, 3, 5);
return 0;
}
把一维数组作为参考,那就意味着⼆维数组传参本质上也是传递了地址,传递的是第⼀⾏这个⼀维数组的地址,也就是指针。
总结:
⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。
⼆维数组传参,形参的部分可以写成数组形式,也可以写成指针形式。
5.指针数组与数组指针
5.1指针数组
其实很好理解,指针数组就是指针的数组,首先他是应该数组,其次,数组里存放的是指针(地址)。
5.2数组指针变量
类似与指针数组,数组指针就是数组的指针。首先,他是一个指针,其次,指针指向的是一个数组。
int (*a)[5];//指向一个有5个元素的整形数组
char(*arr)[10];//指向一个有10个元素的字符数组
a先和*结合,说明a是⼀个指针变量,然后指向的是⼀个⼤⼩为10个整型的数组。所以a是⼀个指针,指向⼀个数组,叫数组指针。
这⾥要注意:[]的优先级要⾼于 * 号的,所以必须加上()来保证a先和 * 结合。(对优先级的知识在揭示c语言操作符之神秘)
也就是说:数组指针变量是⽤来存放数组地址的
二、字符指针变量
在指针的类型中我们有⼀种指针类型为字符指针 char*
这是把一个字符的地址放到pc中:
int main()
{
char ch = 'w';
char *pc = &ch;
*pc = 'w';
return 0;
}
那么字符串是不是也将整个字符串的地址存起来呢?
这里有一道典型的题目,大家一起来品鉴~
#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;
}
C语言会把常量字符串存储到单独的⼀个内存区域,
当⼏个指针指向同⼀个字符串的时候,他们实际会指向同⼀块内存。但是⽤相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。
其实这与数组也有一定关系,因为数组在内存中是连续存放的,所以数组往往只存储首元素地址(字符串首字母),这就导致初始化不同的数组有不同的地址。
完结
-
指针部分下次将迎来难度最大的一节,大家敬请期待~
创作不易,点赞鼓励下吧~~~