目录
一、数据类型
1、变量(Variable)
2、数据类型(Data Type)
3、C 语言中的整数(short,int,long)
4、二进制数、八进制数和十六进制数的表示
5、二进制数、八进制数和十六进制数的输出
6、C 语言中的正负数及其输出
7、C 语言中的小数(float,double)
8、在 C 语言中使用英文字符
9、C 语言转义字符
二、运算符、表达式和语句
1、对取余运算的说明
2、C 语言自增(++)和自减(--)运算符
3、C 语言运算符的优先级和结合性
4、C 语言数据类型转换(自动转换+强制转换)
5、sizeof和size_t类型
一、数据类型
1、变量(Variable)
(1)赋值是指把数据放到内存的过程。
(2)int a; 创造了一个变量 a,我们把这个过程叫做变量定义。 a=123; 把 123 交给了变量 a,我们把这个过程叫做给变量赋值;又因为是第一次赋值,也称变量的初始化,或者赋初值。
2、数据类型(Data Type)
(1)顾名思义,数据类型用来说明数据的类型,确定了数据的解释方式,让计算机和程序员不会产生歧义。
(2)数据类型只在定义变量时指明,而且必须指明;使用变量时无需再指明(包括指针),因为此时的数据类型已经确定了。
(3)在 C 语言中,每一种数据类型所占用的字节数都是固定的,知道了数据类型,也就知道了数据的长度。
说 明 | 字符型 | 短整型 | 整型 | 长整型 | 单精度浮点型 | 双精度浮点型 |
数据类型 | char | short | int | long | float | double |
长 度 | 1 | 2 | 4 | 4 | 4 | 8 |
3、C 语言中的整数(short,int,long)
让整数占用更少的内存可以在 int 前边加 short,让整数占用更多的内存可以在 int 前边加 long。
short int a = 10;
short int b, c = 99;
long int m = 102023;
long int n, p = 562131;
这样 a、 b、 c 只占用 2 个字节的内存,而 m、 n、 p 可能会占用 8 个字节的内存。也可以将 int 省略,只写 short 和 long
(1)short、 int、 long 是 C 语言中常见的整数类型,其中 int 称为整型, short 称为短整型, long 称为长整型。
(2)整型的长度:
- 在 16 位环境下,short 的长度为 2 个字节, int 也为 2 个字节, long 为 4 个字节。 16 位环境多用于单片机和
- 低级嵌入式系统,在 PC 和服务器上已经见不到了。
- 对于 32 位的Windows、 Linux 和 Mac OS,short 的长度为 2 个字节, int 为 4 个字节, long 也为 4 个字节。PC 和服务器上的 32 位系统占有率也在慢慢下降,嵌入式系统使用 32 位越来越多。
- 在 64 位环境下,不同的操作系统会有不同的结果
操作系统 | short | int | long |
Win64(64 位 Windows) | 2 | 4 | 4 |
类 Unix 系统(包括 Unix、 Linux、 Mac OS、 BSD、 Solaris 等) | 2 | 4 | 8 |
(3)不同整型的输出:
使用不同的格式控制符可以输出不同类型的整数,它们分别是:
- %hd 用来输出short int 类型, hd 是 short decimal 的简写;
- %d 用来输出int 类型, d 是 decimal 的简写;
- %ld 用来输出 long int类型, ld 是 long decimal 的简写。
4、二进制数、八进制数和十六进制数的表示
表示一个十进制数字不需要任何特殊的格式。但是,表示一个二进制、八进制或者十六进制数字就不一样了
(1)二进制:
二进制由 0 和 1 两个数字组成,使用时必须以 0b 或 0B(不区分大小写)开头
合法的二进制
int a = 0b101; 换算成十进制为 5
int b = -0b110010; 换算成十进制为 -50
int c = 0B100001; 换算成十进制为 33
非法的二进制
int m = 101010; 无前缀 0B,相当于十进制
int n = 0B410; 4不是有效的二进制数字
读者请注意,标准的 C 语言并不支持上面的二进制写法,只是有些编译器自己进行了扩展,才支持二进制数字。 换句话说,并不是所有的编译器都支持二进制数字,只有一部分编译器支持,并且跟编译器的版本有关系。
(2)八进制:
八进制由 0~7 八个数字组成,使用时必须以 0 开头(注意是数字 0,不是字母 o)
合法的八进制数
int a = 015; 换算成十进制为 13
int b = -0101; 换算成十进制为 -65
int c = 0177777; 换算成十进制为 65535
非法的八进制
int m = 256; 无前缀 0,相当于十进制
int n = 03A2; A不是有效的八进制数字
(3)十六进制:
十六进制由数字 0~9、字母 A~F 或 a~f(不区分大小写)组成,使用时必须以 0x 或 0X(不区分大小写)开头。
合法的十六进制
int a = 0X2A; 换算成十进制为 42
int b = -0XA0; 换算成十进制为 -160
int c = 0xffff; 换算成十进制为 65535
非法的十六进制
int m = 5A; 没有前缀 0X,是一个无效数字
int n = 0X3H; H不是有效的十六进制数字
(4)十进制
十进制由 0~9 十个数字组成,没有任何前缀,和我们平时的书写格式一样,不再赘述。
5、二进制数、八进制数和十六进制数的输出
① 十六进制数字的表示用到了英文字母,有大小写之分,要在格式控制符中体现出来:
- %hx、 %x 和 %lx 中的 x 小写,表明以小写字母的形式输出十六进制数;
- %hX、 %X 和 %lX 中的 X 大写,表明以大写字母的形式输出十六进制数。
② 八进制数字和十进制数字不区分大小写,所以格式控制符都用小写形式。
| short | int | long |
八进制 | %ho | %o | %lo |
十进制 | %hd | %d | %ld |
十六进制 | %hx 或者 %hX | %x 或者 %X | %lx 或者 %lX |
③ 输出时加上前缀
区分不同进制数字的一个简单办法就是,在输出时带上特定的前缀。在格式控制符中加上 # 即可输出前缀,例如 %#x、 %#o、 %#lX、 %#ho 等,请看下面的代码:
short a = 0b1010110; 二进制数字
int b = 02713; 八进制数字
long c = 0X1DAB83; 十六进制数字
printf("a=%#ho, b=%#o, c=%#lo\n", a, b, c); 以八进制形似输出
printf("a=%hd, b=%d, c=%ld\n", a, b, c); 以十进制形式输出
printf("a=%#hx, b=%#x, c=%#lx\n", a, b, c); 以十六进制形式输出(字母小写)
printf("a=%#hX, b=%#X, c=%#lX\n", a, b, c); 以十六进制形式输出(字母大写)
运行结果:
a=0126, b=02713, c=07325603
a=86, b=1483, c=1944451
a=0x56, b=0x5cb, c=0x1dab83
a=0X56, b=0X5CB, c=0X1DAB83
6、C 语言中的正负数及其输出
① C 语言规定,把内存的最高位作为符号位。
② C 语言规定,在符号位中,用 0 表示正数,用 1 表示负数。
③ C 语言允许我们这样做,如果不希望设置符号位,可以在数据类型前面加上 unsigned 关键字。不加 unsigned 的数字称为有符号数,能表示正数和负数,加了unsigned 的数字称为无符号数,只能表示正数。
unsigned short a = 12;
unsigned int b = 1002;
unsigned long c = 9892320;
short、 int、 long 中就没有符号位了,所有的位都用来表示数值,正数的取值范围更大了。
④ 无符号数的输出:无符号数可以以八进制、十进制和十六进制的形式输出,它们对应的格式控制符分别为:
| short | int | long | unsigned short | unsigned int | unsigned long |
八进制 | -- | -- | -- | %ho | %o | %lo |
十进制 | %hd | %d | %ld | %hu | %u | %lu |
十六进制 | -- | -- | -- | %hx 或者 %hX | %x 或者 %X | %lx 或者 %lX |
- 当以有符号数的形式输出时, printf 会读取数字所占用的内存,并把最高位作为符号位,把剩下的内存作为数值位;
- 当以无符号数的形式输出时, printf 也会读取数字所占用的内存,并把所有的内存都作为数值位对待。
7、C 语言中的小数(float,double)
C 语言中常用的小数有两种类型,分别是 float 或 double; float 称为单精度浮点型, double 称为双精度浮点型。
小数也可以使用 printf 函数输出,包括十进制形式和指数形式,它们对应的格式控制符分别是:
- %f 以十进制形式输出 float 类型;
- %lf 以十进制形式输出 double 类型;
- %e 以指数形式输出 float 类型,输出结果中的 e 小写;
- %E 以指数形式输出 float 类型,输出结果中的 E 大写;
- %le 以指数形式输出 double 类型,输出结果中的 e 小写;
- %lE 以指数形式输出 double 类型,输出结果中的 E 大写。
- %g 会对比小数的十进制形式和指数形式,以最短的方式来输出小数。所谓最短,就是输出结果占用最少的字符。
读者需要注意的两点是:
- %g 默认最多保留六位有效数字,包括整数部分和小数部分; %f 和 %e 默认保留六位小数,只包括小数部分。
- %g不会在最后强加 0来凑够有效数字的位数,而 %f 和 %e 会在最后强加 0 来凑够小数部分的位数。
- 除了 %g,还有 %lg、 %G、 %lG:
① %g 和 %lg 分别用来输出 float 类型和 double 类型,并且当以指数形式输出时, e 小写。
② %G 和 %lG 分别用来输出 float 类型和 double 类型,只是当以指数形式输出时, E 大写。
8、在 C 语言中使用英文字符
① 经常用到的字符类型是 char,它的长度是 1,只能容纳 ASCII 码表中的字符,也就是英文字符。
② 字符类型由单引号' '包围,字符串由双引号" "包围。
③ 字符的输出:输出 char 类型的字符有两种方法,分别是:
- 使用专门的字符输出函数 putchar;
- 使用通用的格式化输出函数 printf, char 对应的格式控制符是%
9、C 语言转义字符
转义字符 | 意义 | ASCII 码值(十进制) |
\a | 响铃(BEL) | 007 |
\b | 退格(BS) ,将当前位置移到前一列 | 008 |
\f | 换页(FF),将当前位置移到下页开头 | 012 |
\n | 换行(LF) ,将当前位置移到下一行开头 | 010 |
\r | 回车(CR) ,将当前位置移到本行开头 | 013 |
\t | 水平制表(HT) | 009 |
\v | 垂直制表(VT) | 011 |
\' | 单引号 | 039 |
\" | 双引号 | 034 |
\\ | 反斜杠 | 092 |
二、运算符、表达式和语句
1、对取余运算的说明
余数可以是正数也可以是负数,由 % 左边的整数决定:
- 如果 % 左边是正数,那么余数也是正数;
printf(
"100%%12=%d \n100%%-12=%d \n-100%%12=%d \n-100%%-12=%d \n",
100 % 12, 100 % -12, -100 % 12, -100 % -12
);
运行结果:
100%12=4
100%-12=4
-100%12=-4
-100%-12=-4
2、C 语言自增(++)和自减(--)运算符
++和--分别称为自增运算符和自减运算符。
int a = 10, b = 20;
printf("a=%d, b=%d\n", a, b);
++a;
--b;
printf("a=%d, b=%d\n", a, b);
a++;
b--;
printf("a=%d, b=%d\n", a, b);
运行结果:
a=10, b=20
a=11, b=19
a=12, b=18
需要重点说明的是, ++ 在变量前面和后面是有区别的:
- ++ 在前面叫做前自增(例如 ++a)。前自增先进行自增运算,再进行其他操作。
- ++ 在后面叫做后自增(例如 a++)。后自增先进行其他操作,再进行自增运算。
自减(--)也一样,有前自减和后自减之分。
int a = 10, b = 20, c = 30, d = 40;
int a1 = ++a, b1 = b++, c1 = --c, d1 = d--;
printf("a=%d, a1=%d\n", a, a1);
printf("b=%d, b1=%d\n", b, b1);
printf("c=%d, c1=%d\n", c, c1);
printf("d=%d, d1=%d\n", d, d1);
输出结果:
a=11, a1=11
b=21, b1=20
c=29, c1=29
d=39, d1=40
a1=++a;会先进行自增操作,再进行赋值操作;而 b1=b++;会先进行赋值操作,再进行自增操作。
int a = 12, b = 1;
int c = a - (b--); ①
int d = (++a) - (--b); ②
printf("c=%d, d=%d\n", c, d);
输出结果:
c=11, d=14
- 执行语句①时,因为是后自减,会先进行 a-b 运算,结果是 11,然后 b 再自减,就变成了 0;最后再将 a-b 的结果(也就是 11)交给 c,所以 c 的值是 11。
- 执行语句②之前, b 的值已经变成 0。对于 d=(++a)-(--b), a 会先自增,变成 13,然后 b 再自减,变成 -1,最后再计算 13-(-1),结果是 14,交给 d,所以 d 最终是 14。
3、C 语言运算符的优先级和结合性
优先级 | 运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
1 | [] | 数组下标 | 数组名[常量表达式] | 左到右 | |
() | 圆括号 | (表达式) | | ||
. | 成员选择(对象) | 对象.成员名 | | ||
-> | 成员选择(指针) | 对象指针->成员名 | | ||
2 | - | 负号运算符 | -表达式 | 右到左 | 单目运算符 |
(类型) | 强制类型转换 | (数据类型)表达式 | | ||
++ | 自增运算符 | ++变量名 | 单目运算符 | ||
-- | 自减运算符 | --变量名 | 单目运算符 | ||
* | 取值运算符 | *指针变量 | 单目运算符 | ||
& | 取地址运算符 | &变量名 | 单目运算符 | ||
! | 逻辑非运算符 | !表达式 | 单目运算符 | ||
~ | 按位取反运算符 | ~表达式 | 单目运算符 | ||
sizeof | 长度运算符 | sizeof(表达式) | | ||
3 | / | 除 | 表达式 / 表达式 | 左到右 | 双目运算符 |
* | 乘 | 表达式*表达式 | 双目运算符 | ||
% | 余数(取模) | 整型表达式%整型表达式 | 双目运算符 | ||
4 | + | 加 | 表达式+表达式 | 左到右 | 双目运算符 |
- | 减 | 表达式-表达式 | 双目运算符 | ||
5 | << | 左移 | 变量<<表达式 | 左到右 | 双目运算符 |
>> | 右移 | 变量>>表达式 | 双目运算符 | ||
6 | > | 大于 | 表达式>表达式 | 左到右 | 双目运算符 |
>= | 大于等于 | 表达式>=表达式 | 双目运算符 | ||
< | 小于 | 表达式<表达式 | 双目运算符 | ||
<= | 小于等于 | 表达式<=表达式 | 双目运算符 | ||
7 | == | 等于 | 表达式==表达式 | 左到右 | 双目运算符 |
!= | 不等于 | 表达式!= 表达式 | 双目运算符 | ||
8 | & | 按位与 | 表达式&表达式 | 左到右 | 双目运算符 |
9 | ^ | 按位异或 | 表达式^表达式 | 左到右 | 双目运算符 |
10 | | | 按位或 | 表达式|表达式 | 左到右 | 双目运算符 |
11 | && | 逻辑与 | 表达式&&表达式 | 左到右 | 双目运算符 |
12 | || | 逻辑或 | 表达式||表达式 | 左到右 | 双目运算符 |
13 | ?: | 条件运算符 | 表达式1? 表达式2: 表达式3 | 右到左 | 三目运算符 |
14 | = | 赋值运算符 | 变量=表达式 | 右到左 | |
/= | 除后赋值 | 变量/=表达式 | | ||
*= | 乘后赋值 | 变量*=表达式 | | ||
%= | 取模后赋值 | 变量%=表达式 | | ||
+= | 加后赋值 | 变量+=表达式 | | ||
-= | 减后赋值 | 变量-=表达式 | | ||
<<= | 左移后赋值 | 变量<<=表达式 | | ||
>>= | 右移后赋值 | 变量>>=表达式 | | ||
&= | 按位与后赋值 | 变量&=表达式 | | ||
^= | 按位异或后赋值 | 变量^=表达式 | | ||
|= | 按位或后赋值 | 变量|=表达式 | | ||
15 | , | 逗号运算符 | 表达式,表达式,… | 左到右 |
|
容易出错的优先级
优先级问题 | 表达式 | 经常误认为的结果 | 实际结果 |
. 的优先级高于 *(-> 操作符用于消除这个问题) | *p.f | p 所指对象的字段 f,等价于: (*p).f | 对 p 取 f 偏移,作为指针,然后进行解除引用操作,等价于: *(p.f) |
[] 高于 * | int *ap[] | ap 是个指向 int 数组的指针,等价于: int (*ap)[] | ap 是个元素为 int 指针的数组,等价于: int *(ap []) |
函数 () 高于 * | int *fp() | fp 是个函数指针,所指函数返回 int,等价于: int (*fp)() | fp 是个函数,返回 int*,等价于: int* ( fp() ) |
== 和 != 高于位操作 | (val & mask != 0) | (val &mask) != 0 | val & (mask != 0) |
== 和 != 高于赋值符 | c = getchar() != EOF | (c = getchar()) != EOF | c = (getchar() != EOF) |
算术运算符高于位移 运算符 | msb << 4 + lsb | (msb << 4) + lsb | msb << (4 + lsb) |
逗号运算符在所有运 算符中优先级最低 | i = 1, 2 | i = (1,2) | (i = 1), 2 |
4、C 语言数据类型转换(自动转换+强制转换)
数据类型转换就是将数据(变量、数值、表达式的结果等)从一种类型转换为另一种类型。
1、自动类型转换
自动类型转换就是编译器默默地、隐式地、偷偷地进行的数据类型转换,这种转换不需要程序员干预,会自动发生。
不建议这种事情发生,因为会导致数据失真。
2、强制类型转换
在代码中明确地提出要进行类型转换,这称为强制类型转换。
(float)a; 将变量 a 转换为 float 类型
(int)(x + y); 把表达式 x+y 的结果转换为 int 整型
(float)100; 将数值 100(默认为int类型)转换为 float 类型
5、sizeof和size_t类型
6、自动算出数组的个数