C语言之指针初阶

目录

指针的定义

指针的大小

指针和指针类型

指针的解引用

指针加减整数

野指针

野指针产生的原因

指针未初始化

指针越界

怎样避免产生野指针 

 指针运算

指针加减整数

指针减指针

指针的关系运算

二级指针和多级指针

 指针数组


指针的定义

指针地址地址就是指针

我们把存放指针和地址的变量称作指针变量,所以指针变量的值是地址

在后续学习生活中,我们一般认为指针指针变量地址这三者具有相同的含义,指的是同一事务。

指针的大小

通过指针的定义我们知道,指针变量是存储变量地址的变量,所以指针变量的大小就取决于变量地址的大小,我们知道,计算机有32位机器和64位机器,这个位是什么意思呢?这个位其实就是地址线的根数,32位机器有32跟地址线,地址的大小就是32位,所以就是4个字节;64位机器有64根地址线,地址的大小就是64位,所以就是8个字节。因此,在32位机器下,指针变量的大小就是4个字节,在64位机器下,指针变量的大小就是8个字节。

指针和指针类型

int main() {
	int a = 10;
	int* p = &a;
	return 0;
}

分析上述代码,我们注意到了指针变量的类型我们设置成了int*,为什么我们要设置成int*,变量的类型这么多,为什么偏偏选取了这一个呢?这是因为变量a的类型是整型。其实这个int*是大有来头的,int*中的*表明了p是一个指针变量,int则表示p指向的变量是一个整型变量。

int main() {
	int b = 20;
	char* p1 = NULL;//当我不知道指针变量指向哪里的时候一般情况下,我们设置指针为空指针,这是为了避免野指针的出现
	int* p2 = NULL;
	short* p3 = NULL;
	long* p4= NULL;
	float* p5 = NULL;
	double* p6 = NULL;
	return 0;
}

  所以,指针变量的类型是非常多的,指针变量要设置成什么类型,可不是随意设置的,这完全取决于指针变量指向的变量是什么类型。不管指针变量是什么类型,指针变量的大小始终是由机器的位数决定的,与指针变量的类型无关,切记切记!

指针的解引用

在上期的操作符中我们讲到了*,这个其实就是解引用操作符。

int main() {
	int a = 2;
	int* p = &a;	//因为p的值是a的地址,所以我们也可以称p指向了a
	*p = 20;	//*p表示p指向的变量,因为p指向了a,所以*p表示a,这里就相当于给a赋值
	printf("%d\n", a);
	return 0;
}

我们发现a的值被*p所改变 

*p表示p指向的变量。这对后面的多级指针同样适用。

指针加减整数

int main() {

	int a = 10;
	char b = 'a';
	int* pa = &a;
	char* pb = &b;
	printf("%p\n",pa);
	printf("%p\n",pa+1);
	printf("%p\n",pb);
	printf("%p\n",pb+1);
	return 0;
}

我们发现整型指针加1,打印的地址增加了4,字符指针+1,打印的地址+1;

所以我们规定,指针加1或者减去1,跳过的字节数取决于指针变量本身的类型,如果是整型指针,那么就跳过4个字节,如果是字符指针就跳过1个字节。计算机中我们规定一个存储单元的大小是一个字节,一个存储单元对应了一个地址,所以跳过几个字节就相当于跳过了几个存储单元,也就相当于跳过了几个地址,因为地址是连续的且相邻两个地址差1,所以跳过了几个字节就相当于地址差了几,这便是上述四个结果产生的原因。

野指针

野指针产生的原因

指针未初始化

int main() {
	int* p;
	*p = 20;
	printf("%d",*p);
	return 0;
}

指针变量没有初始化,所以编译器不知道指针变量指向了哪一个变量,所以会报错。

指针越界

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

第11个元素是内存中随机的内存单元中的值。 

 数组元素的下标只能是0到9,但是这是却访问到了下标为10的元素,所以此时访问的就不是数组中的元素,这是就称指针越界了,此时的p就称作野指针。

怎样避免产生野指针 

要避免野指针就得从产生野指针的原因手。比如在创建指针变量的时候对指针变量进行初始化,如果实在不知道指针变量指向哪里,可以对指针变量设空值<NULL>。在使用指针变量时应该确定指针所指向的变量的范围。

 指针运算

指针加减整数

指针加减整数其实就是指针跳过指针变量自身变量类型的字节数,整型指针+1或者-1跳过四个字节,字符指针+1或者-1跳过一个字节。

指针减指针

很多人会有疑问,为什么只有指针减指针,没有指针加指针呢?

指针(指针变量)它存储的是变量的地址,所以指针的运算就可以理解为变量地址的运算,两个变量地址相减可以理解为两个变量地址的差值,两个地址相加这是毫无实际意义的,可以近似的理解为两个人的身高的加减运算,身高相减是两个人身高的差值,但是两个人身高相加这也是毫无意义的,所以在指针运算这里,我们只考虑两个指针的相减运算。

那么两个指针相减的实际意义是什么呢?我们先看下面的代码

int main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* start = arr;
	int* end = &arr[9];
	int num = end - start;
	printf("%d\n",num);
	return 0;
}

所以我们可以知道,两个指针相减,得到的是两个变量之间的元素的个数+1,这就是我们函数递归那一期,讲的求字符串长度的应用。 

指针的关系运算

int main() {
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int* p = arr;
	for (p = arr; p < &arr[10]; p++)
	{
		printf("%d\n",*p);
	}
	return 0;

}

里面用到了指针的比较,我们又学习到了一种遍历数组的方法。

二级指针和多级指针

根据指针的定义我们可以知道,指针变量本身就是一个变量,既然它是一个变量,那么它就会有地址,同样的我们可以创建一个指针变量存放指针变量的地址,此时我们就称这个指针变量就是二级指针,多级指针也是同样的,二级指针变量也是一个变量,也会有自身的地址,所以我们就可以创建一个指针变量存放二级指针变量的地址,此时这个变量就称作三级指针,理论上,只要脑洞足够大,这个指针是可以无限套娃的。

int main() {
	int a = 10;
	int* p = &a;
	int** pp = &p;
	printf("%d\n", *p);    //表示p指向的变量的值,即a的值
	printf("%d\n", **pp);    //表示a的值
	printf("%d\n", *pp);    //表示p的值
	printf("%d\n",p);        //表示p的值
	return 0;    
}

所以不论是几级指针,我们都可以用它表示最开始的变量的值。

 指针数组

指针数组是什么,指针是定于,数组是主语,所以指针数组本质上就是一个数组,只不过这个数组的类型是指针类型,数组里的元素都是指针变量。

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

int main() {
	int arr1[5] = {1,2,3,4,5};
	int* arr[5] = { arr1,arr1+1,arr1+2,arr1+3,arr1+4 };
	int i = 0;
	for (i = 0; i < 5; i++) {

		printf("%d\n", *arr[i]);

	}
	return 0;

上述代码便应用了指针数组,使用指针数组,可以减少代码的冗余量。

本期的内容就是这些,希望本期内容可以帮助大家加深对指针的理解。在为大家补充一个小的知识点。

int a = 10;

看似很简单的一行代码,其实它也是大有来头的。

我们知道计算机中的内存被分成了很多个内存单元,一个内存单元的大小是一个字节,我们创建了一个整型变量,就意味着在计算机中开辟了一块大小为4个字节的空间,我们称这块空间的名称就是a,这块空间所存储的数据就是a的值10.这便是上述代码在计算机内存中大致的存储过程。

        本期内容到此结束!^_^ 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

棠~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值