C语言之路 第六章 再论数据类型

第六章 再论数据类型

成事者不可狭于器

在第一章中我们看到,主要的数据类型有三种----字符型、整型和浮点型。很多人可能会觉得比较奇怪,C语言程序员是如何用这么少的数据类型去处理事物的。事实上,C语言程序员并不感到匮乏。这三种数据类型可以派生出很多数据类型。理论上,从C语言中派生出来的数据类型是没有限制的。一个C语言程序员总是可以创造他所需要的数据类型,如结构。不仅如此,主要的数据类型本身也可以是多种类型的。例如,一个字符型数据可以是无符号的或有符号的,一个整形数据可以是短整型或长整型的。很困惑吧?那么这一章将详细介绍主要数据类型的一些变化。一个完整的变量定义,不仅需要考虑它的类型,还要考虑它的存储类型。本章将探讨不同变量的存储类型及它们与C语言程序的关联。

6.1 C语言允许将short int 缩写为 short,将long int 缩写为long,将unsigned int缩写为unsigned 。因此

short int i=short i;

long int j=long j;

unsigned int k=unsigned k;

6.2 数据的存储类型

①自动存储类型

②寄存器存储类型

③静态存储类型

④外部存储类型

为了完整定义一个变量,不仅要知道它的数据类型,还要知道它的存储类型。尽管已经用C语言写了好几个程序,但还没有提及存储类型。我们能够侥幸成功是因为存储类型可以缺省。如果在变量定义时,不特别声明它的存储类型,编译器会依据变量程序上下文的关系为其分配一个存储类型。因此,变量具有某种默认的存储类型。

①自动存储类型(★★★★★透彻理解)

定义成自动存储类型的变量具有如下特征:

●存储位置--内存

●默认初始值--不可预料的值,通常称其为无意义的值

●作用域--限定在变量定义的局部快

●生存周期--从变量定义的地方到控制还处在变量定义的块内

举例如下:

#include <stdio.h>

int main(void)

{

      auto int i=1;

      {

           {

               {

                   printf("\n%d",i);

               }

               printf("%d",i);

           }

           printf("%d",i);

      }

      system("pause");

}

运行结果:111

#include <stdio.h>

int main(void)

{

      auto int i=1;

      {

           auto int i=2;

           {

               auto int i=3;

               printf("\n%d",i);

           }

           printf("%d",i);

      }

      printf("%d",i);

      system("pause");

}

思考:关键字auto到底有什么用途?

毫无疑问,它已经过时了。(它是从C语言的无类型前身B语言中继承下来的。在B语言中,没有像int这样的关键字,声明必须包含存储类型)

②寄存器存储类型

定义成寄存器存储类型的变量具有如下特征:

●存储位置--CPU寄存器

●默认初始值--无意义的值

●作用域--变量定义的局部块内

●生存周期--从变量定义的地方到控制还处在变量定义的块内

与存储在内存中的值相比,访问存储在CPU寄存器中的值速度更快。因此,如果一个变量在程序中被多次使用,最好将其声明为寄存器存储类型的。循环计数器就是。

#include <stdio.h>

int main(void)

{

      register int i;

      for(i=1;i<=10;i++)

      printf("\n%d",i);

      system("pause");

}

③静态存储类型

定义成静态存储类型的变量具有如下特征:

●存储位置--内存

●默认初始值--0

●作用域--限定在变量定义的局部块

●生存周期--在不同的函数调用之间,变量的值保持不变。

奉劝一句话--尽量避免使用静态型变量,除非是真的需要。因为当变量不活跃时,它们的值仍然保存在内存中,这意味着它们所占据的内存空间有可能被其他变量使用。

思考:同一个静态(static)函数或变量的所有声明都必须包含static存储类型吗?

语言标准并没有严格规定这一点(最重要的是第一个声明必须包含static),最安全的做法是让static一致地出现在所有的定义和声明中。

④外部存储类型

定义成外部存储类型的变量具有如下特征:

a,存储位置--内存

b,默认初始值--0

c,作用域--全局的

d,生存周期--程序执行结束之前

/*仔细观察这个程序的输出结果*/ 

#include <stdio.h>

int x=10;

void display();

int main(void)

{

      int x=20;

      printf("\n%d",x);

      display();

      system("pause");

}

void display()

{

     printf("\n%d",x);

}

6.3 潜在的问题

●定义在函数内部的变量,每次调用该函数时,都是在栈上创建的。当控制离开这个函数时,这些变量就不存在了。然而,如果在函数内将变量定义成静态型(static)的,则这些变量就不是在栈上创建的,而是创建在内存中的“数据段”。这样,只有在程序执行结束时该变量才会消失。

●如果变量定义在所有函数外,那么该变量不仅可以对定义它的文件内的所有函数可用,而且对其他文件中定义的函数也可用。只是在其他的文件中使用该变量时,要将其声明为extern。

6.4 下面的语句中,前三个是变量定义,但最后一个是变量声明。

auto int i;

register int j;

auto int k;

extern int l;

思考:extern在函数声明中是什么意思?

存储类型extern只对数据声明有意义。对于函数声明,它可以作为一种格式上的提示, 表明函数的定义可能在另一个源文件中。所以:

extern int f();和int f()之间没有实质的区别。

拓展阅读

C语言关键字 - 乱世枭雄:static与extern

描述:在C程序世界里,不同代码国度以.c文件为国界分隔开来,在单个国家(C源文件)里有不同的函数占山为 王,军阀割据,每个C程序世界里只有一个君主main和其首都(main函数体),main通过下传圣旨(参数),调用各种军阀(函数),来掌控整个C程序世界的有序运行。在和谐世界的幌子下,却是别番风景,某军阀(函数)心怀叵测,不想单纯听从于main的指挥与调度,树立了自己的政权旗帜 static。static不用听附与main的调度,自己做主,私藏金库(空间)。而main对此却很无奈,因为相对static来说,extern更是让它皇权难保。不同的国家(不同的.c文件)之间通过extern相互私通,传递信息。二者联合作乱,让编程者逻辑混淆。当然,如果编程者连一个国家都没有走出去过(指将所有代码写到一个.c文件里),不能够上升到一个宏观的角度,将不知所云。乱世出枭雄,切听我慢慢道来其中一二。

作用:简单来说static修辞变量,就是指该变量空间独立于函数中的auto变量或叫栈变量(请查看auto关键字章节),static变量空间在内存中的静态区内被分配。如图xxx所示。

图xxx 程序内存分布示意图

在使用static的时候一定要注意以下几点:

●static变量在程序运行(main启动)之前就已经被分配,它不像是局部变量那样动态在栈上分配的,它在程序彻底退出之后才被释放。

●static变量有访问权限,在子函数里声明的static变量,只能在该函数内访问,如果static变量在函数体外声明,它的访问权限就是本文件内。

●static不仅可以修辞变量,还可以用来修辞函数,如果用来修辞函数,和第2条有着相似的意义,表示该函数访问权限限制在本源文件内。

记住以上三点,可以解释很多初学者不明白的问题:

●为什么子函数里声明的static变量,每次访问其值都是上一次的结果?答案见要点1。

●为什么子函数里的static变量不能在子函数外面访问?答案见要点2。

●如何避免不同文件里命名冲突的问题?答案见要点3。

带着上面的理解,再回头理解描述里的小故事:乱世枭雄。

  extern是指,当前变量或函数不是在本源文件内声明的,它是外部变量或外部函数,正所谓“外来的和尚会念经”,能很好的体现extern的价值。当我们在本文件里试图引用一个外部声明的全局变量或函数时,可以在其前面加上extern,表示它是外来和尚。

  宏观理解:通过上面的分析看来,C程序里,通过函数将功能区分开来,每个函数完成一个功能(这也是为什么函数的英文叫function),而又将一片相关联的功能集合在一个源文件里,这些功能和相关联的功能之间通常要有联系,而这种联系(亦可叫通信)就是通过static和extern进行联系起来的,当然这里面还要有头文件的功劳,关于头文件的解释,后面会单独拿来分析。

 

常见错误理解:

菜鸟:static表示常量。

你要这么说const关键字哭了。static不表示常量,理解它就从上述3点来理解。

菜鸟:static表示其值会被记录住。

这么说只是片面理解。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值