Python 注释
Python的注释方法如下:
- 使用#开头
- 使用三个单引号’’’ 主要用在块注释上
- 使用三个双引号””” 主要用在块注释上
lambda是一个表达式,而不是一个语句,它能够出现在Python语法不允许def出现的地方。
lambda可以用来编写简单的函数,而def用来处理更强大的任务。
比如下面的例子:
1 | add1 = lambda x,y : x + y |
从上面的代码可以看出,labmda表达式是为了减少单行函数的定义而存在的。
lambda的使用大量简化了代码,使得代码简洁、清晰。
常量是一旦初始化后就不能改变的变量,在C++中使用const指定常量。
计算机内存中的一块区域,变量可以存储任何事,而且可以改变。
1 | a = 1 |
1 | _a = 1 |
这里有一个global的关键字,如果没有这个关键字是不对的,结果可能对,但是实际的运行不是你认为的那样
1 | _a = 1 |
define
宏是在预处理阶段展开。const
常量是编译运行阶段使用。define
宏没有类型,不做任何类型检查,仅仅是展开。const
常量有具体的类型,在编译阶段会执行类型检查。define
宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。const
常量会在内存中分配(可以是堆中也可以是栈中)。const
定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而 #define定义的常量在内存中有若干个拷贝。
编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
作为常量,两者都有很多的应用,在一个程序里面看不到const
和define
的可能性不大。
C++ 语言可以用const
来定义常量,也可以用#define
来定义常量。但是前者比后者有更多的优点:比较重要的是const
常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误(边际效应)。
得到随机数的代码:
1 | srand(time(NULL)); //use clock value as starting seed。这个保证每次出来的随机数都不同 |
在做for循环的时候,循环控制变量也可以是一个浮点类型的变量。例如:
for(double x = 1.0; x < 11; x += 1.0),但是由于浮点类型在计算机内部的表示形式,决定了分数值通常没有浮点数形式的精确表示,所以不应该把相等判断作为结束循环的条件,比如x != 2.0,就可能一直打不到要求。
与大多数现代编程语言一样,C语言也没有输入输出的能力,所有这类操作都由标准库中的函数提供。
stderr
流只是将来自C库的错误信息传送出去,也可以将自己的错误信息传送给stderr
。
stderr
和stdout
之间的主要差别是,输出到stdout
的流在内存上缓存,所以写入stdout
的数据不会马上送到设备上,而stderr
不缓存,所以写入到stderr
的数据会立刻传送到设备上。
对于缓存的流,程序会在内存中传入或传出缓存区域的数据,在物理设备上传入或传出数据可以异步进行。这使输入输出比较高效,而为错误信息使用不缓存的流,其优点是可以确保错误信息显示出来,但输出操作是低效的。缓存的流比较高效,但是如果程序因某种原因失败,缓存的流就不会刷新,所以输出可能永远不会显示出来。
scanf
会忽略空白字符scanf
和printf
中有个格式控制符%n
:表示输出有效字符的数量。
N多的scanf
参数也可以保证,你可以用许多方式得到自己希望得到的数据。
但是有一点需要注意,就是scanf
对输入格式很挑剔,稍微错一点就会导致整个读取输入出错。
scanf
的格式控制符%s
只能读取不含空格的字符串,但是%[]
可以读取包含空格的字符串,比如I love you,就可以全部读取。
scanf
的陷阱对于字符串输入,使用gets或fgets通常是首选方式,除非要控制字符串的内容。
这一节接触的都是新东西,hold住。
数据运算符顾名思义就是对数据进行操作的运算符,这里设计到几个新概念,如果刚开始不了解,也没有关系,毕竟是进阶的东西,先大概看一下有个基础概念,因为这一次我们接触到了C语言中最难懂也是最优雅的指针,此处有掌声。
数据运算符有下面几个:
数据运算符 | 含义 |
---|---|
sizeof() | 获取xx的大小,返回字节长度 |
[] | 数组 |
& | 取地址 |
* | 定义指针或者解指针 |
-> | 结构体解应用 |
. | 结构体应用 |
详细说说这几个的具体含义:
sizeof(xx)
:这个比较简单,就是计算xx的字节长度;[]
:数组的定义方式,比如int a[10]就是定义了一个一维的整数数组,这个数组长度为10,但是有个问题要注意了,数组的长度从0开始,所以如果访问数组a
,只能是a[0]到a[9]
,如果下标是10就越界报错了,其实ANSI也曾尝试着把这个下标从1开始矫正过来,但是几十年的传统还有兼容性,此事只能作罢;&
:取地址是取一个变量的地址,比如int a=0
;我们顶一个了一个整数a
,它的值是0
,那么它位于哪里呢,这个就类似于你叫张三,你家的地址在桃花坞里桃花庵,桃花庵里第一间,另注意这个符号在C++
里面是引用的含义,不要混淆;*
:这个星号就大有来头了,前后左右的含义不一样,古往今来也很很多人栽进去了,就是因为这个隐晦又高效的指针,所以有了一本书叫做《C和指针》,专门来讲讲这个东西,后面我们也会 有系列小篇,争取能让大家越过这个坎,那就算是C语言里面的高手了;->和.
:这两个的区别主要在于结构体,如果定义的结构体是指针用->
,如果不是用.
,这个我也迷惑过。看个例子来show一下:
这个例子又新增了一些东西,除了上面描述的运算符,我们增加了一个头文件string.h
,这个用来后面调用strcpy
函数,另外还使用了结构体,下一节来聊聊必须要使用的结构体。
1 | /*advance/operator/operator3.c*/ |
相应地Makefile
如下所示:
1 | #advance/operator/Makefile |
输入make
,然后./operator3
输出为:
1 | sizeof(a) is 4 |
Q&A :上上节的答案,为什么a没有赋值却有这么大的值,这个涉及到后面会说到的全局变量和局部变量的区别,局部变量在未初始化之前,有可能是任何值,所以为防意外,变量定义最好都要初始化。