[c 要点回顾]《C 程序设计新思维》 第6 - 8 章笔记

[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:[email protected] 
	> 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:[email protected] 
	> 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 营造健壮和繁荣的宏

宏的本质是一种没有脑子的文本替换

  • ()括号,一定要加

  • {}也要加

  • 避免重复作用

    #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 关键字

注意 const 是一种文法,而不是一种锁

理解const的关键是从右向左阅读,并且注意,const作用于const左边的文本就像* 一样。

int const  = 一个(不变的)整数常量
int const * = 指向一个(不变的)整数常量的(可以变的)变量指针
int * const = 指向一个(可以变的)变量整数 的(不变的)常亮指针

注意 常量结构的成员并不是常量。

OK 不。

猜你喜欢

转载自blog.csdn.net/weixin_39722329/article/details/88750476