C语言常见指针应用-Half_word编写
C语言常见指针应用
-Half_word编写
简单级别:
前言:
首先简单回顾一下:C语言普通变量名/标号代表队<int Alex = 32; char Tina = ‘a’… …>
这是初学C语言时候‘结识’的‘好汉’ ;对于其使用不再赘述(无外乎赋值,逻辑运算等)。本章来聊一聊这些普通的变量的“深层“内涵;一个变量的声明等同于给内存中某个地址单元起别名,而赋值等操作等价于在这个单元上进行的各类值传递(可以从下表窥探一二);变量具体占内存空间(通俗而言就是有多少个单元)由声明的类型决定。

传递给变量的值可以多种,只要合法(与声明时的类型对应)。
这样的变量使用较为简单,但是… …,有这样的需求:每次给这个变量赋值都要拿出变量名,一两个倒是能接受,要是有一堆变量(万一类型还各不一样),重复度太高。我想高效点,用一个东西就可以改变他们所有的值。So,我们需要找出这些类型不同的变量之间的“通信证“----内存地址。
计算机的角度看:程序皆数据;所以得地址者得天下
所以,引出今天的“难一号”----指针;有同学会问,指针不是也只能存放对应类型的地址吗?
这个答案并不对,既然是地址,就没有类型之分,它只是记录一个相对的偏移量数值,因此其大小是个定值。
那得到地址后如何区分该进行哪些数据的修改呢?
这一问题的答案刚好解释前一问题。能修改多少取决于你给这个指针的类型决定(比如这个指针是char* p;那么它指向的地址单元起你可以修改sizeof(char)个字节)。
意味着:指针仅仅得到了一个地址值,天下指针一个样。
实例:
char* p1 = &Tina;
int* p2 = &Alex;

(PS: 要是有童鞋喜欢钻研可以声明多个不同类型的指针,通过sizeof运算符检验它们的大小,你会得出上述结论的)
!!!既然天下指针“都一样“;为了方便,我们一个指针是不是就可以开遍整个“小区”呢?YES,不过需要一些手段----强制类型转换
(PS: 有些类型的强制转换过于繁琐,有的甚至你找不出对应的强制转换类别,即可以声明那种指针。但是强制类型转换那种指针编译器不能通过)


至于更多的类型值修改,参照上述方案,需要自己动手好好揣摩其中的转换。
(PS:指针本身也是一个内存中的数据;所以,只要指的好,指针也能变工具人的工具)
所以在今后的指针使用中应当注意的是指向的类型大小, 对于指针本身而言在其次。
练一练:
char arr[9] = “ABCDEF”;
int* p;
用p将arr内的字母变为小写。
总结:天下指针皆一家,只要目标的大小和地址已知,一个指针就能改遍内存
中级级别:
经过前面的学习,我们知道了指针是辅助修改内存中的值的这样一种特殊存在;
但是,我们会发现这样一个问题,那些基本变量类型大小都是丹尼斯·里奇的蓝图下给的,要修改就不得不找准大小,否则引起内存数据错乱,重则引发程序崩溃。
那么,有没有可以自由支配的大小内存块呢?
答案是有的,为了保证C语言的高灵活性(较之汇编等低级语言),malloc()函数应运而生。
从而也有了一系列的内存泄漏等等事故(🤣开玩笑的)。这个函数就是为了给用户申请自定义大小的内存空间并且返回该处内存空间首地址的“好东西“;
例如:int* p3 = malloc(1024);//向内存要了1024字节(1kb)的空间.
有了这个地址,我们就可以向一大片内存注入数据了。但是,一个地址一个地址的写数据又回归了机器语言的时代了。
我们需要规范的写入一系列有用的值(比如在这片内存记录下MM的QQ号、微信号、年龄(问就是18))。
所以我们就找到了C语言的模板设计师----struct结构体家族,帮助你管理申请的内存空间数据写入;具体设计操作见下代码:
struct MM_info {
char name[20];
unsiged char age;//150岁以上的就别管了,国家的
char Q_nub[11];
/*… …其它暂不定义写入… …*/
struct MM* next;
};
struct MM* info_A = malloc(1024);
现在我们就可以通过info_A这个有特定模板的指针对申请到的匿名内存进行读写操作了,具体操作由模板内的类型声明决定。
如:
info_A -> age = 1;
对于申请的内存在单次最大值限制,所以我们在实际工程开发的时候对于一个模板还会引入
一个指向这个模板类型的指针,并且用其存放下一个匿名内存块的起始地址;这就形成了一种链式的数据结构----链表。在链表的基础上延伸出的图、树此类皆是同原理,区别就是指针数目不同。
我们可以通过这些模板操作匿名内存,做一些高级的数据结构设计;甚至用这样的数据结构开发系统。
(具体有哪些数据结构和相关一些算法参考相关书籍,如:《趣学数据结构》等)
针对匿名内存,除申请和使用还应当注意的是释放内存,对于那些使用完的内存如果不释放就会产生开头所说的内存泄露了,对于内存来说这是灾难。
应当注意:每次malloc()等申请内存操作完成后皆需调用free()释放已用完的内存区,安全第一。

函数指针的出现使得原本就很复杂的指针类型圈又浓墨重彩的添加了一笔。
我们对于一个函数声明到定义,处理通常有两种处理思路:1.先声明后定义;2.直接给出定义,但是这种多见于单文件编译的情况。
既然是定义,就会在内存中占据空间,函数名(标号)显式的占据了空间,肯定会给出寻找这片内存起始地址的方法;没错,就是那个定义函数的的函数名,main函数也不例外的有它的起始地址(AT&T汇编结果显示其起始地址为0x0000,有兴趣的小伙伴可以通过gcc -S查看相关汇编代码)。
只要用指针找到这片内存就可以对其进行使用。这似乎和前面讲的简单的指针使用是一样的… …(细品品好像漏了点东西)
BUT函数还有一大重要的属性----参数;前面的内存里面的数据我们只是当成了数据并且进行相应的操作,对于函数标号所在的那片内存空间的数据,我们需要把它们看做一条条的指令而不是一大串数据。
因而声明一个函数指针时你需要进行有效的内存引导,而不能进行匿名内存的使用(除非您手写机器代码进该内存空间)

笔者水平有限,只能分享这些浅显的指针使用,如有不足处请多多指教