1.C语言的存储类型有这四种:auto,register,,extern和static类型,其中,在缺省的情况下,编译器默认的所有变量都是auto的。而regeister寄存器则是最快的,但是由于其数量很少,所以弥足珍贵。extern是申明外部变量和函数的。static比较复杂,也比较重要,会专门讲解。这里为了测试register和auto的效率,我们做了一下实验。

#include <stdio.h>

int main()

{

   register int i = 0,j = 0;

   //int i = 0,j = 0;

       for(i = 0;i < 10000;i++)

   {

       for(j = 0;j < 100000;j++)

       {

           ;

       }

   }

return 0;

}

在运行的时候,我们用time a.out命令简单测试一下程序的执行时间,当使用int i = 0,j = 0;语句的时候,打印有:

第二天_return

程序大约执行了2.2秒,而使用register int i=0,j=0的时候,打印有:

第二天_register_02

执行的时间约为0.6秒,比上面快了近4倍,所以register的速度比较快,因为变量存在寄存器中。

2.对于关键字,大家要记住,sizeof是一个关键字,不是函数。

第二天_return_03

3.在C99标准中,拓展了C语言的类型,增加了bool类型。我们在C89标准中如果要使用bool类型,则需要使用<stdbool.h>头文件,见下面实例:

#include <stdio.h>

#include <stdbool.h>

int main()

{

   bool a = 0.001;

   printf("true = %d\n",true);

printf("false = %d\n",false);

printf("a = %d\n",a);

return 0;

}

打印的结果是:

第二天_register_04

bool a = 0.001,非零为真,所以true = 1,false = 0,此时的a = 1表示a为真。与a原来的值无关,大家可以把a的值改为7.8试试!

4.关于static大家要注意这几点:

a.static修饰变量。在修饰全局变量的时候,作用于限定于被定义的文件中,使用extern也不能访问;在修饰局部变量的时候,在函数体中定义,只能用于该函数,即使使用该函数结束,静态变量也不会被销毁,下次可以继续使用,即缩小了访问范围但是延长了访问时间。

b.修饰函数的时候,函数的作用于仅限于本文件,故也叫内部函数,和修饰全局变量类似。这就是为什么linux内核中所有的函数和全局变量都声明为static的原因,linux内核代码很多,有几万个文件,为了防止文件中的函数重名造成冲突,所以就干脆声明为静态的。

c.Static修饰的静态变量,一次定义多次使用,值具有继承性(可以被修改),静态区BSS段中,初始值为0,修饰全局变量也一样,未初始化时,初始值为0;为在栈区,即局部变量中,未初始化的变量,初始值全部都是随机的脏数据。

见下面的实例:

#include <stdio.h>

//int a;

void test()

{

  // static int a = 30;

  static int a;

   printf("a = %d\n",a);

   printf("%s : &a = %p\n",__FUNCTION__,&a);

   a = a + 1;

}

void test1()

{

   int b;

   printf("b = %d\n",b);

   printf("%s : &b = %p\n",__FUNCTION__,&b);

   b = b + 1;

}

int main()

{

   int i = 0;

   for(i = 0;i < 4;i++)

   {

       test();

   }

   getchar();

   for(i = 0;i < 4;i++)

   {

       test1();

   }

   return 0;      

}

打印结果为:

第二天_register_05

可以看到a虽然没有初始化,但是被赋值为0了,因为声明成了static,回车后,打印:

第二天_return_06

在函数test1()中,我们没有把b声明为static,则b的初始值为一个随机值。

当我们把a的初始值设为static int a = 30时,则打印:

第二天_register_07

说明对于staic int a = 30这条语句执行了四次,但是赋值却只是执行了一次,就是上面所说的“一次赋值,多次使用”。

5.在linux系统编程,我们经常要使用sizeof和strlen,但是大家对它们的认识有多少呢?看看下面的例子,你知道打印出什么吗?

# include <head.h>

int main(int argc, const char *argv[])

{

char *p = "abcdef";

char q[9] = "1234567";

strcpy(p,"ABCDEF");

strcpy(q,"9876543");

puts(p);

printf("sizeof(p)=%d, strlen(p)=%d\n",sizeof(p),strlen(p));

printf("sizeof(q)=%d, strlen(q)=%d\n",sizeof(q),strlen(q));

return 0;

}

我们会发现,在编译和链接的时候,没有什么错误,但是在执行的时候,出现了段错误;在VC++下运行的时候出现非法访问的错误报告,段错误和非法访问一般是因为我们访问了一段不属于我们的内存空间。为什么会出现这种情况呢?

大家看看这两条语句:char *p =“abcdef”;char q[9] =“1234567”;对于char q[9] =“1234567”;我们知道这是一个数组的普通的初始化,所以对数组再次赋值,不会出错;但是对于char *p =“abcdef”;实际上,字符常量存在只读数据段.rodata区,因为是只读区,所以再次赋值修改肯定会报错。当我们把strcpy(p,”ABCDEF”);注释掉就行了,结果打印:

第二天_register_08

因为是只读的,所以我们可以使用puts();打印结果,p是一个指针变量,所以只占4个字节;strlen()求的是数组中实际存放的字符数,不包含后面的’\0’,sizeof()则求的是整个申请数组的长度(包括未用的和’\0’),所以,有了上面的结果。