[c 要点回顾]《C 程序设计新思维》 第6 - 8 章笔记
首先,这本书还是蛮值得一看的,然后呢,前六章是一些有用的工具的介绍。
第 6 章 玩转指针
6. 1 自动,静态 和手工内存
C 提供三种内存管理的模式,理解这三种概念,对于我们理解变量,寻找类似核心已转移的bug有莫大的帮助。
自动
当我们声明一个变量后,当程序离开他的作用域后,就会被程序销毁
静态
函数外部声明的(文件作用域) 和 函数内部使用static 声明的都是静态的,他们会在整个程序生命周期内存在。且如果没有初始化,默认为0(NULL)
所以我们可以看出,静态变量也是一种自动管理的模式,只不过作用域是文件作用域。
手动
即,malloc free ,也是唯一一种,在声明之后改变数组长度的方式(使用 realloc() )
注意,这也是手动申请的数组无法使用sizeof来测量大小的原因
补充一下:
堆栈和栈:
任何函数都在内存中占据一个空间,称为函数帧,用以保存,与这个函数相关的信息,
例如,一个函数执行后返回到哪里,以及保存所有自动分配的变量的空间
当一个函数调用另一个函数的时候,第一个函数的函数帧中的活动就会暂停,并且一个心得函数被添加到这个函数帧中去,当函数执行完毕后,它的函数帧就会弹出,所有保存在这个函数帧的所有变量都会消失,这就是自动的变量管理的方式
注意的是这个堆栈的大小一般为2~3M 所以,当需要更多的更加自由的管理方式的时候,我们就调用malloc ,从堆中要一块内存,归自己管理,而这个堆就是内存的大小。这也是及时使用free的重要性。
这是使用static 实现斐波那契数列的一个方式
/************************************************************************* > File Name: staticTest.c > Author:Gin.TaMa > Mail:1137554811@qq.com > Created Time: 2019年03月20日 星期三 14时42分53秒 ************************************************************************/
#include<stdio.h>
long long int fib(){
static long long int first = 0;
static long long int second = 1;
long long int out = first + second;
first = second;
second = out;
return out;
}
int main(){
for(int i = 0;i < 10;i ++){
printf("%lld\n",fib());
}
return 0;
}
以及一个有意思的bug
/************************************************************************* > File Name: staticBug.c > Author:Gin.TaMa > Mail:1137554811@qq.com > Created Time: 2019年03月20日 星期三 14时46分40秒 ************************************************************************/
#include<stdio.h>
char* aToA(char a){
static char A;
A = a + 'A' - 'a';
return &A;
}
void test(char* a){
printf("a = %c\n",*a);
// 没有改变a的注意
char* b = aToA('b');
printf("a = %c ; b = %c\n",*a,*b);
// a的值改变了
}
int main(){
char* a = aToA('a');
printf("a = %c\n",*a);
test(a);
return 0;
}
猜一下结果是不是这样的呢?
a = A
a = A
a = B ; b = B
这个bug一开始找了我半天。。
关键是我是调用别实现的aToA()这样类似的函数。
这其实是叫做别名和赋值的区别
当我们告诉计算机把a设置成b的时候有两种意义
别名,赋值。
a 为 b的别名:意味着,修改a,就是在修改b。
a 为b的赋值: 意味着a与b仅是有相同的值,但是没有半毛钱的关系。
这里就要注意了,
结构被复制,数组创建别名
当一个结构体b里有一个数组的时候,
你想将b的值赋值给a,很有可能,a的数组是b的数组的别名,也就意味着,你修改了a的数组元素,就是在修改b的数组
* 的解释
关于* 其实是一个不好的设计,它把两种情况杂糅到了一起,需要你依据上下文判断他的意思。
它违背了所谓的**“功能截然不同的事务,看上去应该明显不一样”**
注意 * 在声明中,代表指针。在其他地方代表取指针指向的内容。
所以
int* i = 3; // WRONG
int* i = malloc(sizeof(int)); // OK
*i = 3; // OK
记住这个就OK了。
第 7 章,没啥意思。
第8 章
8.1 营造健壮和繁荣的宏
<mark>宏的本质是一种没有脑子的文本替换</mark>
-
()括号,一定要加
-
{}也要加
-
避免重复作用
#define max(a,b) (((a) > (b)) ? (a) : (b))
这个是有隐患的比如 max(i ++ ,x ) i 会被加两次。。
补充
_VA_ARG_ 这是变参宏获得变量的关键字
变参宏的一种用法。。
define printf_debug(format,...) printf(__FILE__"(%s:%d)"format"", __FUNCTION__, __LINE__, ##__VA_ARGS__)
8.3 const 关键字
注意 <mark>const 是一种文法,而不是一种锁</mark>
理解const的关键是从右向左阅读,并且注意,const作用于const左边的文本就像* 一样。
int const = 一个(不变的)整数常量
int const * = 指向一个(不变的)整数常量的(可以变的)变量指针
int * const = 指向一个(可以变的)变量整数 的(不变的)常亮指针
注意 常量结构的成员并不是常量。
OK 不。