1、C 语言通俗.txt 单身很痛苦,单身久了更痛苦,前几天我看见一头母猪,都觉得它眉清目秀的什么叫残忍? 是男人,我就打断他三条腿;是公狗,我就打断它五条腿! 1.所有的语言都是一个原理,想理解就要明白计算机是如何工作的。 所有的数据在硬件上都是以 1 定义两个整数。 scanf(“%d%d“, 输入两个整数。 printf(“%dn“,a+b); 输入两个整数之和。 意思是:输入两个整数,输出它们的和。 输出结果的前后都不允许有空格。 6.假如你是一个杀猪的(够不够通俗?)C 是一块铁,VB 是一把文武刀,VF 是一把专起肉片的刀VF 主攻数据库,对基于数据库处理的前后端支持良好,是快速开发数
2、据库软件的利器。其他处理能力欠佳,就好像用起肉片的刀砍骨头。VB 比较中庸,window 上下层都可承接。文武刀起肉片也可以,不过就.C 跨平台,底层语言,功能强大,速度快。但,你要砍骨头的话,先要把这块铁打造成骨刀。你要起肉片的话,先要把这块铁打造成起肉片的刀。甚至你要挂猪肉的话,只要把这块铁打造成铁钩子。此外 3 者的编程语法不一样。 7.你要去某个人的家里,比如张三。你需要知道他家的地址,门牌号。变量,就相当于张三指针,就相当于地址,门牌号。8.指针是什么?初学时是不太好理解的,看多了就领会了。我就拿钟表(有指针的)做个例子:钟表的指针可以指向任意的是刻度,这里“钟表指针”就相当于我们说
3、的指针,它指向的刻度就相当于我们说的“数据地址“。当看到钟表指针指向某个时刻时 ,说明钟表指针所指的刻度是几点钟。用 C 语言中的指针翻译上面的话是:当指针指向某个数据,说明指针所指的地址的所放的数据是多少。如:int i=3,*p;/定义一个整型变量 i,i 里放的数据 3;定义一个指针 pp=/给定义的指针赋值(指针指向了变量 i,也就是指向了 i 所在的地址。 )指针 p 指向 i,说明指针所指的地址所放的数据时 3。“指针所指的地址所放的数据”可以用“p=程序在编译时,系统就会给这个变量i 分配 2 个字节的内存单元,而内存区的每个字节都有一个编号。假如系统把地址编号为2000 和 2
4、001 这两个内存单元分配给 i,则 2000 和 2001 中存放的是变量 i 的值 3,指针 p中则存放着变量 i 的起始地址,即 2000.就好像你去住酒店,指针就用来存放你的房间号,我只通过这个房间号就可以找到你。 10.+是先引用,后加,+i 是先加,后引用;如 i=2,执行 a=i+;则 a 的值为 2; 如 i=2,执行 a=+i;则 a 的值为 3;i+是右值,当成常量对待;+i 是左值,当成变量对待。 如语句:+i=3; 合法如语句:i+=3; 非法 这里我们先讲 i+ 不要记教材上的东西。 。始终记得,+在后,比如在赋值过程中 j = i+; 那么执行语句的流程是 j =
5、i; i = i + 1;也就是说先使用再自加。 如果 + 在 前,那么过程是相反的。那就是先自加再使用。比如 j = +i; 先自加是 i=i+1; 再使用 j = i;10.通俗点说:所谓“精度”可以理解为“精确的程度” 。假设单精度用 4 位数记录一个变量,双精度就是用两个单精度也就是 8 位来记录一个变量。比如 0.11111111,单精度下就只能记录 0.1111,双精度就能记录到 0.11111111。单精度和双精度都指浮点数,就是带小数点的数只不过单精度和双精度是为了区分有效数而已(也就是精确度),它的提法完全符合科学计算中对于数值的观念。 比如:单精度/双精度数值类型从一开始设
6、计的时候,就不是一个准确的数值类型,他只保证在他这个数值类型的精度之内是准确的,精度之外则不保证。P.S. 在 Turbo C 中单精度占 4 个字节(32 位)内存空间只能提供七位有效数字, 而双精度占 8 个字节(64 位)内存空间,可提供 16 位有效数字。 简单点,就是小数点后的位数越多,它就越精确,表示的范围越大!11.C 语言中到底有多少个关键字呢?木有错,ANSI C 规定是 32 个! 他们分别是:auto double int struct break else long switch case enum register typedef char extern return
7、 union const float short unsigned continue for signed void default goto sizeof volatile do if while static。别看那一堆了字母了,直接看下面的分类介绍:第一类:数据类型关键字这一类别的关键字有:char /声明字符型变量或函数double /声明双精度变量或函数enum /声明枚举类型float /声明浮点型变量或函数int /声明整型变量或函数long /声明长整型变量或函数short /声明短整型变量或函数signed /声明有符号类型变量或函数struct /声明结构体变量或函数uni
8、on /声明共用体数据类型unsigned /声明无符号类型变量或函数void /声明函数无返回值或无参数,声明无类型指针这一类别的关键字无需过多的说明,基本都是我们经常用到的,但是,仍然有些是我们需要注意的东西:C 标准并未定义指针、整数型(int) 、长型(long)为特定的位数目。在 32 位体系结构下,一般 int 和 long 都是 32 位长;值得注意的是,64 位机器下,很多程序设计环境,“int”变量仍然是 32 位宽, “long”和指针是 64 位宽。注意,这里说的只是一般情况下!详细的解释可以看这里.(64 位)union 声明的联合数据结构,里面的数据是共享内存的,可以
9、看脑袋一迷糊,人就容易犯二-union 题目今天跟赶场子似的匆匆赶去北邮笔试,题目不是很难,不过满脑子的浆糊,然后就犯了点 2心里很不爽!心态阿心态!看下面这个题目:#include unionint i;char x2;a;int main()a.x0=10;a.x1=1;printf(“%d n“, a.i);问题是这个题目最终会打印出什么(小尾端)?C 语言中的 union 是联合体,里面不同类型的元素共享同一块内存,也就是数组 x2和整数i 共享同一个内存,其中 char 类型占 1 个字节,int 类型占 4 个字节。给数组 x 两个元素赋值,也就是给 int 类型的底两个字节赋值。
10、经过简单的思索和运算之后,我开始犯 2 了!我的到了一个答案:26笔试回来后,在电脑上复原代码,结果呢?266! 这是为什么呢?我用 GDB 跟了一遍,没有想通,怀疑是 64 位机器的原因,查看 sizeof(char),没错阿,是 1。把程序拷贝到 32 位的机器上,仍然是 266。然后又怀疑是 union 会自动讲 char 补齐,将结构体中的 x2改成x4,还是 266!就在这时,我瞬间觉悟了!经常性的整 16 进制把我整傻了,居然把 4 个 bit 当作了一个字节!我算出来的 i 用二进制表示是:11010,高 4 位表示 x1,低 4 位表示 x0,而实际上应该是:100001010
11、!高 8 位表示 x1,低 8 位表示 x0居然犯这么傻的错误!哎迷糊的脑袋 # 谁能给提提意见怎么避免这种大脑的短路呢?另外,透露个消息,李开复大哥将在 10 月 16 号亲自来中科院教学楼为创新工场做宣讲,有兴趣的同学以及开复粉丝可以去看看!unsigned 声明的是一个无符号数据类型,也就是说,如果 unsigned int i; 需要注意变量 i 永远不可能等于复数,除非强制类型转换。 第二类:控制语句关键字for /循环语句do /循环语句的循环体while /循环语句的循环条件break /跳出当前循环continue /结束当前循环,开始下一次循环if /条件分支语句else /
12、条件分支语句goto /无条件跳转语句switch /不解释case /不解释default /不解释return /返回语句这些关键字估计都快被用烂了吧?不解释!下面,开始做点有意义的事情,着重解释以下的关键字:第三类:存储类型关键字 autoexternregisterstatic让我们一一来看这四个关键字:1、auto 关键字: 声明变量的生存期为自动,即将不在任何类、结构、枚举、联合和函数中定义的变量视为全局变量,而在函数中定义的变量视为局部变量。不明白?无视他好了,编译器默认的缺省情况下,所有的变量都是 auto 的。2、extern 关键字: 我们都知道,一个变量或函数,可以在 a
13、.c 文件中定义,而在 b.c 文件中使用,这个时候,b.c 就需要使用 extern 关键字来声明这个变量和函数,目的是为了告诉编译器,这个函数在 b.c 之外,别让我编译不过!3、register 关键字: 这个关键字就很少用到了,但是却十分有用。它的目的是告诉编译器尽量把这个变量放到寄存器中,这样提高存取速度,但是不是能真的放到寄存器中却不一定,毕竟寄存器的数量是有限的。在我们的二进制翻译器中,这个关键字被巧妙的用于线程切换。4、static 关键字: 好吧,我承认我土了,我就是栽在这个关键字上的。static 有两种修饰,分别如下:(1)修饰变量:变量分为全局变量和静态变量,都存储在内
14、存的静态区中。首先,当 static 修饰全局变量的时候,该变量的作用域仅被限定在当前文件中,别的文件即使使用 extern 关键字也无法使用这个变量。其次,当 static 修饰局部变量的时候,该变量在哪个函数体中定义,就只能在哪个函数体中使用。也许你会说,这不跟普通局部变量一样么?不一样!别忘了他是被存储在内存的静态区中,所谓的静态区就是全局区,用来存放全局变量和静态变量的,程序不结束,这个区是不会被释放的,所以即使定义静态局部变量的函数结束,改静态局部变量仍然存在,下次访问改函数的时候,这个变量的值仍然是上次的值!举个例子把:void foo()static int i=0;i+;pri
15、ntf(“%dn“,i);int main()foo();foo();这个小例子的执行结果是什么呢?答案是:12对的,静态局部变量只能被初始化一次,并且值会被保留,使用这个有两个好处,一个是可以计算函数被调用的次数,一个是可以减少函数构建局部变量的开销,自己体会一下把。(2)修饰函数: 经常见这种形式,但没怎么用过,也就没去想。其实这个作用跟静态全局变量相似,也是限定函数的作用域为本文件。这样作的好处就是不用操心是否会跟别人编写的文件里的函数重名。 (我这里栽了一下,太弱了不甘心阿!)第四类:其他关键字 constsizeoftypedefvolatile下面,也是一样,一一解释下这些关键字:
16、1、const 关键字: 这是一个很有意思的关键字,他修饰的变量是只读的,不能被修改;很多时候,编译器会将其优化成一个常量。const 经常被用来修饰函数的参数,表示不希望这个参数值被函数体内的代码意外的改变。其实,最有意思的是用 const 修饰一个指针,让我们看下面这个例子:const int *p; /p 可变,p 指向的对象不可变int const *p; /同上int *const p; /p 不可变,p 指向的对象可变const int *const p; /p 和 p 指向的对象都不可变这些各表示什么呢?注释里面给出了答案!是不是很不好记?我们只需要记得,const 修饰的是*p
17、 的时候,p 指向的内容不可变;const 修饰的是 p 的时候,p 就不可变!2、sizeof 关键字:很多人也许会大吃一斤,我类个去,sizeof 居然是关键字?(高手请无视这里,我当初就是这种表现) 。不错,sizeof 确实是关键字,而不是库函数!所以,如果编译时得不到一个数组的大小,那么就不能使用 sizeof 关键字来获取改数组的大小!3、typedef 关键字: typedef 说白了就是给一个已知的类型起一个外号。让我们考虑一个问题:#define PCHAR char*typedef char* pchar;这两个语句都是给 char*类型起一个别名,那么哪个比较好呢? 要想
18、知道答案,看下面:PCHAR p1, p2;pchar p3, p4;看代码的意思,我们是想将 p1,p2,p3,p4 都赋成 char*类型的,但是,事实是如此么?p2 是么?注意,p2 并没有预期成为一个 char*类型,因为 define 会在预编译阶段展开,所以语句 1就相当于 char* p1, p2;而在这条语句下,p2 不是一个指针,而是一个 char 类型的!这个错误经常会被忽略,所以一定要注意!4、volatile 关键字: 也许你见过这个关键字,但一般你都没有用过。哈哈,我用过!这个关键字表示改变量的值可能在外部被改变,编译器在用到这个变量时不能过度的优化,必须每次都重新从内存中读取这个变量的值,而不是将其优化在寄存器中。这个可以用来防止编译器优化产生的内存屏障,详细的看这里。好吧,32 个关键字介绍完了,我自恃很了解,也从中学了不少东西,但愿下次不要再犯这种低级的错误!没关系,一切都会好起来的!Success is going from failure to failure without losing enthusiasm!