顺序程序设计
看了这章的标题和内容后,真的觉得这标题和内容有关系么;顺序结构就是一种自上而下的思路,一条到底,不进行选择,跳转,这章内容后面讲的却是数据类型和操作运算符,2.1略,后面不想按他的要点来归纳了,由于内容有点多,又不想板书,部分内容引用了 siriyang 博客内容
2.2 数据类型和存储形式
数据类型包括了两个含义,一是指明了是什么类型的数据,二是包括了数据的操作,比如int类型是整型,可以进行算术运算
2.2.1 c的数据类型

2.2.2 数据表现形式-常量和变量
常量:运行时不能改变的量,比如数值常数值
整型常量
实型常量
十进制数形式:由 0~ 9 和小数点组成。注意,必须有小数点
指数形式:以“e”或“E”代表以10为底的指数。3.14e3(表示3.14*10^3)
变量:字面意思就是可变的量,必须先声明后使用
变量名:要声明变量时,实际是计算机找了一块内存空间,操作系统依靠唯一的地址来识别这块内存,声明变量就是给这块内存取了个名字,在程序运行期间,用这个变量名来操作对这块内存;
我以前有个问题,就是明明操作系统可以用地址来找到这块内存,为什么还要用声明变量的方式来操作呢?其实这就是高级语言的特性,人操作不可能直接记内存地址,不实际,用变量名来操作就很好操作了
第二个问题就是那用变量名的话怎么确保计算机能找到,因为在计算机内变量名是可能重复的,比如在A程序中声明了一个x变量,在B程序中也声明了一个x变量,不可能所有变量名都不重复?这个其实就是依靠编译器和作用域来确定了,一般同一个程序中,不允许声明两个同样的变量名,编译的时候就会报错;如果要用同一个变量名,就要在不同的作用域内,虽然他们名字相同,但编译器确保了程序运行时始终能找到正确的内存空间
变量值:这个值就是变量名对应的这块内存内所存储的值;
变量一般的形式:类型名 变量名=初始值; 例: int a=0;
c中要求变量名要符合标识符的要求
- 标识符只能由数字字母下划线组成
- 不能以数字开头(原因参考编译原理的二型文法和三型文法)
- 严格区分大小写
- 不允许用 关键字
书上有一段关于类型与变量的论述
每一个变量都属于一个确定的类型,类型是变量的共性。类型相当于建造房屋的图纸,按照同一套图纸可以建造出许多套外形和结构完全相同的房屋,它们具有相同的特征。但图纸是不能住人的,只有建成的房屋才能住人。
类型是抽象的,不占用存储单元,不能用来存放数据。
变量是具体的,变量占存储单元,可以用来存储数据。
2.2.3 整型数据
1.三种形式: 十进制,八进制,二进制
书里没写,还有十六进制,一般以0x开头,用0~9,a~f(10-15)表示0~15,逢16进
用8421码 F (1111) 2=(8+4+2+1) 10=(15) 10
2.在内存中数据以二进制形式存放
数值是以补码表示的:
- 正数的补码和原码相同
- 负数的补码:将该数的绝对值的二进制形式按位取反再加1
左面第一位是符号位, 一般0为正,1为负
关于原码反码我的组成原理写的详细些,这里略了
3.整型分类
1) 基本型 int
, 4字节,一个字节是八位,所以有32位,除去第一位符号位,还有31位可以表示数值,表示范围为-2 31~2 31-1,这里的减一是0,下面类推
2) 短整型 short int
或 short
,2字节
3) 长整型 long int
或 long
,4字节,一般有后缀L或l
4) 双长型 long long int
或 long long
,8字节
5) 无符号型 unsigned
,没有符号位,全部用来表示数值,4字节,表示范围为 0~2 32-1,一般有后缀U或u
无符号短整型: unsigned short
2字节,无符号长整型: unsigned long
4字节,无符号双长整型: unsigned long long
8字节
字节数一般由编译系统规定,所以不同机器可能有出入,但总的来说,短整型<基本型<双长型
课本里有这样一个题目,来说明溢出的
1 |
|
溢出,就是表示的数已经超过最大能表示的范围了
a是 0(1···1)15个1 ,a=32767
加1进位则b是1(0···0)15个0,b=-32768
实际可以看出,这里的类型都有固定的位数,都有表示的范围,而且这个的范围是一个闭环,运算就是在这个环上操作,超出正常表示范围即溢出
2.2.4 字符型数据
字符是按整数形式存储的,因此属于整数类型
1.字符常量
普通字符和转义字符:普通字符就是数字,字母,字符等,一般采用ASCII码;转义字符则是一种控制字符
特别的字符1和数字1是是不同的,字符1是一个符号,会原样输出,ASCII码49,一个字节;数字1是个数字,以二进制补码存储;
常见的转义字符
转义字符 | 转义字符的意义 | ASCII代码 |
---|---|---|
\n | 回车换行 | 10 |
\t | 横向跳到下一制表位置 | 9 |
\b | 退格 | 8 |
\r | 回车 | 13 |
\f | 走纸换页 | 12 |
\ | 反斜线符”\“ | 92 |
\‘ | 单引号符 | 39 |
\“ | 双引号符 | 34 |
\a | 警告 | 7 |
\ddd | 1\~3为八进制数所代表的字符 | |
\xhh | 1\~2位十六进制数所代表的字符 |
2.字符变量
c用字符变量char
来定义,声明一个字符串变量,实际是把字符对应的ASCII码放到内存中
1 | char c='a'; |
‘a’的ASCII是97,二进制形式为01100001
ASCII第一位都是0,后面七位数,表示127种字符
因为字符变量是以整数形式存在内存中的,所以可以对他进行算数运算,通过格式符”%d”,”%c”控制输出形式
如果给字符赋一个整数值,只有低八位字节参与处理
1 | char c1=289; |
结果是!
ASCII的000~127是标准的,128~255是扩展的用于特定系统,289实际上已经超出了8位二进制数表示的范围,但是他的低8位正好是33,就是除去32位控制符的第一个字符!
3.字符串常量
字符常量是用单引号括起来的单个字符,字符串常量是用双引号括起来的字符序列
字符与字符串区别是字符串会在结尾加上一个’/0‘作为结束标记,因此字符串会多占一个字节的控制符
java中就有字符串string,c中是没有的,原因是 ,C 是静态弱类型语言,内存在编译的时候就要确定下来,如果提供个string,string又可长可短,编译器确定不了;c中用字符数组表示字符串
2.2.5 浮点型数据
1.浮点数
单精度型占4个字节(32位)内存空间,其数值范围为3.4E-38~3.4E+38,只能提供七位有效数字。
双精度型占8 个字节(64位)内存空间,其数值范围为1.7E-308~1.7E+308,可提供16位有效数字。
2.浮点数存储形式
数符+小数部分+指数
不同环境位数规定不同,比如有的是24位小数,8位指数
3.浮点数舍入误差
由于实数是由有限的存储单元组成的,因此能提供的有效数字总是有限的
比如:将3.1415926赋给float类型的变量就只能保证七位有效位置
2.3 表达式的运算
2.3.1 表达式
算数表达式: 数学运算
关系表达式: 比较大小
逻辑表达式: 判断逻辑真假,注意a&&b,若a为假,则不会判断b的真假,造成短路,还有||
赋值表达式: 赋值,不允许连续赋值
逗号表达式 :用逗号连接的表达式
2.3.2 运算符
由于符号太多,手写太麻烦,就直接引用菜鸟教程-C 运算符
算术运算符
下表显示了 C 语言支持的所有算术运算符。假设变量 A 的值为 10,变量 B 的值为 20,则:
运算符 | 描述 | 实例 |
---|---|---|
+ | 把两个操作数相加 | A + B 将得到 30 |
- | 从第一个操作数中减去第二个操作数 | A - B 将得到 -10 |
* | 把两个操作数相乘 | A * B 将得到 200 |
/ | 分子除以分母 | B / A 将得到 2 |
% | 取模运算符,整除后的余数 | B % A 将得到 0 |
++ | 自增运算符,整数值增加 1 | A++ 将得到 11 |
– | 自减运算符,整数值减少 1 | A– 将得到 9 |
关系运算符
下表显示了 C 语言支持的所有关系运算符。假设变量 A 的值为 10,变量 B 的值为 20,则:
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个操作数的值是否相等,如果相等则条件为真。 | (A == B) 为假。 |
!= | 检查两个操作数的值是否相等,如果不相等则条件为真。 | (A != B) 为真。 |
> | 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 | (A > B) 为假。 |
< | 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 | (A < B) 为真。 |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 | (A >= B) 为假。 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 | (A <= B) 为真。 |
逻辑运算符
下表显示了 C 语言支持的所有关系逻辑运算符。假设变量 A 的值为 1,变量 B 的值为 0,则:
运算符 | 描述 | 实例 | ||||
---|---|---|---|---|---|---|
&& | 称为逻辑与运算符。如果两个操作数都非零,则条件为真。 | (A && B) 为假。 | ||||
\ | \ | 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。 | (A \ | \ | B) 为真。 | |
! | 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 | !(A && B) 为真。 |
位运算符
位运算符作用于位,并逐位执行操作。&、 | 和 ^ 的真值表如下所示:
p | q | p & q | p \ | q | p ^ q |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | |
0 | 1 | 0 | 1 | 1 | |
1 | 1 | 1 | 1 | 0 | |
1 | 0 | 0 | 1 | 1 |
假设如果 A = 60,且 B = 13,现在以二进制格式表示,它们如下所示:
A = 0011 1100
B = 0000 1101
-—————-
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A = 1100 0011
下表显示了 C 语言支持的位运算符。假设变量 A 的值为 60,变量 B 的值为 13,则:
运算符 | 描述 | 实例 | ||||||
---|---|---|---|---|---|---|---|---|
& | 按位与操作,按二进制位进行”与”运算。运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1; |
(A & B) 将得到 12,即为 0000 1100 | ||||||
\ | 按位或运算符,按二进制位进行”或”运算。运算规则:`0 | 0=0; 0 | 1=1; 1 | 0=1; 1 | 1=1;` | (A \ | B) 将得到 61,即为 0011 1101 | |
^ | 异或运算符,按二进制位进行”异或”运算。运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0; |
(A ^ B) 将得到 49,即为 0011 0001 | ||||||
~ | 取反运算符,按二进制位进行”取反”运算。运算规则:~1=0; ~0=1; |
(~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。 | ||||||
<< | 二进制左移运算符。将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。 | A << 2 将得到 240,即为 1111 0000 | ||||||
>> | 二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。 | A >> 2 将得到 15,即为 0000 1111 |
赋值运算符
下表列出了 C 语言支持的赋值运算符:
运算符 | 描述 | 实例 | |||
---|---|---|---|---|---|
= | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | C = A + B 将把 A + B 的值赋给 C | |||
+= | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 | C += A 相当于 C = C + A | |||
-= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 | C -= A 相当于 C = C - A | |||
*= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 | C = A 相当于 C = C A | |||
/= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 | C /= A 相当于 C = C / A | |||
%= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 | C %= A 相当于 C = C % A | |||
<<= | 左移且赋值运算符 | C <<= 2 等同于 C = C << 2 | |||
>>= | 右移且赋值运算符 | C >>= 2 等同于 C = C >> 2 | |||
&= | 按位与且赋值运算符 | C &= 2 等同于 C = C & 2 | |||
^= | 按位异或且赋值运算符 | C ^= 2 等同于 C = C ^ 2 | |||
\ | = | 按位或且赋值运算符 | C \ | = 2 等同于 C = C \ | 2 |
杂项运算符 sizeof & 三元
下表列出了 C 语言支持的其他一些重要的运算符,包括 sizeof 和 ? :。
运算符 | 描述 | 实例 |
---|---|---|
sizeof() | 返回变量的大小。 | sizeof(a) 将返回 4,其中 a 是整数。 |
& | 返回变量的地址。 | &a; 将给出变量的实际地址。 |
* | 指向一个变量。 | *a; 将指向一个变量。 |
? : | 条件表达式 | 如果条件为真 ? 则值为 X : 否则值为 Y |
2.3.3 运算符优先级
运算符的优先级确定表达式中项的组合。这会影响到一个表达式如何计算。某些运算符比其他运算符有更高的优先级,例如,乘除运算符具有比加减运算符更高的优先级。
例如 x = 7 + 3 2,在这里,x 被赋值为 13,而不是 20,因为运算符 具有比 + 更高的优先级,所以首先计算乘法 3*2,然后再加上 7。
下表将按运算符优先级从高到低列出各个运算符,具有较高优先级的运算符出现在表格的上面,具有较低优先级的运算符出现在表格的下面。在表达式中,较高优先级的运算符会优先被计算。
类别 | 运算符 | 结合性 | ||
---|---|---|---|---|
后缀 | () [] -> . ++ - - | 从左到右 | ||
一元 | + - ! ~ ++ - - (type)* & sizeof | 从右到左 | ||
乘除 | * / % | 从左到右 | ||
加减 | + - | 从左到右 | ||
移位 | << >> | 从左到右 | ||
关系 | < <= > >= | 从左到右 | ||
相等 | == != | 从左到右 | ||
位与 AND | & | 从左到右 | ||
位异或 XOR | ^ | 从左到右 | ||
位或 OR | \ | 从左到右 | ||
逻辑与 AND | && | 从左到右 | ||
逻辑或 OR | \ | \ | 从左到右 | |
条件 | ?: | 从右到左 | ||
赋值 | = += -= *= /= %=>>= <<= &= ^= \ | = | 从右到左 | |
逗号 | , | 从左到右 |
2.3.4 数据之间的混合运算
自动转换遵循以下规则:
- 若参与运算量的类型不同,则先转换成同一类型,然后进行运算
- 转换按数据长度增加的方向进行,以保证精度不降低。如
int
型和long
型运算时,先把int
量转成long
型后再进行运算 - 所有的浮点运算都是以双精度进行的,即使仅含
float
单精度量运算的表达式,也要先转换成double
型,再作运算 char
型和short
型参与运算时,必须先转换成int
型- 在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换为左边量的类型。如果右边量的数据类型长度左边长时,将丢失一部分数据,这样会降低精度,丢失的部分按四舍五入向前舍入
2.3.5 强制类型转换
(类型名)(表达式)
- 类型说明符和表达式都必须加括号(单个变量可以不加括号)
- 无论是强制转换或是自动转换,都只是为了本次运算的需要而对变量的数据长度进行的临时性转换,而不改变数据说明时对该变量定义的类型
- 强制转换可能会照成精度的误差
2.4 C语句概述
C 语句可分为以下五类:
- 表达式语句:表达式语句由表达式加上分号“;”组成。
- 函数调用语句:由函数名、实际参数加上分号“;”组成。
- 控制语句:控制语句用于控制程序的流程,以实现程序的各种结构方式。它们由特定的语句定义符组成。
- 条件判断语句:if语句、switch语句;
- 循环执行语句:dowhile语句、while语句、for语句;
- 转向语句:break语句、goto语句、continue语句、return语句。
- 复合语句:把多个语句用括号{}括起来组成的一个语句称复合语句。
- 空语句:只有分号“;”组成的语句称为空语句。空语句是什么也不执行的语句。在程序中空语句可用来作空循环体。
2.4.4 赋值语句的类型转换
略,见2.3.4归纳
2.5 数据输入输出的概念及在C语言中的实现
c本身不提供输入语句,输出语句,输入输出是由标准库函数实现的,所以在c程序开头要引入头文件
1 | #include< stdio.h > |
printf函数(格式输出函数)
1 | printf("%d\n",a); |
printf(“格式控制”,输出列表);
格式控制,其实就是双引号括起来的那段字符串,程序用这这段字符串做两个事情,一是确定你输出的是什么类型,二是控制输出怎么显示,达到你的要求
注意格式参数要和列表参数对应,否则编译报错
控制类型的字符如下
格式字符 | 意义 |
---|---|
d | 以十进制形式输出带符号整数(正数不输出符号) |
o | 以八进制形式输出无符号整数(不输出前缀 0) |
x,X | 以十六进制形式输出无符号整数(不输出前缀 0x) |
u | 以十进制形式输出无符号整数 |
f | 以小数形式输出单、双精度实数 |
e,E | 以指数形式输出单、双精度实数 |
g,G | 以%f 或%e 中较短的输出宽度输出单、双精度实数 |
c | 输出单个字符 |
s | 输出字符串 |
怎么控制显示格式呢?以下几种常用的
1.指定宽度和小数位数 %m.nf
m:总宽度,包括小数点;n:小数部分位数;如果m过大, 会在左边补空格;如果m过小, 会正常输出;不写n,取整
2.精度:精度格“.
,后跟十进制整数
如果输出数字,则表示小数的位数;如果输出的是字符,则表示输出字符的个数
scanf函数(格式输入函数)
1 | scanf("%d",&a); |
scanf(“格式控制”,地址列表);
类比printf(),但也有不同
1) 类型:表示输入数据的类型
格式 | d |
---|---|
o | 字符意义 |
x | 输入十进制整数 |
u | 输入八进制整数 |
f 或 e | 输入十六进制整数 输入无符号十进制整数 输入实型数(用小数形式或指数形式) |
c | 输入单个字符 |
s | 输入字符串 |
2) “\*
”符:用以表示该输入项,读入后不赋予相应的变量,即跳过该输入值。
如:
1 | scanf("%d %*d %d",&a,&b); |
复制
当输入为:1 2 3
时,把1
赋予a
,2
被跳过,3
赋予b
。
3) 宽度:用十进制整数指定输入的宽度(即字符数)。
例如:
1 | scanf("%5d",&a); |
复制
输入:12345678
只把 12345
赋予变量 a
,其余部分被截去。
又如:
1 | scanf("%4d%4d",&a,&b); |
复制
输入:12345678
将把 1234
赋予 a
,而把 5678
赋予 b
。
4) 长度:长度格式符为l
和h
,l
表示输入长整型数据(如%ld
)和双精度浮点数(如%lf
)。h
表示输入短整型数据。
使用 scanf 函数还必须注意以下几点:
1) scanf
函数中没有精度控制,如:scanf("%5.2f",&a);
是非法的。不能企图用此语句输入小数为 2 位的实数。
2) scanf
中要求给出变量地址,如给出变量名则会出错。如 scanf("%d",a);
是非法的,应改为scnaf("%d",&a);
才是合法的。
3) 在输入多个数值数据时,若格式控制串中没有非格式字符作输入数据之间的间隔则可用空格,TAB或回车作间隔。C 编译在碰到空格,TAB,回车或非法数据(如对“%d
”输入“12A
”时,A
即为非法数据)时即认为该数据结束。
4) 在输入字符数据时,若格式控制串中无非格式字符,则认为所有输入的字符均为有效字符。
例如:
1 | scanf("%c%c%c",&a,&b,&c); |
复制
输入为:d e f
则把’d
‘赋予 a
, ‘‘ 赋予
b
,’e
‘赋予 c
。
只有当输入为:def
时,才能把’d
‘赋于 a
,’e
‘赋予 b
,’f
‘赋予 c
。
如果在格式控制中加入空格作为间隔, 如:
1 | scanf ("%c %c %c",&a,&b,&c); |
复制
则输入时各数据之间可加空格。
2.4.5 字符数据的输入输出
getchar
函数:从键盘上输入一个字符
getchar
函数只能接受单个字符,输入数字也按字符处理。输入多于一个字符时,只接收第一个字符
putchar
函数是字符输出函数,是在显示器上输出单个字符,也可输出控制符,如(”\n”)