目录

主要内容

1.内存和地址

2.取地址操作符

3.指针变量与解引用操作符

4.指针变量的大小

5.指针变量类型的意义

6.指针运算:指针+-整数,指针-指针,指针的关系运算符


一.内存和地址

        计算机内存是连续的存储空间,系统会为内存中每一个字节的空间分配唯一的编号,这个编号就是内存地址

        我们定义的普通变量(int、char、float等)都会占用对应的内存空间,变量的本质是内存中一块空间的别名,而变量的地址就是其占用内存空间的起始地址。地址是操作系统层面的数值标识,专门用于定位内存空间,也是指针所有操作的基础。

二.取地址操作符

        & :是C语言中的取地址操作符,作用是取出变量在内存中的起始地址

        语法规则:&变量名,例如代码中&a 可以取出整型变量a的内存地址。

三.指针变量与解引用操作符

        指针变量是专门用来存放内存地址的变量,区别于存放数值的普通变量。

        定义语法:数据类型* 指针变量名。

例一:

int main()
{
	int a = 10;
	// &a :& 为取地址操作符,取出的是a的地址
	int* p = &a;//p就是指针变量,指针变量就是存放地址的变量; int * :* 指p是指针变量,int表示为 p指向的对象为int类型 
	printf("%p\n", &a);
	printf("%d\n", *p);//*是解引用操作符,*p的意思是通过p里边存放的地址,找到p指向的对象,也就是a,所以*p就是a;
	printf("%p\n", p);//p 本身就是 &a,和第 1 行地址完全相等
	//printf("%d\n", p);//p 是指针 int*(存地址,是长整型数值)% d 用于打印 int,指针宽度通常 4 / 8 字节,和 int 尺寸不一致

	*p = 5;// 通过指针修改地址里的数据,等价于 a = 5;
	printf("%d\n", *p);
	printf("%d\n", a);
	return 0;
}

代码运行结果:

四.指针变量的大小

例二:

/*结论
* 32位平台下地址是32个比特,指针变量大小就是4个字节;
* 64位平台下地址是64个比特,指针变量大小就是8个字节;
* 指针变量的大小和类型是无关的,只要是指针类型的变量,在相同平台下,大小都是相同的。 
*/
/*这个代码是在64位平台下运行的*/
int main()
{

    printf("%zu\n", sizeof(char*));//8
	printf("%zu\n", sizeof(short*));//8
	printf("%zu\n", sizeof(int*));//8
	printf("%zu\n", sizeof(long*));//8
	printf("%zu\n", sizeof(long long*));//8
	printf("%zu\n", sizeof(float*));//8
	printf("%zu\n", sizeof(double*));//8

	return 0;
}

代码运行结果:

五.指针变量类型的意义

例三:

int main()
{
	int a = 0x11223344;
	//int* p = &a;
	char* p = &a;

	*p = 0;//指针的类型只决定解引用 *p 一次操作读写多少字节,
	return 0;
}

这段代码主要是指针解引用时查看a的值在内存中的变化;若使用 int* 指针 接收a的地址并解引用赋值 *p = 0,会一次性修改4个字节,变量a的完整数值会变为0;若使用 char* 指针 接收a的地址并解引用赋值 *p = 0,仅会修改1个字节,只会改变变量a内存中最后一位字节的数据,其余高位字节数据保持不变。

例四:

//指针的类型决定了指针向前或者向后走一步多大(距离)
int main()
{
	int a = 0x11223344;
	int* pa = &a;
	char* pc = &a;

	printf("pa     = %p\n", pa);
	printf("pa + 1 = %p\n", pa + 1);
	printf("pc     = %p\n", pc);
	printf("pc + 1 = %p\n", pc + 1);

	return 0;
}

代码运行结果:

例五:

//void *指针
/*
* 在指针类型中有一种特殊的类型是void*类型的,可以理解为无具体类型的指针(或者叫泛型指针),这种类型的指针可以用来接受任意类型地址,
但也有局限性,void*类型的指针不能直接进行指针的+-整数和解引用的运算

void*类型指针到底有什么用呢?
一般void*类型的指针是使用在函数参数的部分,用来接收不同类型数据的地址,
这样的设计可以实现泛型编程效果。使得一个函数来处理多种类型的数据
*/
int main()
{
	char a = 'w';
	int b = 10;
	//int* pa = &a;
	void* pb1 = &a;
	void* pb2 = &b;
	return 0;
}

六.指针运算:指针+-整数,指针-指针,指针的关系运算符

例六:

//指针+-整数
int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int* p = &arr[0];
	int i = 0;

	for (i = 0;i < 10;i++)
	{
		//printf("%d ",*(p+i));
		printf("%d ", *p);
		p++;
	}
	return 0;

}

代码运行结果:

在这个代码中指针向后/向前移动对应个数的元素,而非字节,步长由指针类型决定。

例七:

//指针 - 指针得到的是指针和指针之间的元素个数;前提,两个指针指向同一块空间;
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

	printf("%d\n", &arr[9] - &arr[0]);

	return 0;
}

代码运行结果:

例八:

int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int* p = arr;

	while (p < &arr[10])
	{
		printf("%d ", *p);
		p++;
	}
	return 0;
}

代码运行结果:

代码解释:数组遍历边界判断,例如 p < &arr[10],通过指针地址的大小关系,判断遍历是否结束,实现数组完整遍历。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐