一.声明与定义

1.声明

1).变量的声明会将变量的类型和名称传达给程序。

2).可以通过使用“extern”关键字来声明一个变量,而不用定义它。声明的形式就是在变量的名字和类型前面,加上关键字”extern”,表明该变量来源于外部文件。

221539271.png

3).声明可以多次。

2.定义

1).变量的定义会为这变量分配存储空间,并且可能指定初始化值。

2).一个变量的定义有且只有一处。定义实际上是一种特殊的声明。

3.区别

1).为了使不同的文件都可以访问同一变量,C会区分变量的定义与声明。

2).变量的定义为这个变量分配存储空间,可能赋初值;变量的声明会将变量的类型和名称传达给程序。

221558629.png

二.常量

1.概念

1).常量是可以在程序使用之前预先设定,并且在整个程序运行过程中没有变化的那些数据。

2.特点

1).不能对常量取地址

221611628.png

3.常量的类型

1).整型常量

221628816.png

2).浮点型常量

221646152.png

3).符号常量(即宏替换)

#define PI 3.1415

a.使用的优势:

使用符号常量通常比一个数字更容易读懂。

假设在多个地方使用同一个变量,那么修改起来也会很方便。

b.特点

a).C中,符号常量一般用大写表示。大写常量使程序更容易阅读。符号常量也一定要符合命名规则。

b).在预处理时,进行常量的替换。

4).字符型常量

221657156.png

221708894.png

221727153.png

a.使用转义字符时需要注意以下问题:

a).转义字符中只能使用小写字母,每个转义字符只能看作一个字符。

b).\v垂直制表和\f换页符对屏幕没有任何影响,但会影响打印机执行响应操作。

c).C程序中,使用不可打印字符时,通常用转义字符表示。

d).转义字符’\0’表示空字符NULL,它的值是0。而字符'0'ASCII码值是48。因此,空字符’\0不是字符0。另外,空字符不等于空格字符,空格字符的ASCII码值为32而不是0。编程序时,读者应当区别清楚。

e).如果反斜线之后的字符和它不构成转义字符,则’\’不起转义作用将被忽略。

例如:

printf(“a\Nbc\nDEF\n”);

输出:

aNbc

DEF

f).转义字符也可以出现在字符串中,但只作为一个字符看待。

例如:求下面字符串的长度

\026[12,m长度为6

\0mn长度为0。(想想:为什么不是2

b.字符测试代码

 221749732.png

c.C语言中printf("%d\n",strlen("\t\"\065\xff\n"));的输出为5:

221853619.png

d.char c[]="\t\v\\\0will\n",求strlenc)的输出

221910865.png

5).字符串型常量

a.特点

a).“hello world”赋值(非初始化)时,返回的是地址。指针可以接收该字符串常量返回的地址。

b.测试代码

221931533.png

221945285.png

6).系统定义常量

222001922.png

4.常量存储特点

1).用常量赋值给变量,先维持常量存在于代码段中,然后将该常量拷贝到相应的存储区,赋值给变量。如果是局部变量,拷贝到栈中;如果是静态变量,拷贝到数据段中。

2).常量作为只读数据,放在代码段中。

三.变量

1.概念

1).变量是指在程序运行过程中可能变化或被赋值的一些数据。

2.特点

1).变量赋值本质:左值和右值。

2).变量的值可以在程序执行的过程中变化或指定,而常量不可以。常量所在的地址不能被赋值。

3.局部变量

1).定义一个局部变量而没初始化,那么该变量的值为随机值。

4.全局变量

1).特点

a.存放在内存的静态存储区域,在整个工程文件内都有效。

b.全局变量就是在函数体外说明的变量,它们在程序中的每个函数里都是可见的。

c.属于静态存储方式的变量不一定就是静态变量,必须由 static加以定义后才能成为静态变量。

2).存储方式。

a.全局变量本身就是静态存储方式。但它是一种非静态的全局变量。

b.定义时,如果没有手工初始化,则由编译器初始化为0

5.静态变量

1).特点

a.static修饰的变量,称为静态变量

b.静态变量可以在任何可以申请的地方申请,一旦申请成功后,它将不再接受其他的同样申请。即,静态变量只能被初始化一次,在下一次调用的时候还可以保持原来的最新赋值。

c.变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。

d.静态变量的初始化表达式必须是一个常量或者常量表达式。

2).存储方式

a.静态存储方式。所以,静态变量如果没有手工初始化,则由编译器初始化为0

3).static的三种用途

a.修饰局部变量,使之由原来的自动存储期变成静态存储期。

b.修饰全局变量,使之由原来的外部链接类型变成内部链接类型。

c.修饰函数,使之由原来的外部链接类型变成内部链接类型。

4).静态局部变量

a.与局部自动变量的区别

相同点:只能在定义该变量的函数内使用该变量。

不同点auto自动变量会随着函数被调用和退出而存在和消失,而static类局部变量不会,它不管其所在的函数是否被调用,都将一直存在;再次调用定义它的函数时,将使用前次被调用后留下的值。

222015104.png

b.特点

a).局部静态变量占用内存时间较长,并且可读性差,因此,除非必要,尽量避免使用局部静态变量。

b).把局部变量改变为静态变量后是改变了它的存储方式,即改变了它的生存期。

c.使用情况:

a).当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。

b).仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度

c).当多次调用一个函数且要求在调用之间保留某些变量的值时,可考虑采用静态局部变量。虽然用全局变量也可以达到上述目的,但全局变量有时会造成意外的副作用,因此仍以采用局部静态变量为宜。

5).静态全局变量

a.特点

a).由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。

b).把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。

b.与全局变量的区别

a).相同点:都是静态存储方式。

b).不同点:全局变量的作用域为整个工程文件,静态全局变量只在定义该变量的源文件内有效。

c.使用情况:

a).若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度

6).静态函数

a.函数前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)

b.使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。

7).可重入问题

a.设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题。所谓"可重入"(也可以说是可预测的),即:只要输入数据相同就应产生相同的输出。

b.如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量,这种函数中的static变量,使用原则是,能不用尽量不用。

6.const修饰的变量

1).说明

a.Const修饰符修饰的变量是只读变量,不是常量。

b.一个符号前面加上限定符const只是表示不能被赋值,换句话说,它的值对这个符号来说是只读的。

2).程序在编译时,发现这种类型的变量值被修改,就会报错。但可以在程序运行时来修改这种变量的值:

222036772.png

四.int

1.类型定义

1).C把不含小数点和指数的数当做整数。

2).C把大多数整数常量看做int类型。

3).C中用0开头表示八进制数,用0x开头表示十六进制数。

4).注意:使用不同的数值系统的选择是为了方便而提供的,它们并不影响数字在计算机内部的真实存储。

2.三种关键字修饰

1).short int (简:short

a.用于仅需小数值的场合以节省空间。

2).long int(简:long

a.用于大数值场合。

b.C语言定义的long类型总对等于机器的字长,而int类型有时会比字长小。

c.有时候需要用long型替代int型,因为:

针对不同的机器,为了适应不同的硬件平台,可能long型与int型所占的字节数不同。为了移植的需要。

3).unsigned int(简:unsigned

a.只用于非负值场合。

b.它们都是有符号类型,与加上关键字signed等价。

五.字符类型char

1.字符类型的实质

1).字符类型用于表示字母和标点符号之类的数据。

2).从技术上来说,实际上char型是整型,char型存储的是整型而不是字符。

3).为了处理字符,计算机使用一种数字编码,用于特定的整型表示特定的字符。目前最常用的编码是美国的ASCII码。

2.ASCII

1).标准ASCII码值从0127,只需7位即可表示。而char类型通常定义为使用8位存储单元(一个字节)。

3.定义

1).char ch=’A’; //编译器会把字符常量A对于的ASCII65赋给变量ch

六.浮点型

1.概念

1).表示整数之间的那些数,加小数点的就是浮点型数据。

2.三种类型

1).float

2).double

3).long double

3.存储方案

1).浮点型的存储方案与整型的存储方案不同,浮点数表示法将一个数分为小数部分和整数部分分开存储,虽然占的字节空间与整型数据一样。

222104486.png

七.布尔类型

1._Bool

1)._Bool类型有C99引入,用于表示布尔值,即逻辑值truefalse

2).因为C用非零表示true,用值0表示false,所有_Bool类型实质上也是一种数据类型,只是原则上它仅仅需要1位来进行存储。

2.bool

要使用bool类型和关键字truefalse,必须包含头文件stdbool.h

八.void

1.说明

1).关键字void用来修饰指针变量、函数返回类型和函数参数列表。

2.void  void *型(返回一个地址,地址不确定,可以强制转换成其他类型)

九.字符串

1.概念

1).字符串就是一个或多个字符的序列。

2.特点

1).双引号不是字符的一部分,它们通知编译器其中包含了一个字符串。

2).C没有专门的字符串类型,而是把它存储在char型数组当中。字符串的每个字符存放在相邻的存储单元中。

3).C字符串最后用空字符“\0(也占一个存储字节空间)标识字符串的结束。

4).字符串常量是字符常量的派生类型。

3.字符串的存储

1).数组存储字符串

char a[]={“hello”};等同于 char a[]=”hello”;

a.占用六个字。

b.数组在初始化时,可以用字符串进行初始化。但后面的赋值不能整体进行字符串赋值。

2).指针指向字符串

a.在指针中存放指向字符串首地址的地址,字符串通过“\0”标识结束。

b.malloc申请空间存放字符串

222122394.png

4.计算字符串的长度:

1).strlen()

a.strlen()函数以字符为单位给出字符串的长度,其计算长度的方法是遇到字符串结束符”\0”为止。

2).sizeof()

a.sizeof()运算符,用于求参数类型的长度。

b.当字符串赋值给数组时,用这运算符求数组的长度,会求出字符串的长度,包括最后的结束符。

3).当用数组形式存储字符串时,用这两个函数获取字符串长度的情况如下

222144805.png

4).sizeof关注的只是类型

222207300.png

5).strlen关注的只是地址:从起地址到以’\0’结尾的地址间的字节数

222358985.png

5.字符串操作

1).除去字符串中的空格

222425357.png

十.可移植的数据类型

1.不透明类型

1).不透明的数据类型隐藏了它们内部格式或结构,作为替代,开发者利用typedef声明一个类型,即不透明类型。如:Int16_tint32_t等,必须包含头文件:inttypes.h

2.指定数据类型

1).内核中有些数据类型虽然无需要用透明数据类型,但它们已被指定了数据类型,比如jiffy数目用的是unsigned long型,视其为unsigned是常见的错误。

3.长度明确的类型

1).有时,我们需要在程序中使用长度确定的数据,比如一个网络数据包。

十一.volatile类型

1.加上关键字volatile,告诉编译器该定义的变量的值是不稳定的,不能从寄存器中读取该变量(变量用得多,系统会将该变量放到寄存器里面的缓存中),只能从内存或存储器里面中读取该值。

2.定义方式:

int volatile a;

十二.restrict类型

1.只能修饰指针加上这关键字,对变量使用时的程序进行优化

2.应用

222438490.png

十三.类型转换

1.隐式类型转换

int->unsigned int->long->unsigned long->long long->

unsigned long long->float->double->long double

1).隐式转换都是“小”类型向“大”类型转换的。隐式转换都是低精度向高精度类型转换的,因此不会产生丢失信息的危险。

2).无符号型比有符号型占用空间大,因此在类型转换中他们的转换是从有符号类型向无符号类型转换

3).注重,上面并不必然合用于各种计算机,比如当intlong具有相同字长时,unsigned int的精度就会比long的精度高(事实上针对32机器的编译器都是这样)

4).此外需要注重的一点是并没有将charshort型写入上式,原因是他们可以被晋升到int也可能被晋升到unsigned int

2.强制类型转换

1).格式:(数据类型)表达式;

2).强制类型转换一般是把高精度类型转换成低精度类型,存在丢失数据信息的危险。

3.实例-隐式转换1

片段A:

unsigned short i;

            unsigned short index=0;

            for(i=0;i<index-1;i++){

            }

片段B

        unsigned short i;

        unsigned long index=0;

        for(i=0;i<index-1;i++){

        }

程序不能进入片段Afor语句,能进入片段B

原因如下:

  1、在轨范片段A中,index是无符号短整型unsigned short,所以,当执行到语句 i<index-1 时,因为类型不匹配,右边的index1相减时会发生隐式类型转换,转换的轨则是低精度类型向高精度类型转换,即index将被转换成有符号整型,转换之后的index仍是0,是以轨范片段A中的index-1的功效就是 -1 ,此时判定 i<index-1,即 0<-1,显然不成立。当即退出轮回。

2、在轨范片段B中,index是无符号长整型unsigned long,所以,当执行到语句 i<index-1 时,因为类型不匹配,右边的index1相减时也会发生由低精度类型向高精度标的目的的隐式类型转换,即1将被转换成无符号长整型,是以轨范片段B中的index-1的过程用十六进制数暗示现实上就是0x0000-0x0001=0xffff,此时再把左边的 i 隐式转换成无符号长整型之后判定 i<index-1,即 0<0xffff,显然成立。当即进入轮回。

4.实例-隐式转换2

222454312.png

222507104.png

5.实例-强制转换

chara0;

double a1=2.0445;

printf(“%x\n”,&a0-(char *)&a1);//类型不一致,地址不能相减