【c语言跟练】笔记3-运算

引言

为什么要区分数据类型?

  • 整数运算快,所以需要识别是不是整数

  • but现在可能char、short也是按int存储,不见得更快

  • 此外,现在计算机性能好,所有就int就行,不用再指明

  • 现在,遇到数据类型区分更多是和硬件控制有关

不同语言对数据类型定义都有什么要求?

  • c语言允许过渡变化

  • c++/Java对变量预先定义更严格

  • python不要求预先定义,直接用就行


第五章 数据类型

一、数据类型

1.简介

  1. 整数:char、short、int、long、long long

  1. 浮点数:float、double、long double

  1. 逻辑:bool

  1. 指针:

  1. 其他:自定义

2.占据内存大小

// 查看各种类型数据所占字节数
printf("char = %d\n", sizeof(char));

printf("short = %d\n", sizeof(short));
printf("int = %d\n", sizeof(int));
printf("long = %d\n", sizeof(long));
printf("long long = %d\n", sizeof(long long));

printf("float = %d\n", sizeof(float));
printf("double = %d\n", sizeof(double));

(一)整数

    • 数在计算机上的存储

  • 数据在计算机内都是以二进制的形式表示,数据存储重要的是以什么方式去看待它,而不是内部具体怎么表示

  • 内存:1个字节可表达数的范围:00000000 —— 11111111 (0-255)。1字节能表达2^8=256种信息,正数+零= 负数 = 128种信息,所以正数的范围比负数少一个。正数a的补码等于本身,零即为零,负数-a的补码是0-a求出,即2^n-a

举例:数据的表达
18 -> 00010010
0 -> 00000000
-18 -> ?

2.如何表达负数?

  • 人脑思维,以十进制为例:

12 +(-18)-> 12 - 18 -> -6
12 -(-18)-> 12 + 18 -> 30
12 *(-18)-> - 12 * 18 -> ……
12 /(-18)-> - 12 / 18 -> ……
  • 计算机思维,以二进制为例:

方案1:仿照十进制,特殊符号表示

需要控制运算符,比如有负号,+ -> -

方案2:取中间的数为0,如10000000表示0,比它小为负数,比它大为整数

需要转换,比如
10000000(128)->0
10000001(129)->1
也就是说需要换算成正常二进制转换,再转换为想表达的数

方案3:创造一种数的表现形式,特殊符号表示+可以直接运算,不用控制什么——那就是补码

正数a的补码等于本身,零即为零,负数-a的补码是0-a求出,即2^n-a。

一个字节表示数的范围:
无符号:
00000000 ~11111111 (0-255)
有符号:
0111 1111 ->127(2^7-1)
0000 0001 ->1
0000 0000 ->0【界限】
1111 1111 ->-1
1000 0001 ->-127
1000 0000 ->-128
首位为符号位,通过加和为0求负数表达式(补码)

二进制(补码) -> 十进制

  • 零:0000 0000 ->0

  • 正数:0000 0001 ~ 0111 1111 ->1~127

  • 负数:1111 1111 ~ 1000 0000 ->-1~-128

3.无符号数?

  • 定义,如unsigned int ……

  • 表明,如字面常量255U

4.整数越界?

有符号数:
1111 1111(-1) + 0000 0001(1) -> 1 0000 0000(0)
0111 1111(127)+ 0000 0001(1) -> 1000 0000(-128)
无符号数:
1111 1111(255)+ 0000 0001(1) -> 1 0000 0000(0)

5.不同进制输入输出?

  • 十进制:正常

  • 八进制:0……

  • 十六进制:0x……

//不同进制输入
char a = 012;
/*十进制格式化输出 %d:012(八)——001 010(二进制)——0000 1010(char,根据符号位判断,正数)——10*/
char b = 0x12;
/*十进制格式化输出 %d:0x12(十六)——0001 0010(二进制)——0001 0010(char,根据符号位判断,正数)——18*/
printf("a = %o",a);//八进制输入 12
printf("a = 0%o",a);//八进制输入 012
printf("a = %x",a);//十六进制输入 12
printf("a = 0%x",a);//十六进制输入 0x12
补充:
1.换算不同进制,会用计算器看就行
2.无论怎么样,计算机内都是二进制,八进制、十进制、十六进制都是人机交互层面的
3.程序员常用十六进制表示数,因为十六进制一位-二进制四位,好转换

附件:int数据类型最大的数

4.数据类型的选择

无特殊情况,用int

总结

  • 数据类型&占据字节数&占位符&表达数的范围

数据类型

sizeof() 字节数

格式化输入输出

(占位符)

数的范围

char

1字节

int及以下:

%d(十进制)

%o(八进制)

%x (十六进制,字母小写)

%X(十六进制,字母大写)

-128 ~ 127

整型

short

2字节

-256 ~ 255

int

4字节(取决于编译器、CPU,通常“1个字”)

long

4字节(取决于编译器、CPU,通常“1个字”)

long long:

%ld(十进制)

long long

8字节

无符号数

unsigned

%u

无符号long long %lu

sum

n字节

-2^n ~ 2^n-1

1 字节 = 8 比特,常说的字长32位,即是指32比特,4字节

其他:

  • 表达数的范围排序:char<short<int<float<double

  • 在内存中所占据大小:1-16个字节

  • 内存中的表达形式:二进制数(补码)、编码,浮点数运算用的是编码,而不是像整数直接加减

  • 浮点数可以是0,也可以无限接近0,但是断点,不衔接

(二)浮点数

1.科学计数法

2.表达数的范围

  • inf 表示超出范围的浮点数

  • nan 表示不存在的浮点数

printf("%f\n",12.00/0.00);//正无穷大,inf
printf("%f\n",-12.00/0.00);//负无穷大,-inf
printf("%f\n",0.00/0.00);//nan
printf("%d\n",0/0);//编译错误
/*浮点数把几类特殊情况存储起来*/

3.精度

  • 浮点数不能表示精度,不准确,只能在一定范围内相信它,或可用BCD数运算

  • 整数一定是准确的

举例:传统计算器保证精度就是用BCD码运算,整数运算

float a,b,c;
a = 1.1234f;//带小数点的字面常量默认double,若浮点要特别标注一下
b = 1.2345f;
c = a + b;//理论上是2.3579
if (c == 2.3579){
    printf(" a + b = c");
}else{
    printf(" a + b != c");
    printf("c = %f 或 %.10f\n", c,c); 
}
// 结果:!= ,c = 2.357900 或 2.3579001427(前7位有效,四舍五入2.357900),因为浮点数存储时四舍五入,不精准的
其他:带小数点的字面常量默认double,若浮点要特别标注一下!!f或F
  • 两个浮点数判断是否相等:直接判断可能是错的,要做差设置允许误差

// f1 == f2可能是错的
// fabs(f1 - f2) < 1e-10 做差与允许误差相比

4.浮点数的内部表达?

5.浮点数与整型傻傻分不清

  • 整数运算结果,自动以整数呈现

  • 浮点数参与运算,自动变成浮点数

//浮点数参与运算自动变型,与赋值给定义数据类型的变量的关系
//①输出运算式
int b=1;
printf("%f",b/2.0); //即输出1/2.0,浮点数参与运算结果为浮点数,所以%f,所以0.500000
printf("%d",b/2); //即输出1/2,运算结果为整型,所以%d,所以0
printf("%f",b/2); //即输出1/2,运算结果为整型,若%f,则0.000000

/*对于有浮点数参与的运算,如果变量类型已经被定义,数据类型还是不受影响的*/
//②输出变量:浮点数
int b=1;
double a = b/2; //顺序:先运算b/2整型结果为0,再赋值给浮点数a
printf("%f",a);//输出结果0.000000

//②输出变量:整型
int b=1;
int a = b/2.0;//顺序:先b/2.0浮点数运算结果为0.500000,再赋值给整型数据a
printf("%d",a);//输出结果0
printf("%f",a);//输出结果0.000000


//举例:
/*注意感受数据类型的变化,这里得是1.0,右边做完计算再赋值。
以i=2为例:
赋值时1/i自动结果是整数为0,赋给浮点数sum,表示为0.000000
赋值时1.0/i自动结果是浮点数0.500000,赋给浮点数,表示为0.500000
*/
int i = 2;
double sum = 0;
sum += 1.0/ i; //注意这里是1.0
printf("%f", sum);

/*总结:再次理解运算符优先级*/
double ff = -5E+10;

6.数据类型的选择

无特殊情况,用double

总结

  • 数据类型&占据字节数&占位符&表达数的范围

浮点型

float

4字节

scanf %f

printf %f %e %E

7

double

8字节

scanf %lf

printf %f %e %E

15

sum

printf

%f

%e (科学计数法,小写e)

%E(科学计数法,大写E)

%……f(可以指定输出小数点后几位,四舍五入的)

举例:%0.16f(小数点后16位)

关于%……f四舍五入的算法:

(三)逻辑

#include <stdbool.h> 

bool a = 6>5;
bool b = true;
b = 2;
printf(" b = %d\n",b);

※小结:数据类型相关表格

数据类型

sizeof() 字节数

格式化输入输出

(占位符)

数的范围

有效数字

char

1字节

int及以下:

%d(十进制)

%o(八进制)

%x (十六进制,字母小写)

%X(十六进制,字母大写)

-128 ~ 127

整型

short

2字节

-256 ~ 255

int(最常用,遇事不决选int)

4字节(取决于编译器、CPU,通常“1个字”)

long

4字节(取决于编译器、CPU,通常“1个字”)

long long:

%ld(十进制)

long long

8字节

unsigned

无符号数

%u

无符号long long %lu

sum

n字节

-2^n ~ 2^n-1

浮点型

float

4字节

scanf %f

printf %f %e %E

7

double(最常用,遇事不决选double)

8字节

scanf %lf

printf %f %e %E

15

sum

printf

%f

%e (科学计数法,小写e)

%E(科学计数法,大写E)

%……f(可以指定输出小数点后几位,四舍五入的)

举例:%0.16f(小数点后16位)

二、字符类型

1.简介

字符类型

sizeof() 字节数

格式化输入输出(占位符)

备注

char

1

scanf printf %c

char:一种数据类型-整数,也是一种字符类型,character。举例:单个字符'a' '1' ''

\……

2.格式化输入/输出

//格式化输出
//char - 数据类型
char a = 1;
printf("%d\n",a); //%d 1
//char - 字符类型
char b = '1';
printf("%d\n",a);//%d 49
printf("%c\n",a);//%d 输出了了个正方块

//格式化输出
char c; 
scanf("%c",&c); //输入字符变量
//char - 数据类型
printf("c = %d\n",c); // c = 49
//char - 字符类型
printf("c ='%c'\n",c);// c = '1'
// 若%c 输入 1,则d = 49,d ='1'

char d;
int i;
scanf("%d", &i); //输入整数变量
d = i;
//char - 数据类型
printf("d = %d\n", d); 
//char - 字符类型
printf("d ='%c'\n", d);
// 若%d 输入 49,则d = 49,d ='1'
// 若%d 输入 1,则d = 1,d =''

// ASCII码,%c 字符,%d 整数
if (49 == '1'){
    printf("ok");
}
// ok

3.混合输入——加不加空格

int a;char b;
scanf("%d %c",&a,&b);
printf("a = %d,b = %d,b = '%c'",a,b,b);//
//输入12 1 
// a = 12,b = 49,b = '1'
//输入12a
// a = 12,b = 97,b = 'a'
//输入12 a
// a = 12,b = 97,b = 'a'

int c;char d;
scanf("%d%c",&c,&d);
printf("c = %d,d = %d,d = '%c'",c,d,d);
//输入12 1
// c = 12,d = 32,d = ' '
//输入12a
// c = 12,d = 97,d = 'a'
//输入12 a
// c = 12,d = 32,d = ' ' 

//混合输入啥也没有就盖的少,有点啥就盖的多

4.字符计算

char a = 'a';
a++;
printf(" a = '%c\n'",a); // a = 'b'
/*字符与数字运算,新字符*/

int b = 'z'- 'a';
printf(" b = %d\n",b); // b = 25
/*字符与字符运算,相距数字*/

举例:字母大小写转换

// 首先了解:字母顺序排列,大写小写分开排列,顺序不相邻
// a + 'A' - 'a' 可以把小写转为大写
char a = 'a';
a += 'A' - 'a';
printf("a = '%c'",a); //a = 'A'

5.逃逸字符

printf("请你像我这样做\"不要! \""); //请你像我这样做"不要! "

逃逸字符:用来表达无法打印的控制字符或特殊字符,由\开头+不能直接打印的字符组成。

附表:逃逸字符

字符

意义

字符

意义

\b

回退一格(不是删除,是光标移动)

\"

双引号

\t

到下一个表格位

\'

单引号

\n

换行

\\

反斜杠\

\r

回车

// \b回退一格
printf("123\b\n456\n");
/*输出
123
456
*/
printf("123\bA\n456\n");
/*输出
12A
456
*/

// \t制表位统一
printf("123\t456");
printf("12\t45");
/*输出
123 456
12  45
*/

冷知识:回车和换行


三、类型转换

1.自动类型转换

运算符两边出现不一致的类型,自动转换成表示范围大的类型

2.强制类型转换

//(int)10.0
//(short)32
//注意小的类型的数据范围
//(short)324568
printf("%d",(short)32768); //-32768
printf("%d",32768); //32768

int i = 32768;
short s = short(i);
printf(" i = %d",i);//还是32768

注意:

  • 通常是较小的值,可以理解为是一种函数

  • 强制类型转换优先级高于四则运算

四、小结

怎么理解硬件对int所占字节数的约束作用?

  1. cpu与ram通过总线连接

  1. cpu内有寄存器reg,有32字长、64字长等

  1. 字长代表存储数据的位数即32bit、64bit,同时代表总线一次能传输的数据大小,即一个“字”

  1. int就是用来表示寄存器的

※总结:理解数据在计算机上的存储

//单个数

char a = 255;// %d -1
// char:1个字节,8bit
// 255(十)——1111 1111(二)--1111 1111(二,char)—— -1(十)
// 由于char 8bit,所以1111 1111中的1是符号位,根据上述信息,对应-1*/

int b = 255;// %d 255 
// int:4个字节,32bit
// 255(十)--1111 1111(二)——0000 0000 0000 0000 0000 0000 1111 1111(二,int)——255(十)
// 由于int 32bit,所以中的0是符号位,根据上述信息,对应255

unsigned char c = 255;// %d 255
//运算

// 255 + 1
char a = 255;// %d -1
/*十进制格式化输出 %d:255 --1111 1111--1111 1111(char,根据符号位判断,负数)--(对着那个1 0000 0000 - 1111 1111 = 0000 0001)-- -1*/
a += 1;// %d 1
/*十进制格式化输出 %d:1111 1111 + 0000 0001 = 1 0000 0000 (char,根据符号位判断,零)-- (对着那个1 0000 0000 - 1 0000 0000 = 0000 0000)-- 0*/

// -128 + 1
char b = -128;// %d -128
/*十进制格式化输出 %d:-128 --1000 0000 -- 1000 0000(char,负数,根据符号位判断)-- (对着那个1 0000 0000 - 1000 0000 = 1000 0000)-- -128*/
b += 1;// %d 1
/*十进制格式化输出 %d:1000 0000 + 0000 0001 = 1 0000 0001(char,根据符号位判断,正数) -- 1*/

// 127U + 1
unsigned char c = 127; // %d 127
/*127(无符号) -- 0111 1111(char,无符号)-- 127*/
c += 1;// 128
/*十进制格式化输出 %d:0111 1111(无符号)+ 0000 0001 = 1000 0000(无符号)--128*/

// 255U + 1
unsigned char d = 255; // %d 255
/*十进制格式化输出 %d:255 -- 1111 1111 -- 1111 1111(char,无符号) -- 255*/
d += 1;// 0
/*十进制格式化输出 %d:1111 1111(无符号) + 0000 0001 = 1 0000 0000(char,无符号)-- 0*/

// 0U -1
unsigned char e = 0; // %d 0
/*十进制格式化输出 %d:0 -- 0000 0000 -- 0000 0000(char,无符号数) —— 0*/
e -= 1;// %d 255
/*十进制格式化输出 %d:0000 0000(无符号数) - 0000 0001 = 0000 0000 + 1111 1111(有符号,负数-1的补码)= 1111 1111 —— 11111 1111(char,无符号数)—— 255*/
// 格式化输入输出
char a = -1;
/*十进制格式化输出 %d:: -1 ——(char,8位,有符号数,-1)—— 1111 1111*/
printf("a = %u", a);// 4,294,967,295 = 2^32 -1
/*非正常输出%u:*/

第六章 运算

一、算数运算

1.表达式

a = b +10

  • 算子:a、b、10

  • 运算符:=、+

2.优先级

  1. 优先级

  • 算数运算符-单目运算符 【*- 】【*+】

  • 算数运算符-四则运算【*】【/】>【+】【-】

  • 关系运算【>】【 >=】【 <】【 <=】>【==】【!=】{结果:0或1} 从左至右

  • 赋值运算【=】(结合关系特殊,自右向左)

其他:类型强制转换的优先级高于四则运算

  1. 其他(不用考虑优先级,一般)

  • 算数运算符-复合赋值【+=】【-=】

  • 算数运算符-递增递减【++】【--】 注意++a和a++ {结果:使得a+1或a-1}

附表:

怎么读表:注意优先级和结合关系

  • 单目运算的优先级最高,结合关系自右向左

  • 赋值也是一种运算符,结合关系自右向左

3.复合赋值与递归变化

//复合赋值
t += 12;//t = t +12;

//递归变化
t--;//t=t-1

注意:++ --可以放前,也可以放后

  • a++:①是表达式,a++还是a之前的值;②副作用是执行完该语句后,a的值为a+1;

  • ++a:①是表达式,++a是a之后的值;②副作用是执行完该语句,a的值为a+1。

二、逻辑运算

1.逻辑量

  • 逻辑运算是对逻辑量进行的运算,结果只有true = 1; false = 0;

  • 关系运算或逻辑运算的结果是逻辑量

运算符

优先级

描述

示例

结果

1

逻辑非 NOT

!a

如果a 是true,结果是false;

如果a是false,结果是true。

&&

2

逻辑与AND

a && b

如果a和b都是true,结果是true;

否则,结果是false。

||

3

逻辑或OR

a || b

如果a和b有一个是true,结果是true;

否则,结果是false。

2.优先级

举例:理解逻辑运算符的意思和优先级

  • age>20 && age<30 --> age ∈ (20,30)

  • index<0 || index>99 --> index ∈(-∞, 0)U(99,∞)

  • !age<12 -->!age: not age,如果age=0,!age=1;age=1,!age=0,都是小于12的,所以式子逻辑量为0

  • !done && (count>MAX) -->

举例:如何表达区间 x∈(4,6)

// 4 < x < 6,是无法被正确识别的,4 < x的结果是一个逻辑量(0或1)再与6相比,所以这个式子值为1
// 所以应该 4 < x && x < 6
if (4 < x && x < 6){
    ……
}

举例:判断是不是大写字母

if (x >= 'A' && x <= 'Z'){
    ……
}

3.组合关系

自左向右,如果左边的结果已经出来,能够决定结果,就不会做右边的计算了

  • 对于&&,左边是false就不做右边了

  • 对于 || ,左边是true就不做右边了

// 就不执行了
int a = -1;
if (a > 0 && a++ > 2) {
    printf("Yes\n");
}
printf("a = %d\n", a);

// 执行了
int a = 1;
if (a > 0 && a++ > 2) {
    printf("Yes\n");
}
printf("a = %d\n", a);

重要:不要把赋值,包括复合赋值写进表达式!!

其他:什么情况++这么高的优先级不会被执行
  • sizeof 静态运算符内不会执行

  • 逻辑运算 左边定结果,右边就不做了


三、条件运算

count = (count>20)?count-10:count+10;
//如果count>20,count=count-10;否则,count=count+10。

// 与以下表述表达内容一致
if (count>20){
    count -= 10;
}else{
    count += 10;
}

注意:条件运算符优先级只比赋值运算符高,比其他所有类型都低

举例:理解条件运算符的意思和优先级

  • m<n ? x : a+5;

如果 m>n,结果为x;m<n,结果为a+5;

  • a++ >= 1 && b-- >2 ? a :b;

左边:首先a++,然后a++ >= 1如果为1(true),看右边;如果0(false),&&式子为0;

右边:首先b--,然后b-->1如果为1(true),&&式子为1;否则为0;

如果&&为1,则结果为a;如果&&为0,则结果为b。

  • x = 3*a >5?5:20;

如果3*a,3*a>5,则逻辑量为1或x;

进一步,如果x和逻辑量相等,则结果为5;否则结果为20。

  • count = (count>20)? (count < 5)? count-10:count -5:(count<10)?count+10:count+5;

注意:
自右向左,每个?管着最近的:
类似的,自左向右,每个if管着最近的else

注意:不建议用嵌套的条件运算符,不易读


四、逗号运算

int a = 3+4,5+6; // %d b = 7
int b = (3+4,5+6); // %d b = 11
  • 逗号用来连接两个表达式,并以其右边的表达式的值作为它的结果。

  • 逗号的优先级是所有的运算符中最低的,所以它两边的表达式会先计算

  • 逗号的组合关系是自左向右,所以左边的表达式会先计算,而右边的表达式的值就留下来作为逗号运算的结果。

惟此应用:多加执行动作

int i,j;
for (i=0,j=10;i<j;i++,j--){
    a++;
    printf("i = %d,j = %d",i,j);
}

理解:没用到结果

※总结:运算符集合

优先级

运算符

类型

结合性

举例

1

()

从左到右

2

!

单目+ 单目-

++ --

单目运算符、

递归运算符

从右到左

!age < 12

3

* / %

四则运算符

从左到右

32/15 32%15

4

+ -

四则运算符

从左到右

5

< <= > >=

关系运算符

从左到右

6

== !=

关系运算符

从左到右

7

&&

逻辑运算符

从左到右

8

||

逻辑运算符

从左到右

9

? :

条件运算符

从右到左

count = (count>20)?count-10:count+10;

10

= += -= *= /=

赋值运算符

从右到左

11

,

逗号运算符

从左到右

for (i=0,j=10;i<j;i++,j--)

如何读表:

  • 单目运算符的优先级高于双目,!逻辑运算符的优先级就很高

  • 赋值运算符的优先级是最低的

  • 关系运算符的优先级高于逻辑运算符(除了!)

  • 条件运算符的优先级只比赋值运算符高,比其他都低

注意:运算符使用的总体思想是易读

  • 不要在表达式中赋值

  • 不要嵌套条件运算符

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值