指针入门简介

指针

什么是指针?

指针是一个值为内存地址的变量。就像char类型变量的值是字符,int类型变量的值是整数,指针变量的值是地址。

int main()
{	
	int a=0;//声明一个变量,在内存中分配空间
	int* pa=&a;//&是取地址操作符,表示取出a的地址
    		//pa是一个指针变量,来存放地址。
    		//*表示pa是一个地址,int表示指向的对象是整型
	return 0;
}

指针的解引用

如何通过指针来获取指针指向的内容呢?答案是解引用操作符*

int main()
{
	int a = 10;
	int* pa = &a;
	printf("%d\n", *pa);//*pa表示通过指针找到指向的内容
	return 0;
}

那如何改变变量的值呢?也可以通过解引用来改变

int main()
{
	int a = 10;
	int* pa = &a;
	*pa = 20;//*pa就是a
	printf("a=%d\n", a);
	return 0;
}

需要注意的是:指针解引用作为左值和右值时怎么理解?

int main()
{
	int a = 10;
	int b = 100;
	int* pa = &a;
	int* pb = &b;
	*pa = *pb;  // 指针是左值和右值时不一样
	printf("a=%d\n", a);
	printf("b=%d\n", b);
	return 0;
}

结论

当指针作为左值时,p的值是内存中某个特定位置的地址。*p操作符使机器指向那个位置,表示指定需要修改的位置。当它作为右值使用时,它就提取当前存储于这个位置的

不能说变量可以作为左值而表达式不能作为左值。

例如:

int main()
{
	int arr[10] = { 0 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
		arr[i + 3] = i;// 左值就是表达式
	}
	return 0;
}
int main()
{
	int a=1;
	int* pa=&a;
	*pa=2;//左值也是表达式
	return 0;
}

指针的大小

既然指针是存放地址的,那么地址就跟机器本身有关了。

在32位机器上,有32根地址线,所以能存放32位0或1组成的二进制序列。但一个字节是8位,所以需要4个字节来存放地址。
在64位机器上,有64根地址线,所以能存放64位0或1组成的二进制序列。因此需要8个字节来存放地址。

总结:

32位机器上:sizeof(p)==4

64位机器上:sizeof(p)==8

指针的类型

在整形家族中,有被分为字符型,短整型,长整型等。

在浮点型家族中,有被分为单精度、双精度型。

那么指针作为一种特殊的类型,是否有被分为类型?看下边代码:

int main()
{
	int arr[] = { 1,2,3,4,5 };
	int* pa = arr;
	pa++;
	return 0;
}

我们可以分析一下调试的过程:

  1. 当代码走到第9行时,指针变量pa接受数组首元素的地址,在监视和内存窗口知道pa的地址是 0x010ff87c.

  1. 当代码走过第9行时,执行完pa++操作后,此时的pa是0x010ff880,也就是跳过了数组中的一个元素指向了元素2。我们知道地址在内存中以16进制形式表示,执行代码第9行前后的指针差正好差了80-7c=4个字节。

再来看下边代码:

int main()
{
	int arr[] = { 1,2,3,4,5 };
	char* pc = (char*)arr;
	pc++;

	return 0;
}

当我们用字符指针操作时:

  1. 当代码走到第9行还未执行时,pc的值是0x00effe50.

  1. 当代码执行完第9行时,pc的值是0x00effe51,并没有访问到数组第二个元素。此时的指针差是1个字节。

  1. 这就说明了虽然指针(任意类型)的大小在同一机器下都是相同的,但是指针向前或者向后走的步长是不一样的。

总结:指针的类型决定了走一步走多长。因此可以得出另一个结论:当我们解引用操作时,指针的类型决定了我们所访问的权限。

char*的指针解引用只能访问一个字节。
int*的指针解引用能访问4个字节。

指针的运算

  • 指针+-整数:一般就是指针自增自减

  • 指针+-指针:运算结果是两指针之间的元素个数

  • 指针的关系运算:指针可以比大小

指针与数组的关系

首先说下数组名的特点:

数组名就是数组首元素地址。但是在两种情况下不是:
1、sizeof(数组名):这是整个数组所占的空间大小。
2、&数组名,这是取出整个数组的地址。

举例:

int main()
{
	int arr[] = { 1,2,3,4,5 };
	int sz = sizeof(arr);

	printf("数组所占的空间大小是%d个字节.\n", sz);

	printf("数组名地址是:%p\n", arr);
	printf("数组名+1地址是:%p\n", arr+1);
	printf("\n");

	printf("数组首元素的地址是:%p\n", &arr[0]);
	printf("数组首元素+1的地址是:%p\n", &arr[0] + 1);
	printf("\n");

	printf("&数组名的地址是:%p\n", &arr);
	printf("&数组名+1的地址是:%p\n", &arr+1);


	return 0;
}	

可以看出:

数组名就是首元素地址。当数组名+1时只是跳过数组内一个元素。因为08->0C正好跳过了4个字节,即一个整型元素。

&数组名看起来也是首元素地址,但是+1后,从08->1C,跳过了14个字节。注意的是,这是以16进制下的表示,转化为10进制是1*16^1 + 4*16^0=20个字节,刚好是整个数组的大小。所以数组名+1是跳过整个数组。

sizeof(数组名)是计算整个数组大小,即20个字节。


知道了上述以后:是不是就可以用指针访问数组内元素?答案是肯定的

int main()
{
	int arr[] = { 1,2,3,4,5 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* p = arr;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));//p是首元素地址,每次加1都是跳过一个元素得到                           //地址,然后解引用。
	}
	return 0;
}

所以现在访问数组除了用[]下标访问,还可以通过指着访问。

arr[i] == *(p+i) 这两者是等价的!!!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值