我是一名软件工程专业即将大四的学生,周围的同学都在准备考研,不知道为什么考研对我没有太大的吸引力。当然我不是反对考研,上研究生确实很好,它可以让我们深入某一个流域、对知识有一个系统的理解等。但对于一个喜欢技术的我而言,我更倾向于在实际开发经验中去获得新知识,可能这也就是我选择工作的主要原因吧。所以最近一直都在准备即将到来的2014年的校园招聘,听毕业参加工作的一些学长那里得知笔试、面试大多都还是考一些最基础的东西,比如C语言/数据结构/网络等。因此最近也都在看一些基础的东西和往年一些公司的面试题,看了好几天,感觉考得是挺基础的,但也有一定的深度。有很多看似很基础的东西就是弄不明白,可能这也与我们的教育体制有关吧(至少本人很鄙视)。感觉现在很多计科出身的同学大学毕业了,连C语言的门都还没有找到,更别说入门了,有的都还以为C语言早过时了,而且太简单了,学也没有什么用。所以大多同学都热衷直接学什JAVA/C#/C++等高级语言,甚至有些学校把这些高级语言都开了一遍。个人认为如果把C语言这种简单的整明白了,我想其它语言学习也不再话下。好了,不多说了(这是本人第一次写博客,啰嗦了点~),下面是最近对C语言的深入学习吧,现在让我们一块进入主题吧。
可能我现在问大家:C语言中有多少关键字?sizeof怎么用?sizeof是个关键字吗? 我相信现在很多同学都答不出来(当然在我没有复习以前,一些关键字我自己都也不认识)。
C语言标准定义了32个关键字:
关键字 意义
auto 声明自动变量,缺省时编译器一般默认为auto
int 声明整型变量
double 声明双精度变量
long 声明长整型变量
char 声明字符型变量
float 声明浮点型变量
short 声明短整型变量
signed 声明有符号类型变量
unsigned 声明无符号类型变量
struct 声明结构体变量
union 声明联合数据类型
enum 声明枚举类型
static 声明静态变量
switch 用于开关语句
case 开关语句分支
default 开关语句中的“其他”分支
break 跳出当前循环
register 声明寄存器变量
const 声明只读变量
volatile 说明变量在程序执行中可被隐含地改变
typedef 用以给数据类型取别名(当然还有其他作用)
extern 声明变量是在其他文件正声明(也可以看做是引用变量)
return 子程序返回语句(可以带参数,也可不带参数)
void 声明函数无返回值或无参数,声明空类型指针
continue 结束当前循环,开始下一轮循环
do 循环语句的循环体
while 循环语句的循环条件
if 条件语句
else 条件语句否定分支(与if 连用)
for 一种循环语句(可意会不可言传)
goto 无条件跳转语句
sizeof 计算对象所占内存空间大小
在一一讲解这些关键字前,先弄清楚两个概念:
什么是声明?什么是定义?他们怎么区别?
举个例子:
A> int i;
B> extern int i;
哪个是定义?哪个是声明?或者都是定义或者都是声明?
什么是定义:所谓的定义就是(编译器)创建一个对象,为这个对象分配一块内存并给它取上一个名字,这个名字就是我们经常所说的变量名或对象名。但注意,这个名字一旦和这块内存匹配起来(可以想象是这个名字嫁给了这块空间,没有要彩礼啊。^_^),它们就同生共死,终生不离不弃。并且这块内存的位置也不能被改变。一个变量或对象在一定的区域内(比如函数内,全局等)只能被定义一次,如果定义多次,编译器会提示你重复定义同一个变量或对象。
什么是声明:有两重含义,如下:
第一重含义:告诉编译器,这个名字已经匹配到一块内存上了(伊人已嫁,吾将何去何从?何以解忧,唯有稀粥),下面的代码用到变量或对象是在别的地方定义的。声明可以出现多次。
第二重含义:告诉编译器,我这个名字我先预定了,别的地方再也不能用它来作为变量名或对象名。比如你在图书馆自习室的某个座位上放了一本书,表明这个座位已经有人预订,别人再也不允许使用这个座位。其实这个时候你本人并没有坐在这个座位上。这种声明最典型的例子就是函数参数的声明,例如:
void fun(int i, char c);
好,这样一解释,我们可以很清楚的判断:A)是定义;B)是声明。那他们的区别也很清晰了。
记住,定义、声明最重要的区别:定义创建了对象并为这个分配内存,声明没有分配内存。(一个是抱伊人,一个抱自己,哈哈~)。
1.最宽恒大量的关键字---auto
auto: 编译器在默认情况下,所有变量都是auto的。所以说它很宽恒大量,你就当他不存在吧。
2. 最快的关键字---register
register:这个关键字请求编译器尽可能的将变量存在cpu内部寄存器中而不是通过内存寻址访问以提高效率。注意是尽可能,不是绝对。你想想,一个cpu的寄存器也就那么几个或几十个,你要是定义了很多很多register变量,它累死也不可能把这些变量放到寄存器吧,轮也轮不到你。
皇帝身边的小太监---寄存器:大家都知道皇帝阅读奏章的时候,大臣总是先把奏章交给皇帝身边的小太监,小太监呢再交给皇帝同志。其实这个小太监只是个中转站,别无其他功能。 好了,现在让我们联想一下我们的cpu,cpu不就相当于皇帝吗,大臣就相当于我们的内存,数据从他们这拿出来。那小太监就是我们的寄存器了(这里不考虑cpu的高速缓存区)。数据从内存中拿出来先放到寄存器中,然后cpu再从寄存器中读取数据来处理,处理之后同样通过寄存器放回内存里,cpu不直接和内存打交道。但是我们要注意一点:小太监是主动从大臣手里接过奏章然后有主动交给皇帝,但我们的寄存器没有这么自觉,它从不主动干什么事。 可能大家会问为啥这么麻烦?,速度,就是因为速度。
register使用的注意事项:虽然寄存器的速度非常快,但使用register也有些限制:register变量必须是被cpu寄存器所接受的类型。意味着register必须是一个单个的值,并且其长度应该小于等于整型的长度。而且register变量有可能不存放在内存中,所以不能用取址运算符“&”来获取register变量的地址。
3. 最名不符实的关键字---static
不要以为关键字static很安静,其实它一点都不安静。这个关键字在C语言里主要有两个作用,C++对它进行了扩展。
第一个作用:修饰变量。变量又分为局部和全局变量,但它们都存在内存的静态区。
静态全局变量:作用域仅限于变量定义的文件中,其他文件即使使用extern声明也没有办法使用它。准确地说作用域是从定义之处开始,到文件结尾处结束,在定义之处前面的那些代码行也不能使用它,要想使用就得在前面加上extern***。恶心吧?
静态局部变量:在函数体内部定义,就只能在这个函数里面使用,同一个文档中的其他函数也不能用。由于被static修饰的变量总是存在内存的静态区,所以即使这个函数运行结束,这个静态变量的值还是不会被销毁。函数下次使用时仍然能用到这个值。
static int j ;
void fun1(){
static int i = 0;
i++;
}
void fun2(){
j = 0;
j++;
}
int main(){
for(int k = 0; k<10; k++){
fun1();
fun2();
}
return 0;
}
i和j 的值分别是多少?为什么?
第二个作用:修饰函数。函数前加上static使得函数成为静态函数。但此处“static”的含义不再指存储方式,而是指对函数的作用域仅局限于本文件(所以又称局部函数)。使用内部函数的好处是:不同人编写不同的函数式,不用担心自己定义的函数是否会与其他文件中的函数同名。