重新温习了一遍 C 的指针,感觉当前(也就是前年)不明白的地方现在真的有种豁然开朗的感觉。
# Memory in C
# Static Memory
- 全局变量,可以被整个程序访问到。
- static 关键字描述的局部变量,也和全局变量类似,在程序运行时就会完成初始化,但是它对其他程序隐藏。(虽然是局部变量,但是在程序运行时进行初始化)
# Stack Memory
- 局部变量将会在函数结束时候进行回收。
# Heap Memory
- 由程序员进行申请的变量,需要自己进行 free,否则会有内存溢出。
# what is pointer?
指针说白了就是一个 int64 的值,这个 int64 的值指向了内存的地址空间,理论上来说,C 语言中所有的变量都可以用指针来描述,因为它们也是保存在内存中的。
来看这个例子:
char* makeABC() { | |
char y[3] = {'a', 'b', 'c'}; | |
return y; | |
} | |
int main() | |
{ | |
char * t= makeABC(); | |
printf("%s", t); | |
exit(0); | |
} |
这个函数会报错,会说 y 不是 const char *
。原因就是 y
字符数组是局部变量,因此在函数结束后就会被堆栈进行回收,无法进行返回。
一个非常有意思的改动:
char* makeABC() { | |
char y[3] = {'a', 'b', 'c'}; | |
char *p = y; | |
return p; | |
} |
成功打印了输出!
abc
再对 main 函数进行修改:
int main() | |
{ | |
char * t= makeABC(); | |
sleep(3); | |
printf("%s", t); | |
exit(0); | |
} |
输出结果:
看上去出现了内存溢出,这是因为在 C 中,堆栈回收不是删除数据,而是直接将堆栈的指针复位。原本内存的数据通过指针 p 进行访问,但是这段内存段可能正在 main
函数 sleep
3s 的时候,被别的程序写,这就导致出现了乱码。
# 强制类型转换
上面已经提到了,程序运行时数据保存在以 01 方式保存在内存中,那么我们如何将这些 01 数据变成我们需要的类型。这就编译器做的。
int a = 2; | |
float b = (float)a; | |
printf("%f \n", b); |
上面两行代码就是简单的类型转换,做的事情就是编译器先把一段 01 数据转换为 int 类型的 2,再将 int 类型转换 float 类型。
# 指针类型转换
指针其实就是一个 int64 的值,它指向了一段内存地址,这个内存里的值到底是什么,就需要编译器来处理。
所以如果对指针进行类型转换,比如:
int a = 2; | |
float* b = (float*)&a | |
printf("%f \n", *b); |
这个代码告诉编译器,请把保存变量 a 的内存地址中的 01bit 数据解释为 float 类型保存的数据。
打印输出: 0.000000
这是因为 float 类型的保存为:
int 2,在内存中保存为 10
。转换为 float 类型来解释后,这个 01
就是尾数,打印输出时候就会忽略,因为就打印了 0.00000。
# 特殊的 Void 指针
void 指针有点像 go 里面的空接口,可以传递任何类型的指针。