C语言:指针2:指针类型,指针计算,数组指针,指针数组(一个C语言小白的理解之旅)

一.指针和指针类型

这里我们在讨论一下:指针的类型。我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢? 准确的说:有的。当有这样的代码:

int num = 10;
p = #

要将&num(num的地址)保存到p中,我们知道p就是一个指针变量,那它的类型是怎样的呢? 我们给指针变量相应的类型。

char   *pc = NULL;
int    *pi = NULL;
short  *ps = NULL;
long   *pl = NULL;
float  *pf = NULL;
double *pd = NULL;

这里可以看到,指针的定义方式是: type + * 。 其实: char* 类型的指针是为了存放 char 类型变量的地址。 short* 类型的指针是为了存放 short 类型变量的地址。 int* 类型的指针是为了存放 int 类型变量的地址。

指针类型的意义

1.指针 ± 整数

#include <stdio.h>
//演示实例
int main()
{
int n = 10;
char *pc = (char*)&n;
int *pi = &n;
printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc+1);
printf("%p\n", pi);
printf("%p\n", pi+1);
return 0;
}

运行结果在这里插入图片描述
总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。

2.指针的解引用

//演示实例
#include <stdio.h>
int main()
{
	int n = 0x11223344;
	char *pc = (char *)&n;
	char *pi = &n;
	*pc = 0x55;//重点在调试的过程中观察内存的变化。
	*pi = 0; //重点在调试的过程中观察内存的变化。
	system("pause");
	return 0;
}

总结: 指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。 比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

二.指针和数组

1.指针和数组名

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

运行结果在这里插入图片描述
由运行结果可见,数组名和数组首元素的地址是一样的。
结论:数组名表示的是数组首元素的地址。

2.指针运算
(1)指针变量可以互相赋值,也可以赋值某个变量的地址,或者赋值一个具体的地址。

int *px, *py, *pz, x = 10;
//赋予某个变量的地址
px = &x;
//相互赋值
py = px;
//赋值具体的地址
pz = 4000;

(2)指针与整数的加减运算

指针变量的自增自减运算。指针加 1 或减 1 运算,表示指针向前或向后移动一个单元(不同类型的指针,单元长度不同)。这个在数组中非常常用。
指针变量加上或减去一个整形数。和第一条类似,具体加几就是向前移动几个单元,减几就是向后移动几个单元。

//定义三个变量,假设它们地址为连续的,分别为 4000、4004、4008
int x, y, z;

//定义一个指针,指向 x
int *px = &x;

//利用指针变量 px 加减整数,分别输出 x、y、z
printf("x = %d", *px);		//因为 px 指向 x,所以*px = x

//px + 1,表示,向前移动一个单元(从 4000 到 4004)
//这里要先(px + 1),再*(px + 1)获取内容,因为单目运算符“*”优先级高于双目运算符“+”
printf("y = %d", *(px + 1));		
printf("z = %d", *(px + 2));

3.关系运算
假设有指针变量 px、py。
px > py 表示 px 指向的存储地址是否大于 py 指向的地址;
px == py 表示 px 和 py 是否指向同一个存储单元;
px == 0 和 px != 0 表示 px 是否为空指针。

//定义一个数组,数组中相邻元素地址间隔一个单元
int num[2] = {1, 3};

//将数组中第一个元素地址和第二个元素的地址赋值给 px、py
int *px = &num[0], *py = &num[1];
int *pz = &num[0];
int *pn;

//则 py > px
if(py > px){
	printf("py 指向的存储地址大于 px 所指向的存储地址");
}

//pz 和 px 都指向 num[0]
if(pz == px){
	printf("px 和 pz 指向同一个地址");
}

//pn 没有初始化
if(pn == NULL || pn == 0){
	printf("pn 是一个空指针");
}

三.指针和数组关系代码实践

示例代码:

#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,0 };
	int *p = arr; //指针存放数组首元素的地址
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i<sz; i++)
	{
		printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p + i);
	}
	system("pause");
	return 0;
}

运行结果:在这里插入图片描述
既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。所以 p+i 其实计算的是数组 arr 下标为i的地址。

那我们就可以直接通过指针来访问数组。实例代码如下:

#include <stdio.h>
int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	int *p = arr; //指针存放数组首元素的地址
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i<sz; i++)
	{
		printf("%d ", *(p + i));
	}
	system("pause");
	return 0;
}

运行结果:在这里插入图片描述
总结

1.*p = 1,此操作为赋值操作,即将指针指向的存储空间赋值为 1。此时 p 指向数组 arr 的第一个元素,则此操作将 arr 第一个元素赋值为 0,即 arr[0] = 1。
2.p + 1,此操作为指针加整数操作,即向前移动一个单元。此时 p + 1 指向 arr[0]的下一个元素,即 arr[1]。通过p + 整数可以移动到想要操作的元素(此整数可以为负数)。
3.p,(p+0)指向 arr[0]、p + 1 指向 arr[1]、、、类推可得,p+i 指向 arr[i],由此可以准确操作指定位置的元素。
4.在 (p + 整数)的操作要考虑边界的问题,如一个数组长度为 2,(p+3) 的意义对于数组操作来说没有意义。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值