《C和指针》笔记 1-5

第一章
1,可以利用特殊数或字符作为输入停止的标志(信息数)

2,注释,以/*开始,以 星号/结束,注释不可以嵌套,容易注释掉内层的代码,不建议用注释的方法屏蔽一段代码,在逻辑上从源文件去除一段代码可以用 #if 0
想去掉的代码
#endif

3,预处理指令,如#include<stdio.h> 它是由预处理器解释的,预处理器读入源代码,根据预处理指令对其进行修改,然后把修改过的源代码交给编译器,
如#include<stdio.h>,预处理器用名叫stdio.h的库函数头文件的内容替换掉第一条#include指令,其结果仿佛stdio.h的内容被逐字写到源文件的那个位置,常见库函数头文件 stdio.h,标准输入输出库,进行IO操作必要
stdlib.h,标准库函数头文件,定义了五种类型,一些宏和通用函数工具
string.h,字符串处理函数的头文件,可调用字符串处理函数

tip:当又一些声明需要几个不同的源文件,可以在一个单独的文件中编写这些声明,然后用#include指令把这个文件包含到需要使用这些声明的源文件里,避免了多次使用出错

4,预处理指令#define,如 #define MAX_PEN 20 ,多用大写用来区分并非普通变量,它会把MAX_PEN定义为20,当这个MAX_PEN出现在源文件的任何地方时,它就会被换成定义了的值,它们被定义为字面值常量!,不可出现在赋值符左边等普通变量可以出现的地方

5,函数原型,如 int pen_numbers ( int pens[ ], int max);它们告诉编译器以后将在源文件定义的函数的特征,每个函数原型以一个类型开头,表示函数返回值的类型,跟在返回类型后的是函数的名字,在后面是函数期望接受的参数

tip:指针指定一个存储于计算机内存中的值的地址,但C语言对数组下标引用和指针访问并不进行有效性检查,这提高了它的效率但也增加了出错的可能性

6,每个C程序都有main函数,它是程序开始执行的起点,int main(void)关键字 int表示函数返回一个整型值,关键字void表示函数不接受任何参数,以{ }为界,在main函数内声明的变量都是局部变量,其它函数不可以根据它们的名字访问它们,但是,它们可以作为参数传递给其它函数,所有传递给函数的参数都是按值传递的,但当数组名作为参数就会产生引用传递的效果

7,字符串,字符串是一串以NUL字节结尾的字符,NUL(ASCII码中\0字符的名字)是字符终止符,无法通过键盘输入,并不是字符串内的一部分,它的字节模式为全0,NULL是一个值为0的指针

8,常见printf打印格式,%d 以十进制打印一个数,%o 以八进制打印一个数,%x 以十六进制打印一个数,%g 根据结果自动选择科学记数法或小数记数法打印浮点值,取决于输出时宽度小的一种, %c 打印一个字符 ,%s 打印一个字符串, \n 换行

tip:局***部变量在定义后需要初始化,如果不初始化,就是垃圾数据,无意义***
scanf函数其所有标量参数前必须加&,数组参数前不需加&,但是,如果数组参数出现了下标引用,即实参是数组的某个特定元素,那它前面也要加&

9,对于内存空间的使用需谨慎,如果申请了一个空间,向其中加入了过多的值,那么过多的值会存储在紧随数组元素后的内存位置,就会破坏原先这个内存里存储的数据,会产生无法预料的错误后果

tip:用于测试两个表达式是否相等用的是==,而不是=,=是赋值符把后面的量赋值给前面,return语句就是函数向调用它的表达式返回给一个值
可以用#define预处理指令给字面值常量取个符号名

第二章 基本概念
1,环境,C程序在实现的过程中存在两种不同的环境,第一种是翻译环境,在这个环境里,源码被转换为可执行的机器指令,第二种是执行环境,用于实际执行代码,值得注意的是,这两个环境不必位于同一台机器上

翻译阶段,首先是预处理器处理,在这个阶段,预处理器在源代码上执行一些文本操作,如,用实际值代替#define定义的符号以及读入由#include指令包含的文件内容,然后,源代码经过解析,产生机器指令的初步形式

执行阶段,首先将程序载入内存中,此任务由操作系统完成,那些不是存储在堆栈中的尚未初始化的变量也将此时得到初始值,然后开始执行程序代码,大部分机器中,程序将使用一个运行时堆栈,它用于存储函数的局部变量和返回地址,最后正常终止时即是main函数的返回

2,注释,源代码中一个注释可能跨越多行,但它不能嵌套于另一个注释,所有的注释部分会在翻译阶段被预处理器拿掉,取而代之的是一个空格

tip:相邻的标记或操作符之间要有空格,可以使表达式的可读性更佳,良好的编程风格能够大大提高程序的可读性,使程序更容易运行,更方便维护

第三章 数据
1,变量可视性(在什么地方使用)和变量的生命期(它的值将保持多久)
由变量的三个属性:作用域,链接属性,存储类型

2,C中仅有4中基本数据类型-整型,浮点型,指针,聚合类型(数组 结构体
其他的类型由着几种派生而来

3-整型家族包括:字符,短整型,整型和长整型,它们都分为有符号或无符号,对于char,它虽然用来容纳字符型值,但其本质是小整型值

tip:当可移植问题比较重要时,字符是否为有符号数就会带来疑虑,最佳妥协方案是把存储于char类型变量的值限制在有符号(-127-128)和无符号(0-255)间,这样可以最大获得可移植性

4-字面值:是字面值常量的缩写,它是一种实体,指定了自身的值,并且不允许发生改变,它与普通变量有些相似,但它被初始化后,它的值便不会变
在字面值后面加后缀可以改变其类型,另外还有字符常量,它们的类型总是int,字符常量后面不能加后缀

tip:浮点类型中C对所有未定义的浮点值默认类型为double类型

5-指针:变量的值存储于计算机内,每个变量占据一个特定的位置,每个内存位置都有地址唯一确定并引用,就像一条街上的房子由它们的门牌号辨别一样,指针只是地址的另一个名字罢了,指针变量就是一个其值为另一个内存地址的变量

6-字符串常量:字符串在C语言的概念是-一串以‘/0’字节结尾的零个或多个字符
字符串通常存储在字符数组中,所以C中并没有字符串类型,作为结束标志的0字符是不可打印的ASCII码,即使是空字符串,结尾也含有一个不可见的0结束标志,正所谓字符串 遇0则止

tip:当我们把字符串常量(“ABCD”)和指针放在一起讨论时,会发现,在程序中使用字符串常量会生成一个“指向字符的常量指针”,当一个字符串常量出现在一个表达式中,表达式所使用的值就是这些字符所存储的地址(而不是这些字符本身),所以,我们可以把字符串常量赋值给一个“指向字符的指针”,后者指向这些字符所存储的地址,但是,不可以把字符串常量赋值给一个字符数组,因为字符串常量的直接值是一个指针,而不是这些字符本身
在给字符数组赋初值时,给的是字符串的地址,不是字符串本身

7- 声明简单数组和指针
声明一维数组: 类型名 数组名[长度] = {…}
数组下标从0开始,最后一个元素的下标是元素的数目减一,值得注意的是,编译器并不检查程序对数组下标的引用是否在数组的合法范围内,这种不加检查的行为有好有坏,好处是不用浪费时间检查对的下标,提高效率,坏处是这样使无效的下标引用无法检测出来,并且出现更严重的问题

声明指针:先给出一个基本类型,紧随其后是一个标识符列表,这些标识符组成表达式,用于产生基本类型的变量 即 int *a
int *a 意为表达式部分 星号a 产生的结果类型为int,星号操作符执行的是间接访问(间接寻址),所以我们知道了a是一个指向int的指针
间接访问-间接访问操作只是针对指针变量才是合法的,指针指向结果值,对指针间接访问的操作可以获得这个结果值
在声明指针变量时,也可指定它的初始值, 如 char *message = “hello!”
这条语句把message声明为一个指向char类型的指针,并用该字符串常量的第一个字符的地址对该指针进行初始化在这里 字符串常量是赋值给了message本身,可看作 char *message; message = “hello!”

8-typedef 的使用:typedef允许我们为各种数据类型定义新名字,用法 即和普通的声明基本相同,只是把typedef这个关键字放到声明的前面,
如 char *ptr_to_char
先把变量ptr_to_char声明为一个指向字符的指针
typedef char *ptr_to_char
这个声明意为把标识符ptr_to_char作为指向字符的指针类型的新名字
如 ptr_to_char a 就会声明 a是一个指向字符的指针
使用typedef可以避免声明又臭又长,且在定义较复杂的类型名字时,如函数指针或指针数组的指针,使用tyedef更为合适,#define无法正确的处理指针类型 如 #define d_ptr_to_char char *
d_ptr_to_char a,b 这里正确的声明了a 但b却被声明为一个字符

9-常量:常量的样子和变量一样,只是其数值不可修改,我们可以用const来声明常量,如 int const a = 10;此时a是一个整数,其值不可以被修改,
#define指令是另一种创建名字常量的机制,如 #define MAX_NUM = 10;
对比 int const max_num = 10;这种情况下使用#define比使用const变量更好,因为只要允许使用字面值常量的地方都可以使用前者,比如声明数组的长度,const变量只能用于允许使用变量的地方

tip:用名字常量定义数组的长度或限制循环的计数器可以提高程序的可维护性,如果要修改一个字面常量,只需修改一次即可

10-作用域:当变量在程序的某个部分被声明时,它只有在程序得一定区域才能被访问,这个区域由标识符得作用域(程序中该标识符可以被使用的区域
如 函数的局部变量的作用域仅局限于该函数体,这个规则意味着,首先,其他函数都无法通过这些变量的名字访问它们,因为这些变量在它们的作用域外便不再有效,其次,只要分属不同的作用域,我们可以给不同的变量起同一个名字 编译器可以确定四种不同类型的作用域-文件作用域,函数作用域
,代码块作用域和原型作用域,表示符声明的位置决定它的作用域

代码块作用域:位于一对花括号内的所有语句称为一个代码块,任何在代码块开始的位置声明的标识符都具有代码块作用域,它表示可以被这个代码块中的所有语句访问,应该避免在嵌套的代码块中出现相同的变量名,容易引起混淆,不是嵌套的代码块有些不同,声明于每个代码块的变量无法被另一个代码块访问,两个非嵌套代码块最多只有一个处于活动状态

文件作用域: 任何在代码块之外声明的标识符都具有文件作用域,它表示这些标识符从它们的声明处到其所在的源文件结束为止都是可以被访问的,在文件中编写并通过#include指令包含到其他文件中的声明就像是把它们直接写到那些文件中一样,它们的作用域并不局限于头文件的文件尾

原型作用域:只适用于在函数原型中声明的函数名(函数部分) 未完!

函数作用域:它只适用于语句标签,语句标签用于goto语句,一条规则,一个函数中的语句标签必须唯一

11-链接属性:当组成一个程序的各个源文件分别被编译后,所有目标文件以及那些从一个或多个函数库中引用的函数链接在一起,形成可执行程序
标识符的作用域与它的链接属性有关,但这两个属性并不相同
链接属性共三种: 外部(external),内部(internal),无(none)
无(none),没有链接属性的标识符(none)总被当作单独的个体,即该标识符的多个声明被当作独立不同的实体
内部(internal),属于internal链接属性的标识符在同一个源文件内的所有
声明中都指向同一个实体,但位于不同源文件的多个声明则分属不同的实体
外部(external),属于external链接属性的标识符不论声明多少次,位于几个源文件都表同一个实体

tip:关键字 extern和static用于在声明中修改标识符的链接属性
若某个标识符本是external属性,在它前面加上static即可使它的链接属性变为internal 如, static int a;那么变量a就变为这个源文件私有,在其它源文件中,也存在一个a,那么这二者的作用域就不同,static仅对缺省链接属性的external的声明才有改变链接属性的效果
extern一般可以为一个标识符指定extern链接属性,这样就可以访问在其它位置定义的这个实体

12-存储类型:变量的存储类是指存储变量值的内存类型,变量的存储类型决定变量何时创建,合适销毁,以及其值将保留多久,有三个地方可以存储变量:普通内存,运行时堆栈,硬件寄存器,存在这三个地方的变量具有不同的特性
变量的缺省存储类型取决于它的声明位置,凡是在任何代码块之外的声明的变量总是存储于静态内存中,也就是不属于堆栈的内存,这类变量成为静态变量,无法为它指定其他值,静态变量在程序运行前创建,在程序执行时始终存在,它始终保持原先的值,除非给它赋一个值或程序结束

在代码块内部声明的变量的缺省存储类型是自动的,也就是它存在于堆栈中
称为自动变量,自动变量在代码块执行完毕后就消失,当代码块再次执行时,它们的值并不是上次执行时的值,如果给代码块内部声明的变量加上static,可以使它的存储类型从自动变为静态,具有静态存储类型的变量在
整个程序执行过程中一直存在,而不仅在声明它的代码块的执行时一直存在
但修改变量的存储类型并不代表修改其作用域,它仍只能在该代码块内部按
名字访问 函数的形参不能声明为静态

关键字register可以用于自动变量的声明,提示它们应该存储于机器的硬件寄存器而不是内存中,这类变量称为寄存器变量,通常,寄存器变量比存储于内存的变量访问起来效率更高

13-作用域,链接属性和存储类型总结
在这里插入图片描述
tip:存储于堆栈的变量只有当该代码块活动时,才能保持自己的值,当程序离开该代码块时,这些变量的值将丢失
并非存储于堆栈的变量在程序开始执行时创建,并在整个程序执行时一直保持它们的值,不管它们是全局还是局部变量

第四章 语句

1-空语句:本身只包含一个分号,空语句并不执行任何任务
表达式语句:C中并不存在专门的赋值语句,赋值就是一种操作,在表达式内部进行
代码块:位于一对花括号内的声明和语句

2-C中并不具有布尔类型,而是用整型来代替,零值表示假,非零表示真

tip:尽管所有的非零值都被认为是真,但把两个不同的非零值进行相等比较,其结果确是假
if-else如果嵌套使用,else字句服从就近原则,它从属于最靠近它的不完整的if语句

3-break和continue(while内):while中使用break语句可以永久终止循环
while中用continue,可以终止当前的循环,接下来会重新测试表达式的值,决定是否继续执行
break和continue如果出现在嵌套循环内部,只对最内层循环起作用,不可以使用break和continue语句影响外层循环

do语句,可以使循环体至少执行一次

4-for语句:执行流程-初-条-体-步-条-体-步-条…
for嵌套时,外层循环一次,内层循环完,在执行外层的第二次
for中使用break和continue,break可立刻退出循环,而continue语句把控制流直接转移到步长操作,在判断下次是否可以循环

5-switch语句:switch(条表),其条表结果必须为整型值
switch常与case和break联系在一起使用,每个case都必须有唯一的一个值
case标签并不是把语句列表划分为几个部分,它们只是确定语句列表的进入点,switch的执行流程,先计算条表的值,然后执行流转到语句列表中case与条表的值匹配的语句,如果在switch中遇到了break,执行流会立刻跳到语句的结尾,大部分程序每个case内都有一个break,这里break的效果实际是把语句列表划分为不同的部分,switch语句中continue是无效的

6-default子句:default子句可以出现在switch中case出现的位置,当switch的条表不匹配所有case中的内容时,这个default子句中的语句就会执行,在每个switch语句中只能出现一条default子句,在每个switch语句中加上一个default子句是个很有用的习惯

7-goto语句:goto 语句标签(跳转标签);可以在任意地方中断当前流程直接跳转到相应位置
使用goto语句,要在希望跳转的语句前加上语句标签,语句标签就是标识符后面加个冒号,包含这些标签的goto语句可以出现在同一个函数的任意位置,能不用尽量不用,易使程序不清晰,变得不可跟踪,出错可能增多

tip:C并不具备任何输入输出语句,I/O是通过调用库函数实现的,C也不具备任何异常处理语句,它们也是调用库函数实现的

第五章 操作符和表达式

1-算术操作符:+ - * / %,出了取余其它操作符均适于浮点类型和整数类型
取余%返回的值是余数不是商

2-位移操作符:左移位操作符: << 右移位操作符: >>
使用 value << n(n位移动位数)左值将移动右值指定的位数
移位操作是把一个值得位向左或向右移动,左移中值最左边的几位被丢弃,右边多出来的空位由0补齐
右移位有两种情况,逻辑移位(左边空的用0补齐)和算术移位(左边补0或1,看原值的符号位是0还是1)

3-位操作符和单目操作符
位操作符对它们的操作数各个位执行 和,或,异或逻辑操作
位操作符: & 和,位位匹配,全1为1,有0为0
| 或,位位匹配,有1为1,全0为0
^ 异或, 位位匹配,同值为假,相异为真
位操作符要求操作数位整型类型,运用位操作符可以把指定的位变为0或1

~ 用于对操作数进行求补运算,即原先为1的位变为0,0变1
!对操作数进行1反逻辑操作,颠倒原先操作数的值,取反
& 将产生它的操作数的地址
*间接访问操作符,它与指针一起用,用于访问指针所指向的值
下标引用[],接受两个参数,数组名和索引值,下标引用操作和间接访问表达式是等价的

4-关系操作符:用于测试操作数之间的关系
如> >= < <= != == 关系操作符的结果为整型

tip:注意 = 是赋值操作符, ==判断两个值是否相等,不可混用
程序不正常时,可以检查一下操作符是否写错

5-逻辑操作符:&& 和 || 用于对表达式求值,判断其值是真还是假
短路运算,逻辑操作符&&的左边已确定为假那么忽略右边真假
||左边已确定为真那么忽略右边真假
逻辑运算符和位操作符不可混用,逻辑操作符判断表达式的真假,位操作符用于比较它们操作数中对应的位

6-左值和右值:左***值出现在赋值号左边,可以标识一个可以存储结果值得地点,我们可以在之后得程序中引用它,字面值常量不可以是左值,右值即是一个可以出现在赋值号右边的量
左值意为一个位置,右值意为一个数值***
在使用右值的地方可以用左值(a=&b),但需要左值的地方不可用右值
有些操作符,如间接访问和下标引用,它们得结果是一个左值

tip:C中并不具备显示的布尔类型,布尔值用整型表达式代替,但在表达式中混用布尔值和任意类型的整型值会出错,不要对整型变量进行布尔值测试
两个不同的非零值比较,结果是 假

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值