数据

程序是对数据进行操作的。

基本数据类型

在C语言中,仅有4中基本数据类型:

  • 整型
  • 浮点型
  • 指针
  • 聚合类型

整型

整型家族包括字符、短整型、整型、长整型。

而整型家族中的每一种类型分为有符号的和无符号的。

具体如下图所示:

这里写图片描述

注意,尽管设计char类型变量的目的是为了让他们容纳字符型值,但字符在本质上是整型值(例如,ASCII码)。

只有当char型变量显示声明为singed或unsinged时,才对它指向算术运算。

整型字面值常量

字面值常量是一种实体,其指定了自身的值,并且不允许发生改变。

对于整数字面值常量而言,当一个程序内出现整数字面值常量时,它是属于整数6种不同类型的哪一种呢?

答案取决于整数字面值是如何书写的。

  1. 其中最自然的方式是十进制整型值。
  2. 整数也可用八进制来表示,只要在数值前面以0开头。
  3. 整数也可以用十六进制来表示,它以0x开头。

但是,我们可以在有些整数字面值后面添加一个后缀来改变默认的规则。

  • 在整数字面值后面添加L或l,可以使这个整数被解释为long整型值。
  • 在整数字面值后面添加U或u,可以使这个整数被解释为unsigned整型值。
  • 如果在一个整数字面值后面添加这两组字符中的各一个,那么它就被解释为unsigned long整型值。

对于字符字面值常量而言,它就是一个用单引号包围起来的单个字符。

字符字面值常量类型总是int,所以我们不能在它后面添加unsigned或long后缀。

但是,我们可以在字符字面值常量前面加L,表示其实宽字符常量。

浮点类型

浮点数通常以一个小数以及一个以某个假定数为基数的指数组成。

浮点数家族包括单精度float类型、双精度double、扩展精度long double类型。

浮点数字面值常量总是写成十进制形式,它必须有一个小数点或一个指数,也可以两者都用。

浮点数字面值常量在默认情况下都会double类型的。除非我们在其后面添加L或l表示它是一个long double类型的值。或在其后面添加一个F或f表示它是一个float类型的值。

基本声明

变量声明的基本形式是:

说明符(一个或多个) 声明表达式列表

  • 说明符包含了一些关键字:
    • 用于描述被声明的标识符的基本类型。
    • 用于修改变量的长度或是否为有符号数的关键字。
    • 用于改变标识符的默认存储类型和作用域。
  • 对于简单的类型来说,声明表达式列表就是被声明的标识符的列表。
int i;
char j , k , l;

注意:

  1. 在声明整型变量时,如果声明中已经至少有了一个其他的说明符,关键字int可以省略。
  2. 除char类型之外,其他整型类型在默认情况下都是有符号数。

初始化

在声明中,我们可以给一个标量变量指定一个初始值。

int i = 15;

声明简单数组

声明一个一维数组,在数组名后面要跟一对方括号,方括号里面是一个整数,指定数组中元素的个数。

int values[20];/*声明一个整型数组,数组包含20个整型元素*/

注意:数组的下标总是从0开始,最后一个元素的下标是元素的数目减1。

声明指针

int *a;

声明指针变量的同时,我们可以给其指定初始值。

char *message = "Hello,World!";

等价于

char *message;
message = "Hello,World!";

关键字typedef

typedef允许我们为各种数据类型定义新名字。

typedef char* ptr_to_char;
ptr_to_char a;/*a是一个指向字符的指针*/

关键字const

const声明的常量和变量完全一样,只是它们的值不能修改。

const int a;

由于我们无法给修改常量,我们也就无法给a赋值,所以我们必须在声明a的同时给其赋予初始值。

const int a = 15;

注意:在函数声明为const的形参在函数被调用时会得到实参的值。

对于指针而言,常量const这一概念就会更复杂了!

指针和常量混在一起有两种情况:

  • 指针是常量。

    • int *const p ;
    • 指针的值无法修改,但是指针指向的值可以修改。

  • 指针指向的数据是常量。

    • const int *p;
    • 指针指向的值无法修改,但是可以修改指针的值。

变量

变量拥有三个属性,这三个属性决定了一个变量的“可视性”(在什么地方使用)和“生命期”(值将保存多久)。

  1. 作用域
  2. 链接属性
  3. 存储类型

作用域

当变量在程序的某个部分被声明时,它只有在程序的一定区域才能被访问,这个区域由标识符的作用域决定。

标识符的作用域就是程序中该标识符可以被使用的区域。

标识符声明的位置决定它的作用域。

编译器可以确认4种不同类型的作用域:

  • 文件作用域
    • 任何在所有代码之外声明的标识符都具有文件作用域,它表示这些标识符从它们的声明指出知道它所在的源文件结尾处都是可以访问的。
    • 在文件中定义的函数名也具有文件作用域,因为函数名本身并不属于任何代码块。
  • 函数作用域
  • 代码块作用域
    • 位于一对花括号之间的所有语句称为一个代码块。
    • 任何在代码块的开始位置声明的标识符都具有代码块作用域,表示它们可以被这个代码块中的所有语句访问。
    • 函数定义的形式参数在函数体内部也具有代码块作用域。
  • 原型作用域
    • 原型作用域只适用于在函数原型中声明的参数名。
    • 原型作用域防止这些参数与程序其他部分的名字冲突。
    • 在函数原型中,参数的名字不是必需的。但是如果我们想给予参数名,我们可以给它们取任何名字,同时不必与函数定义中的形参名匹配,也不必与函数实际调用时所传递的实参匹配。

这里写图片描述

链接属性

当组成一个程序的各个源文件分别被编译之后,所有的目标文件以及那些从一个或多个函数库中引用的函数链接在一起,形成可执行程序。

但是,相同的标识符出现在几个不同的源文件中,那么它们是表示同一个实体,还是不同的实体呢?

这取决于这些标识符的链接属性。

标识符的链接属性决定如何处理在不同文件中出现的标识符,一共有三种:

  • none(无)
    • 没有链接属性的标识符总是被当做单独的个体,也就是说该标识符的多个声明被当做独立不同的实体。
  • external(外部)
    • external链接属性的标识符不论声明多少次、位于几个源文件中,都表示一个实体。
  • internal(内部)
    • internal链接属性的标识符在同一源文件内的所有声明中都指向同一个实体,但是位于不同源文件的多个声明则分属于不同的实体。

关键字static

如果某个声明在正常情况下具有external链接属性,在它前面加上static关键字可以使它的链接属性变为internal。

static int b;/* 变量b为源文件私有*/
static int c(int d); /*函数c为源文件私有,防止其他源文件对其调用*/

关键字extern

关键字extern为一个标识符指定external链接属性,这样就可以访问在其他任何位置定义的这个实体了。

注意:当extern关键字用于源文件中一个标识符的第一次声明时,它指定该标识符具有external链接属性。

但是,如果它用于该标识符的第二次或以后的声明时,它并不会更改由第一次声明所指定的链接属性。

static int i;
int func()
{
    int j;
    extern int k;
    extern int i;
}

存储类型

变量的存储类型是指存储变量值的内存类型。

变量的存储类型决定了变量何时创建、何时销毁以及它的值将保存多久。

变量的默认存储类型取决于它的声明位置。

有三个地方可以用于存储变量:

  • 普通内存
    • 凡是在任何代码块之外声明的变量总是存储于静态内存中,就是不属于堆栈的内存,这类变量称为静态变量。
    • 静态变量在程序运行之前创建,在程序的整个执行期间始终存在。它始终保持原先的值,除非给它赋一个不同的值或程序结束。
  • 运行时堆栈
    • 在代码块内部声明的变量的默认储存类型是自动的,也就是说它存储于堆栈中,称为自动变量。
    • 在程序执行到声明自动变量的代码块时,自动变量才被创建,当程序的执行流离开该代码时,这些自动变量便自行销毁。
  • 硬件寄存器
    • 关键字register可以用于自动变量的声明,提示它们应该存储于机器的硬件寄存器而不是内存中,这类变量称为寄存器变量。

关键字static

对于在代码块内部声明的变量,如果给它们加上关键字static,可以使它们的存储类型从自动变为静态。

具有静态存储类型的变量在整个程序执行过程中一直存在,而不仅仅在声明它的代码块的执行时存在。

但是,修改变量的存储类型并不表示修改了变量的作用域,它仍然只能在该代码块内部按名字访问。

静态变量和自动变量的初始化

在静态变量的初始化中,我们可以把可执行程序文件想要初始化的值放在当程序执行时变量将会使用的位置。当可执行文件载入内存时,这个已经保存了正确初始值的位置将被赋值给那个变量。

完成这一任务不需要额外的时间,也不需要额外的指令,变量将会得到正确的值。

如果不显示地指定其初始值,静态变量将初始化为0。

对自动变量而言,当程序连接时无法判断自动变量的存储位置,所以自动变量没有默认初始值。

并且,显示的初始化将在代码块的起始处插入一条隐式的赋值语句。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章