由浅入深的指针讲解

一、首先了解指针变量的概念:存放内存中数据的地址的变量

代码演示:
TIPS: “&”为取址操作符,可以将变量的地址取出;“*”是取值操作符,可以将指针变量指向的变量取			    出。
下边的代码就是指针的最简单的一个实现,下面的输出语句等价于printf(“%d”,num);
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
	int num = 10;//内存里创建一个整型变量num
	int* p = &num;//将num在内存里的地址存放在指针变量 p里,可以说p指向num
	printf("%d", *p);
}

二、指针变量的大小

问题:在32位机和64位机里指针变量所占的内存空间分别是多少?为什么是是这么分配的?

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
	int num = 10;//内存里创建一个整型变量num
	int* p = &num;//将num在内存里的地址存放在指针变量 p里,可以说p指向num
	printf("%zd", sizeof(p));//32位情况下输出4,64位情况下输出8
}

为什么在不同机器上指针大小会不一样呢?
首先32/64 位指的是计算机可以同时处理的二进制位数,在32位机下数据可以出现 2^32 种组合可能,要为这么多的数据编址也要对等数量的地址。故地址也一共有 2 ^32 个。32b/8=4byte。这就是为什么在32位机情况下一个指针占用4个字节空间了。
同时我们可以知道地址的大小跟指向数据的类型是无关的,因为指针与计算机的位数有关,不论指针指向什么元素他只会占4/8个字节的空间,内存的每个字节都有他自己的地址

三、指针变量+1意味着什么?

代码示例:
重点观察指针每次加一后在内存的情况

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
	int arr[5] = { 1,2,3,4,5 };
	//指针遍历数组
	for (int i = 0; i < 5; i++) {
		//重点观察指针每次加一后在内存的情况
		printf("%d", *(arr + i));
	}
}

程序调试图:
在这里插入图片描述
可以很清楚的在内存里看到,指针每次加一地址都会+4,这是因为指针的基类型是int形的,而我是在32机的情况下运行的程序。一个int占4个字节,指向int 的指针变量每次加一就会跳过一个int的内存,这么做也是为了方便我们编程者的使用,举一反三,指向什么类型的数据,指针每次加一就会跳过这个类型大小的空间。

四、 void * 指针是做什么用的?怎么用?

在我看来void 的指针就像一个垃圾桶,当我们编写一个适用范围比较广的函数或者方法的时候,往往并不能确定传参时候到底传的是什么数据类型,这个时候void* 指针就排上用场了,我们可以将任意类型的地址传给他,他都可以接收。下边通过一个具体例子给大家解释到底如何使用好 void* 指针*

模拟实现qsort()函数:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
typedef struct stu {
	char name[20];
	int num;
	} Stu;
Stu student[3] = { {"zhangsan",100} ,{"lizi",101},{"wangwu",102} };
void swap(char* buf1, char* buf2, int size) {
	char temp;
	for (int i = 0; i < size; i++) {
		temp = *(buf1+i);
		*(buf1 + i) = *(buf2+i);
		*(buf2+i) = temp;
	}
}
void qsort(void* base, size_t num, int size, int (*pfun)(void* e1, void* e2)) {
	//注意这里数组使用void*接受的,我们并不知道数组的基类型,但是我们可以通过数组元素的大小来进行元素的使用
	//我们知道char只占一个字节空间,不受32/64 位机的影响,故我们将base强制转换成char*指针就能对内存里的数据进行精确的操控了
	//(char *)base +1*size ,(char *)base +2*size  这样就可以操作数组的第一个和第二个元素了,以此类推..
	for (size_t i = 0; i < num - 1; i++) {
		for (size_t j = 0; j < num - 1 - i; j++) {
			if (pfun((char*)base + j * size, (char*)base + (j + 1) * size) > 0) {
				//printf("进入了循环,size=%d\n",size);
				swap((char*)base + j * size, (char*)base + (j + 1) * size, size);//交换函数
			}
		}
	}
}
//冒泡排序byInt
int bubble_byInt(void* e1, void* e2) {
	//printf("返回值是%d\n", *(int*)e2 - *(int*)e1);
	return *(int*)e2 - *(int*)e1;
	
}
//冒泡排序byStruct:string
int bubble_byString(void* e1, void* e2) {
	//printf("返回值是%d\n", strcmp(((Stu*)e1)->name, ((Stu*)e2)->name));
	return strcmp(((Stu *)e1)->name, ((Stu*)e2)->name);

}
void test01() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	size_t num = sizeof(arr) / sizeof(arr[0]), size = sizeof(arr[0]);
	qsort(arr, num, size, bubble_byInt);
	for (int i = 0; i < 10; i++) {
		printf("%d ", arr[i]);
	}
}
void test02() {
	qsort(student, sizeof(student)/sizeof(student[0]), sizeof(student[0]), bubble_byString);
	for (int i = 0; i < 3; i++) {
		printf("%s \n",(student+i)->name);
	}
}
int main() {
	//qsort是一个万能排序函数,它源代码采用快速排序,这里我们采用冒泡来实现底层排序逻辑,他一个非常
	//重要的参数就是第四个参数传送的是自己写的判断函数,他将根据我们排序函数的返回值进行排序,这里不是重点不做过多赘述
	test01();
	printf("\n");
	test02();
	return 0;
}

使用我已经在代码的注释中详细给出,下边贴出运行结果

在这里插入图片描述

以上是我对指针的一些浅薄理解,希望可以帮助到更多人理解指针的用法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

栗悟饭&龟波气功

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

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

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

打赏作者

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

抵扣说明:

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

余额充值