指针解析(1)

一.指针定义

内存是被划分为一个一个小的内存单元的,每个内存单元大小是一个字节,而每个内存单元又有一个编号,这个编号就是地址。而指针就是存储这个地址的,指针可以认为是地址,通常说的指针是指针变量。

1.创建指针变量

创建一个变量,需要变量的类型,变量名和变量储存的数据。
比如

int a=10;
int* p=&a;

在这里,int*就是指针变量p的类型,&为取地址操作符,取出a的地址,保存在变量p里。在int*里,*代表p变量是一个指针变量,int代表p指向的那块内存里存储的数据是int类型的。数据类型有int,float,short,char,double等这么多种,那么相应的指针变量的类型也有许多。

2.指针类型和大小

指针变量的类型有很多,比如下面代码,还有许多没有列举完全,后面会渐渐的认识到。

	int* i = NULL;
	char* c = NULL;
	double* d = NULL;
	short* s = NULL;
	float* f = NULL;

其中NULL是空指针,代表指针没有存储有效数据,如果不知道初始化什么内容,建议使用NULL初始化,可以防止野指针。
指针变量的大小在32位机器下是4个字节,在64位机器下是8个字节。
先了解下地址是怎样产生的。在32位机器下,每一位在寻址时会有两种情况,高电平和低电平,即1或者0,那么32位就会产生32个0或者1组成的二进制序列,这个序列就是每个内存单元的地址。

0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0001
0000 0000 0000 0000 0000 0000 0000 0010
0000 0000 0000 0000 0000 0000 0000 0011
0000 0000 0000 0000 0000 0000 0000 0100




1111 1111 1111 1111 1111 1111 1111 1111

从全0到全1,一共2的32次方个数。
一个字节占8个bit位,四个字节就占32个bit位,而指针变量存储的是地址,所以指针变量的大小就是4个字节,64位机器下就是8个字节。
既然指针变量的大小是固定的,那么指针变量的类型的意义是什么呢?这就要了解指针的运算了

二.指针运算

指针是可以进行运算的,不同类型的指针运算结果是不同的。
先看一个例子

在这里插入图片描述
在这个例子中,只有a变成了0,b没有变成0,具体原因是什么呢,接下来就给大家分析。

1.解引用

指针的解引用就是得到指针指向的内存单元的数据

int main()
{
	int a = 0x11223344;
	int b = 0x11223344;
	int* p = &a;
	char* p1 = &b;
	*p = 0;
	*p1 = 0;
	return 0;
}

在上面程序里,p和p1是指针变量,在前面加个*,变为*p和*p1,这里的*作用为解引用,结果是得到指针变量指向的内存单元里存储的数据,即*p==a,*p1==b,最后两句代码,明明将0赋值给了a和b,但是只有a变为0了。这是为什么呢,通过代码,可以看到,p和p1的类型不同,一个是int*,一个是char*,这就是不同变量类型带来的不同结果。具体产生了什么不同,我们观察一下监视和内存窗口。
通过监视窗口,可以看到,变量a的值为0,变量b的值不为0;通过内存窗口,可以看到前面的0x0000… 为地址,b里面存储的44332211变为了00332211。在这里的数是16进制的数,两个16进制的数字就存到一个字节里了,八个16进制的数字就占满了四个字节。char占一个字节,通过*p1=0改变了b里一个字节的内容,int占四个字节,通过*p=0改变了a里四个字节的内容,所以可以判断,指针类型可以决定指针变量解引用时访问的字节数,事实上,也确实是如此。

可以看到,在代码里b是0x11223344,经过修改后,在内存窗口变成,00332211,倒着存储了,这是怎么回事,这涉及到另一个知识,机器的大小端存储,关于机器的大小端存储,后续在给大家介绍。

2.指针加减整数

先看一个代码

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

大家可以去vs上运行一下,结果是在屏幕上打印6。
在这个例子中指针加5,结果就是跳过五个整型,因为指针类型是int*,这也是不同类型会造成的不同结果。
首先,数组名是首元素的地址,创建一个变量p保存这个地址,如果直接解引用p,那么应该打印1,但是这里是p+5在解引用,就打印了6,那为什么不是向后跳五个数据呢,因为数组在内存里是连续存储的,随着下标的增加,地址由低到高,指针加整数,就会向后走。
通过这一点,可以用另一种方式打印数组里的元素。

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

理解了指针加整数,指针减整数自然也就理解了。

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

这个程序打印结果是5
指针类型可以决定指针加减整数一次走的步长。

3.指针减指针

指针是可以相减的,前提是两个指针指向的是同一块连续的内存,指针减指针存在相对关系。

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;                  //首元素的地址
	int* p1 = &arr[9];             //尾元素的地址 
	printf("%Id\n", p1-p);         //打印9
	printf("%Id ", p-p1);          //打印-9
	return 0;                      //指针减指针的结果是两个指针相差的元素个数
}

c语言规定,两个指针不能相加,因为相加得不到什么有意义的结果。

三.指针的一个小应用

交换两个整数a和b,相信大家都遇到过这个问题。这里提供几种方法。

方法一

int main()
{
	int a = 10; 
	int b = 5;
	printf("交换前a=%d,b=%d\n",a,b);
	int c = a;
	a = b;
	b = c;
	printf("交换后a=%d,b=%d\n",a,b);
}

创建临时变量保存其中一个值,这是一种方法,如果不能创建临时变量呢?

方法二

int main()
{
	int a = 10; 
	int b = 5;
	printf("交换前a=%d,b=%d\n",a,b);
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("交换后a=%d,b=%d\n",a,b);
}

这样也是一种方法,没有创建临时变量。

a^b^b=a
a^a=0

通过这两个性质可以做到不创建临时变量交换两数

这里还有第三种方法

void fun(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
int main()
{
	int a = 10; 
	int b = 5;
	printf("交换前a=%d,b=%d\n",a,b);
	fun(&a, &b);
	printf("交换后a=%d,b=%d\n",a,b);
}

通过函数和指针相结合的方法,但是也创建了临时变量,将a和b的地址传给形参x和y,解引用x和y后,得到a和b的值,创建一个临时变量进行交换。

关于指针的知识,本篇就介绍到这里了,后面还会有更多的关于指针的知识介绍。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值