顺序程序设计

看了这章的标题和内容后,真的觉得这标题和内容有关系么;顺序结构就是一种自上而下的思路,一条到底,不进行选择,跳转,这章内容后面讲的却是数据类型和操作运算符,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 intshort,2字节
3) 长整型 long intlong,4字节,一般有后缀L或l
4) 双长型 long long intlong long,8字节
5) 无符号型 unsigned,没有符号位,全部用来表示数值,4字节,表示范围为 0~2 32-1,一般有后缀U或u

无符号短整型: unsigned short2字节,无符号长整型: unsigned long4字节,无符号双长整型: unsigned long long8字节

字节数一般由编译系统规定,所以不同机器可能有出入,但总的来说,短整型<基本型<双长型

课本里有这样一个题目,来说明溢出的

1
2
3
4
5
6
7
8
#include<stdio.h>
void main(){
int a,b;
a = 32767;
b = a+1;
printf("a=%d,b=%d\n",a,b);
}
运行结果:a=32767,b=-32768

溢出,就是表示的数已经超过最大能表示的范围了

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
2
char c1=289;
printf("zifushi %c\n", c1);

结果是!

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 数据之间的混合运算

自动转换遵循以下规则:

  1. 若参与运算量的类型不同,则先转换成同一类型,然后进行运算
  2. 转换按数据长度增加的方向进行,以保证精度不降低。如 int 型和 long 型运算时,先把 int 量转成 long型后再进行运算
  3. 所有的浮点运算都是以双精度进行的,即使仅含 float 单精度量运算的表达式,也要先转换成 double型,再作运算
  4. char 型和 short 型参与运算时,必须先转换成 int
  5. 在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换为左边量的类型。如果右边量的数据类型长度左边长时,将丢失一部分数据,这样会降低精度,丢失的部分按四舍五入向前舍入

2.3.5 强制类型转换

(类型名)(表达式)

  1. 类型说明符和表达式都必须加括号(单个变量可以不加括号)
  2. 无论是强制转换或是自动转换,都只是为了本次运算的需要而对变量的数据长度进行的临时性转换,而不改变数据说明时对该变量定义的类型
  3. 强制转换可能会照成精度的误差

2.4 C语句概述

C 语句可分为以下五类:

  1. 表达式语句:表达式语句由表达式加上分号“;”组成。
  2. 函数调用语句:由函数名、实际参数加上分号“;”组成。
  3. 控制语句:控制语句用于控制程序的流程,以实现程序的各种结构方式。它们由特定的语句定义符组成。
    1. 条件判断语句:if语句、switch语句;
    2. 循环执行语句:dowhile语句、while语句、for语句;
    3. 转向语句:break语句、goto语句、continue语句、return语句。
  4. 复合语句:把多个语句用括号{}括起来组成的一个语句称复合语句。
  5. 空语句:只有分号“;”组成的语句称为空语句。空语句是什么也不执行的语句。在程序中空语句可用来作空循环体。

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赋予a2被跳过,3赋予b

3) 宽度:用十进制整数指定输入的宽度(即字符数)。
  例如:

1
scanf("%5d",&a);

复制

  输入:12345678
  只把 12345 赋予变量 a,其余部分被截去。
  又如:

1
scanf("%4d%4d",&a,&b);

复制

  输入:12345678
  将把 1234 赋予 a,而把 5678 赋予 b

4) 长度:长度格式符为lhl表示输入长整型数据(如%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”)