学习篇 | 初识C语言----内存&指针

导语 

本篇博客是针对C语言学习中遇到的一大难题『指针』所做总结, 以此互勉.

学习篇 | 初识C语言----内存&指针_第1张图片

目录

导语 

内存

指针

常见问题解答:


内存

学习指针, 一定要先了解一下内存, 内存是电脑上特别重要的存储器, 计算机中的所有程序的运行都是在内存中进行的.

 

所以为了有效的使用内存, 就把内存划分成一个个小的内存单元, 每个内存单元的大小是1个字节, 为了能够有效的访问到内存的每个单元, 就给内存单元进行了编号, 这些编号被称之为该内存单元的地址.

 

学习篇 | 初识C语言----内存&指针_第2张图片

 

一波代码强入:

int main()
{
   int a = 10;      //int整型向内存申请了4个字节的空间
   return 0;
}

学习篇 | 初识C语言----内存&指针_第3张图片

这里注意:地址随机分配, 每次执行程序, 地址一般都会改变, 但规律不变

 


指针

在计算机科学中, 指针(Pointer)是编程语言中的一个对象, 利用地址, 它的值直接指向(points to)存在电脑存储器中另一个地方的值. 由于通过地址能找到所需的变量单元, 可以说, 地址指向该变量单元. 因此, 将地址形象化的称为“指针”. 意思是通过它能找到以它为地址的内存单元.

int main()
{
   int a = 10;      //int整型向内存申请了4个字节的空间
   //&a -- 取地址,得到 a 的首地址,地址也是一个数值,
   //把这个数值用一个变量保存,此时这个变量的类型是(int*)类型
   int* p = &a;     //这个变量叫做指针变量, 指针变量是用来存放地址的
   return 0;
}

指针变量就是用来存放地址的, 在指针变量的眼里, 它所存储的就是一个地址

学习篇 | 初识C语言----内存&指针_第4张图片

◆ 指针的使用

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;
}

输出结果:

 学习篇 | 初识C语言----内存&指针_第5张图片

指针和指针类型

我们都知道, 变量有不同的类型, 整形, 浮点型等. 那指针有没有类型呢?准确的说:有的. 

 

当有这样的代码:

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;
}

学习篇 | 初识C语言----内存&指针_第6张图片

输出结果:

&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实现猜数字游戏

 

感谢阅读本篇博客,如果有不错的建议或意见,欢迎在评论区留言,喜欢的话,麻烦点个赞和关注哦~~~


 

你可能感兴趣的:(01.C语言,11.学习篇)