本篇博客是针对C语言学习中遇到的一大难题『指针』所做总结, 以此互勉.
目录
导语
内存
指针
常见问题解答:
学习指针, 一定要先了解一下内存, 内存是电脑上特别重要的存储器, 计算机中的所有程序的运行都是在内存中进行的.
所以为了有效的使用内存, 就把内存划分成一个个小的内存单元, 每个内存单元的大小是1个字节, 为了能够有效的访问到内存的每个单元, 就给内存单元进行了编号, 这些编号被称之为该内存单元的地址.
一波代码强入:
int main()
{
int a = 10; //int整型向内存申请了4个字节的空间
return 0;
}
这里注意:地址随机分配, 每次执行程序, 地址一般都会改变, 但规律不变
在计算机科学中, 指针(Pointer)是编程语言中的一个对象, 利用地址, 它的值直接指向(points to)存在电脑存储器中另一个地方的值. 由于通过地址能找到所需的变量单元, 可以说, 地址指向该变量单元. 因此, 将地址形象化的称为“指针”. 意思是通过它能找到以它为地址的内存单元.
int main()
{
int a = 10; //int整型向内存申请了4个字节的空间
//&a -- 取地址,得到 a 的首地址,地址也是一个数值,
//把这个数值用一个变量保存,此时这个变量的类型是(int*)类型
int* p = &a; //这个变量叫做指针变量, 指针变量是用来存放地址的
return 0;
}
指针变量就是用来存放地址的, 在指针变量的眼里, 它所存储的就是一个地址
◆ 指针的使用:
p的里面存的是a的地址, 我们要想找到a只用找到p就可以了, 那怎样获取p所存储的内容呢?
*p -- 对p解引用,*p就是a(的地址),通过指针变量中存储的那个地址,找到它所对应的对象
int main()
{
int a = 10;
int* p = &a;
printf("%d\n", a);
*p = 20; //把20赋值给*p,
printf("%d\n", a); //如果 a 的值变为20,那么证明*p就是a
return 0;
}
输出结果:
◆ 指针和指针类型
我们都知道, 变量有不同的类型, 整形, 浮点型等. 那指针有没有类型呢?准确的说:有的.
当有这样的代码:
int num = 10;
//p = #
要将&num(num的地址)保存到p中, p中存放的是那个地址的16进制形式. 我们知道 p 就是一个指针变量, 那它的类型是怎样的呢?我们给指针变量相应的类型.
char *pc = NULL;
int *pi = NULL;
short *ps = NULL;
long *pl = NULL;
float *pf = NULL;
double *pd = NULL;
这里可以看到, 指针的定义方式是:type(类型) + *(指针), 其实: char*类型的指针是为了存放 char 类型变量的地址, short* 类型的指针是为了存放 short 类型变量的地址, int*类型的指针是为了存放 int 类型变量的地址, 定义指针时, 同时将其初始化为NULL, 这个NULL是宏, 在C语言中, 指针的零值就是NULL, 在C++中, #define NULL ((void *) 0 ) 把 0 强转为零号地址
int num = 10;
void *pp = # //无类型的指针
*pp = 100; //报错: 非法的间接寻址
PS:无类型的指针不能被解引用, 无类型的指针也属于指针
◆ 那指针类型的意义是什么?
指针只是指向了一个内存地址, 但是当存内存中取值的时候, 系统不知道你要从当前指针指向的地址, 取几个字节, 指定了指针的类型后, 系统就知道取几个字节了. char类型取1个字节, short类型取2个字节, int类型取4个字节. 任何指针, 不管它是什么类型, 它的大小都是 4 (在64位平台中是8), 就算是多级指针也是如此.
int main()
{
//int a = 10;
//int* p = &a;
int *pp = 10; //对指针赋值不是地址,此时指针pp存的是10,指向地址为10的位置
return 0;
}
//结果如何?
不合理, 但编译器并没有报错, 因为C语言类型检查不严格, 换成 C++ 编译检查是无法通过的
◆ 指针加减一个整数
#include
//演示实例
int main()
{
int n = 10;
char *pc = (char*)&n; //强制类型转换
int *pi = &n;
printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc+1);
printf("%p\n", pi);
printf("%p\n", pi+1);
return 0;
}
PS:%p 用于打印地址, 类似于 %d 用于打印一个整型
输出结果:
小结:指针的类型决定了指针向前或者向后走一步有多大(距离), 指针加一(减一), 指针所存地址向后(向前)移动一个“类型大小”的距离
◆ 指针的解应用
#include
int main()
{
int n = 0x12345678; //十六进制,四个字节12 34 56 78
char *pc = (char *)&n; //一个字节,至于为什么是一个字节,下个示例会讲
//printf("%d\n", *pc); //%d整型(十进制)打印,结果为120
printf("%x\n", *pc);
return 0;
}
输出结果:
&n :
所以 n 在内存中的存储为:78 56 34 12, 表示在当前编译器中的物理存储, 是倒序存储(大端 & 小端)。
应用问题:如何判断当前系统(编译器)是大端还是小端?可以通过上面的代码验证
//演示实例
#include
int main()
{
int n = 0x11223344; //十六进制,四个字节
char *pc = (char *)&n; //一个字节
int *pi = &n;
*pc = 0; //重点在调试的过程中观察内存的变化。
*pi = 0; //重点在调试的过程中观察内存的变化。
return 0;
}
逐步调试: int n = 0x11223344; 观察内存&n
char *pc = (char *)&n;
int *pi = &n; 监视pc, pi
指针 pc 中存放的仅仅只是0x44; 而指针 pi 中存放的是0x11223344
小结:指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。 比如:char*的指针解引用就只能访问一个字节,而int*的指针的解引用就能访问四个字节。
◆ 为什么打印地址时,我的打印结果跟上面不一样?同一个代码每次执行,地址的打印结果也不一样
因为每次代码运行过程中,变量的创建都要重新申请内存空间,每次申请的空间是『临时』的,创建时申请空间,使用完自动释放空间
◆ 回到开头 @ 目录
内存
指针
常见问题解答
◆ 其他博客 @ https://blog.csdn.net/weixin_42194161
◆ 相关博客
探索篇 | C简单实现『字符动画』
探索篇 | C实现猜数字游戏
感谢阅读本篇博客,如果有不错的建议或意见,欢迎在评论区留言,喜欢的话,麻烦点个赞和关注哦~~~