指针与数组

**在我们学C语言时候,当我们存储一个整型数据时候用int类型,存储小数数据用float类型,当这个小数的小数点精确非常长就用double类型,存储字符用char类型,我们用不同的类型去定义不同类型的变量时候,这些变量相当于一个房间,里面住着不同类型的人,而这些房间也有相应各自的房间号码。

在这里插入图片描述
上图中,0x11, 0x32, 0x55, 0x63这些数据相当于这些房子中每一个房子门牌号码。

计算机内存那么大,大到相当于里面有一个大世界,那么我应该怎么样在大世界里面才能找到我想要的房子呢?
这就是指针起到作用了。

是呀,我们所定义的每一个变量相当于是每一个小房子,但每一个小房子有他相应的号码
指针定义格式:
数据类型 * 变量
>>>>>>>>》》 int * p;
这里p是一个int类型的指针p只能存储int类型的地址,那么应该如何去存储呢?
示例一:

 int a = 5; 
//定义一个int类型的变量a, a里面装了一个数字5,a又相当于一个小房子
//,这个房子是int类型,这个房子也有他的编号。

 int * p;     
//定义了一个int类型的指针,p是int类型指针,p只能存储int类型的地址(小房子的编号)
//, int *类型就是int指针类型
 p = &a;
//p存储了变量a的地址,也就是p里面装了a这个房子的号码,我可以通过p找到a这个小房子对
//应的号码是多少,既然a房子号码能够通过p找到了,那不就意味着能通过p找到a的嘛,
//而p这里存的是变量a的房间号码,所以*p 等于 a, *号是解引用,由于p存储的是a的房间号码
//所以*p意思就是取出房间号码对应的房子里面住的人,而a这个房子里面住着的是一个5,
//所以*p
//就是取出a这个房子里面的人,最终*p和a都是5
//p指向a,那么*p 等价于 a, 
   printf("a = %d,*p =  %d", a, *p);
   printf("&a = %p, p = %p", &a, p);
   运行结果:
      a = 5*p =  5
      &a = 000000000062FE14, p =  000000000062FE14

上面代码由于p能够找到a,所以*p和a最终输出都是5,而下面输出的是000000000062FE14,这就是a这个房子的号码。

到这里简单理解了指针是什么了。

数组指针
名字理解:其实就是有一个指针,能够找到数组每一个元素的号码。就这么个东西
数组其实就是一个静态存储,静态其实就是数组内存空间是连续的,也就是说,数组每一个小房子一个一个紧挨着的。
在这里插入图片描述
代码示例

#include <stdio.h>

int main() {
	int a[7] = {1, 2, 3, 4, 5, 6, 7};
	int i;
	for (i = 0; i < 7; i++)
	    printf("&a[%d] = %p\n",i, &a[i]);
	return 0;
} 
/*
运行结果:
&a[0] = 000000000062FE00
&a[1] = 000000000062FE04
&a[2] = 000000000062FE08
&a[3] = 000000000062FE0C
&a[4] = 000000000062FE10
&a[5] = 000000000062FE14
&a[6] = 000000000062FE18 
*/

上面运行结果:a[0]的地址最后两位是00,下一个元素是04 08 由于数组是int类型,所以数组每一个元素也是int类型,int占4字节,由于第一个元素的地址最后两位是00,所以后面分别元素是04,08,0c(16进制表示, 逢16进一), 10, 14, 18

这个代码知道数组里面每一个元素内存空间是连续的,一个紧挨着一个-----------静态存储(内存空间是连续的)

既然有静态,肯定有动态,那就是程序员手动开辟的内存空间---------malloc这个函数去做的事情,在c++用new开辟。

什么是动态。
简单的说,内存空间是不连续的,第一个内存在这,第二个空间在那,两个空间隔着十万八千里远,但是我能够从第一个空间找到第二个空间在哪,通过第二空间找到第三,四后面等等依次类推,都是由上一个空间确定下一个空间位置。
下图:
在这里插入图片描述
由第一个号码为0x12的空间找到0x66的空间,
再由0x66的空间找到0x986的空间,
再由0x986空间找到0x123空间
也能跟数组一样表示一个挨着一个,但是确是间接表示,其实他们每个内存空间相互独立存在的,彼此不认识谁,但是可以通过这种访问方式可以一一找到,-----------这就是动态存储
这些一个个的内存空间是用malloc开辟的空间,在堆区开辟的,我们定义的什么int类型,float类型,基本类型都是在栈区里面的做的。

栈区:编译器自动分配内存,自动释放
堆区:程序员手动分配内存,手动释放

到这里,简单介绍数组是静态存储方式,相对简单介绍动态存储方式。

数组指针示例:

#include <stdio.h>

int main() {
	int a[7] = {1, 2, 3, 4, 5, 6, 7};
	int *p, i;
	p = a; //p指向a 
	for (i = 0; i < 7; i++)
	    printf("a[%d] = %d\n",i, *(p+i));
	return 0;
} 
/*
运行结果:
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
a[5] = 6
a[6] = 7
*/

上面代码,a是一个数组,a是指向数组第一个元素的位置(一个数组的数组名是指向元素第一个位置的),我也定义了一个int类型指针p,p = a,意思就是,p指向a所指向的位置,a指向哪?a指向数组a[0]的位置(也就是a存储的是a[0]的地址),所以p也是指向a[0]的位置(p也存储的是a[0]的地址),也就是a和p都是访问第一个元素的房间号码,指针是访问房间号码的(每一个元素的地址),最开始介绍了什么是房间号码,开始的地方有图。

接着就是for循环,遍历数组每一个元素
紧接着语句*(p + i)
当i为0时候,那么就是*p了,之前说过 *号是解引用,能通过p所能找到的房子,因为p是存储房间号码的嘛,所以能够找到相应的房子,并且能够进入该房子里面去(或者说我能够访问该房子的数据),p是指向a,a指向a[0],也就是p = a = &a[0],这里"="表示的是指向的意思, 所以p指向a[0], 所以房子里面住的是1, *p = =a[0] == 1, (这里“==”表示等于的意思)紧接着, * (p+1), 这一句先执行括号里面的p+1, p原本指向的是a[0]的位置,接着p+1意思就是,p指向下一个房间了,下一个房间在哪,是a[1]了,为什么是a[1], 因为数组每一个空间是一个个紧挨着的,是连续的,所以下一个位置是a[1], 所以p+1 == &a[1] 也就是p+1等价于第二个房子的号码,接着执行 *(p+1)取出第二个房子里面的人,住着的是1,所以 (p+1) == a[1] == 2, 后面也一样(p+2) == a[2] == 3,依次类推,后面规律一样。

到这里是介绍数组指针----------用一个指针能够访问数组的每一个元素。
注意:虽说数组名是一个指向数组第一个元素的指针,但是他却不能移动,因为他是一个常量指针,只能指向数组第一个元素地址
示例:
这种可以:

#include <stdio.h>

int main() {
	int a[7] = {1, 2, 3, 4, 5, 6, 7};
	int *p, i;
	p = a; //p指向a 
	for (i = 0; i < 7; i++)
	    printf("a[%d] = %d\n",i, *p++);
	return 0;
} 
/*
运行结果:
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
a[5] = 6
a[6] = 7
*/

这种不可以:

#include <stdio.h>

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

在这里插入图片描述

a只能指向数组第一个位置,a不能动。
指针能加能减,但是不能乘除。
加:指针向右移动
减:指针向左移动

数组的五种访问方式:

#include <stdio.h>

int main() {
	int a[7] = {1, 2, 3, 4, 5, 6, 7};
	int i;
	int * p = a;
	//第一种
	for (i = 0; i < 7; i++)
	   printf("%d ", a[i]);
	printf("\n");   
	 
	//第二种
	for (i = 0; i < 7; i++)
	   printf("%d ", *(a + i)); 
	printf("\n");   
	
	//第三种 
	for (i = 0; i < 7; i++)
	   printf("%d ", *(p + i)); 
	printf("\n"); 
	
	//第四种 
	for (i = 0; i < 7; i++)
	   printf("%d ", p[i]);
	printf("\n");  
	
	//第五种
	for (i = 0; i < 7; i++)
	   printf("%d ", *p++);
	printf("\n");  
	return 0;
} 
/*
运行结果: 
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7 
*/

指针数组
解释: 数组的每一个元素都是一个指针,数组每一个元素都是存储号码的(地址)
示例:

#include <stdio.h>

int main() {
	int *a[3]; //a[0] a[1] a[2] <==> int *类型指针 
	int A = 1;
	int B = 2;
	int C = 3;
	
	a[0] = &A;
	a[1] = &B;
	a[2] = &C; 
	for (int i = 0; i < 3; i++) {
		printf("%d ", *a[i]);
	}
	return 0;
} 
/*
运行结果: 
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7 
*/

总结:

 数组指针:指向数组类型的指针
 指针数组:数组每一个元素的一个指针
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值