C语言基础 6. 数据类型

C语言基础 6. 数据类型

6.1. 基础数据类型

  • C语言的变量:

    • 必须在使用前定义, 并且确定类型
  • C以后的语言向两个方向发展:

    • C++和Java, 它们更强调类型, 对类型的检查更严格, C语言有时候允许在不同的类型之间使用一些过渡的事情(自动类型转换)

    • JavaScript,Python,PHP不看重类型,甚至不需要事先定义

  • 类型安全:

    • 工业界有两种不同的观点

      • 支持明确类型的观点认为它有助于今早发现程序中的简单错误
      • 反对它的认为过于强调类型迫使程序员面对底层实现而非事务逻辑
    • 总的来说,早期语言和面向底层的语言强调类型,而越面向应用的语言越离底层远的语言,它会忽视类型

    • 而对于C语言来说,它需要类型,但是对类型的安全检查并不足够,它并不是表现为一个非常强的强类型语言

  • C语言的类型:

    • 四大类, 但是为啥会有五种呢, 我们这里把逻辑归类到整数当中, 等讲到逻辑的时候再来说

      • 整数: char, short, int, long, long long
      • 浮点数: float, double, long double
      • 逻辑: bool
      • 指针
      • 自定义类型
  • 类型有何不同:

    • 类型名称: int long double
    • 输入输出时的格式化: %d %ld %lf
    • 所表达的数的范围: char<short<int<float<double
    • 内存中所占的大小: 1字节到16字节
    • 内存中的表达形式: 二进制数(补码)(是对于整数),编码(是对于浮点数)
  • sizeof

    • 是一个运算符, 给出某个类型或变量在内存中所占据的字节数

      	int i;
      	sizeof(int)	== 4
      	sizeof(i) == 4
      
      • 4个字节(byte),1byte == 8比特位(bit), 4byte==32bit
    • 是一个静态运算符,它的结果在编译时刻就决定了,所以不要在sizeof的括号中做运算,这些运算是不会做的

      	int a = 0;
      	printf("%ld", sizeof(++a));	->	4
      	printf("%ld", a); -> 0
      
  • 计算机中的单位

单位描述
bit (比特位)1bit表示一个1或0, 计算机是将接收到的信息转化成能识别的二进制码
byte (字节)1byte=8bit
KB1KB=1024byte
MB1MB=1024KB
GB1GB=1024MB
TB1TB=1024GB
  • 程序中的错误:
    	a = 0;
    
    	错误信息: 未定义标识符 "a"
    	错误原因: 变量a未定义
    	解决办法: 先定义并确定类型再使用
    
  • 代码:
#include <stdio.h>

int main() {
	int a;
	a = 0;
	printf("sizeof(int) = %ld\n", sizeof(int));		//%ld是长整型,更精确
	printf("sizeof(a) = %ld\n", sizeof(a));

	printf("%d\n", sizeof(5.0));
	printf("%d\n", a);
	return 0;
}

6.2. 除了Int外的数据类型

  • 除了int,还有多少整数类型

    • sizeof(long) -> 4 在32位的操作系统上

    • sizeof(long) -> 8 在64位的操作系统上

    • int和long所占的字节数与所在的计算机有关,也与所用的编译器有关

    • int是要表达计算机的字长,也就是寄存器的大小

      char 1
      short 2
      int 4
      long 4或8
      long long 8

  • 字长:

    • 计算机中有个东西叫做CPU,还会有另一个东西叫做内存RAM,在CPU和RAM中间有一个东西连接着它们两个, 叫做总线, 在CPU中外有一个东西叫做寄存器,让我们在说一个计算机的字长时,我们指的是计算机的寄存器是有多宽, 也就是寄存器是多少bit,当寄存器是32bit, 寄存器可以表达32bit的数据,同时我们在CPU和RAM之间传递数据时, 每一次传递32bit. 当我要去RAM中取数据到CPU里面时, 每一次会取32bit的数据,寄存器会表达32bit,这里的32就叫做字长.
      在这里插入图片描述
  • 代码:

#include <stdio.h>

int main() {

	printf("sizeof(char) = %ld\n", sizeof(char));	//1
	printf("sizeof(short) = %ld\n", sizeof(short));	//2
	printf("sizeof(int) = %d\n", sizeof(int));	//4
	printf("sizeof(long) = %ld\n", sizeof(long));	//4		
	printf("sizeof(long long) = %ld\n", sizeof(long long));	//8
	return 0;
}

6.3. Int的内部表达

  • 疑问:

    • 这一节还不是太懂
  • 整数的内部表达:

    • 我们现在知道一个int表达的是一个寄存器的大小,那么整数在计算机的内部是如何表达的呢

    • 计算机内部一切都是二进制,不管是整数还是浮点数(虽然是编码,但是计算机可以通过一定的方式)最终都是二进制,只是我们以什么样的方式来看待它,这是很重要的,而不是表明它在内部是如何表达的

      • 比如:
        18 -> 00010010 18是用00010010这样的一个二进制来表达的
        0 -> 00000000
        -18 -> ?
  • 如何表示负数:

    • 十进制用"-"表示负数

    • 做运算时:
      12+(-18)=12-18
      12-(-18)=12+18
      12*(-18)=-(12*18)
      12/(-18)=-(12/18)

      • 做运算时,总是把这个负号抛掉,把它当作一个正数来做运算,然后在运算的结果上面再去设法处理这个
    • 负号的问题,这是十进制,那么二进制怎么做呢?

    • 二进制负数

      • 1byte可以表达的数: 00000000-11111111(0-255)

      • 补码:

        • 考虑-1,让-1+1=0,怎么做?
          0 -> 00000000
          1 -> 00000001
          11111111 + 00000001 -> 100000000//计算机内部,如果这个数是8bit,那么多出来的那一位就会被丢掉,所以这个结果正好是000000000

        • 因为0-1 -> -1,所以-1 -> 11111111
          (1)00000000 - 00000001 -> 11111111
          11111111被当作纯二进制看待时,是255,被当作补码看待时是-1

        • 同理, 对于-a, 其补码就是0-a, 实际是2^n-a, n是这种类型的位数

        • 补码的意义就是拿补码和原码可以加出一个溢出的"0", 所以为什么要在计算机中使用补码呢, 如果你有一个补码, 你用补码来表示这个-1, 那么当你在做加法时, 你不需要根据条件去变换, 把加变成减, 你直接拿它去做普通的二进制加法, 你就会得到你想要的结果

          在这里插入图片描述

      • 计算机在底层存储数据时, 一律存储的是二进制的补码形式( 补码形式效率最高 ), 打印的是原码

      • 二进制有 : 原码, 反码, 补码

      • 对于一个正数来说 : 二进制原码, 反码, 补码都相同

      • 对于一个负数来说 :

        • char b = -1;
        • 对应的原码 : 10000001
        • 反码 : 11111110 ( 符号位不变, 其他位取反 )
        • 补码 : 11111111 ( 反码+1 )

6.4. Int的范围

  • 疑问:

    • 这一节还不是太懂
  • 数的范围:

    • 对于一个字节(8位)(也就是整数当中的char)来说,可以表达的是:
      00000000-11111111

      • 其中:
        • 00000000 -> 0
          11111111~10000000 -> -1~-128
          00000001~01111111 -> 1~127

        • 11111111

          • 把它看作是一个二进制数,它就是原码形式对应的十进制255
          • 把它看作是一个整数,它就是补码形式对应的十进制-1
        • 所以以什么样的方式来看待它,这是很重要的

        • 但是这只是针对的一个字节的整数,也就是char,如果换成别的类型的整数呢,它就不是-1了

        • char c = 255; 11111111

        • int i = 255; 00000000 00000000 00000000 11111111他前面还有很多位可以填充为1,所以是正数

        • printf(“c = %d, i = %d”, c, i);//c = -1, i = 255

    	char: 1byte: -128~127
    	short: 2byte: -32768~32767
    	int: 48byte,取决于CPU : -2^(32-1)~2^(32-1)-1
    	long: 48byte,取决于CPU
    	long long: 8byte
    		-2^(n-1)~2^(n-1)-1,n为类型位数
    
  • unsigned:

    • 如果我们想要将一个数当作纯二进制数,也就是说这个数不以补码的形式来表示负数,这个数没有负数部分,那么我们需要在那个类型的前面再加上一个关键字unsigned,但是有一个副作用就是这个类型所能表达的数在正数部分会扩大,相当于是原来正数部分的两倍

    • unsigned char a = 255U; 可以在后面加u或U表示自己是unsigned

    • 如果想表示自己是long,可以在后面加上l或L

    • 初衷:

      • 它的设计并非扩展数能表达的范围,而是为了做纯二进制运算,主要是为了移位.
  • 整数越界:

    • 整数是以纯二进制方式进行计算的
      11111111 + 1 -> 100000000 -> 0
      01111111 + 1 -> 10000000 -> -128
      10000000 - 1 -> 01111111 -> 127
      在这里插入图片描述
      在这里插入图片描述
      	char b = 127;
      	b += 1;
      	printf("%d\n", b);//-128
      
      	char d = -128;
      	d -= 1;
      	printf("%d\n", d);//127
      
      	unsigned char e = 127;
      	e += 1;
      	printf("%d\n", e);//128
      
      	unsigned char f = 255;
      	f += 1;
      	printf("%d\n", f);//0
      
  • 代码:

#include <stdio.h>

int main() {
	char c = 255;
	int i = 255;
	printf("c = %d, i = %d\n", c, i);//c = -1, i = 255

	unsigned char a = 255;
	printf("a = %d\n", a);

	char b = 127;
	b += 1;
	printf("%d\n", b);//-128

	char d = -128;
	d -= 1;
	printf("%d\n", d);//127

	unsigned char e = 127;
	e += 1;
	printf("%d\n", e);//128

	unsigned char f = 255;
	f += 1;
	printf("%d\n", f);//0
	return 0;
}

6.5. Int的格式化

  • 疑问:

    • 这一节还不是太懂
  • 整数的输入输出:

    • 只有两种形式: int和long long, 也就是说char和short也可以采用int的方式输入输出
      %d: int
      %u: unsigned
      %ld: long long
      %lu: unsigned long long

    • char c = -1;
      int i = -1;
      printf(“c = %u, i = %u\n”, c, i);//c = 4294967295, i = 4294967295

      • 这个数是unsigned int所能表达的最大的数,因为-1表示全1,为什么这个不是一个字节呢,当我们把所有小于int的变量传给printf时,编译器会把这些变量转换为int传进去,因为是有符号的,所以传进去的时候,当然这个东西也被扩展到所有的位都是1,最后作为unsigned的结果就是这个结果
      • 还是那句话,这和它在计算机内部是什么没有关系,这取决于你用正确的方式把它格式化,也就是这里的%u
  • 八进制和十六进制:

    • 以0开始的数字是八进制
    • 以0x开始的数字是十六进制
    • 无论是八进制还是十六进制,编译器都会将其转成二进制是得计算机能够理解
    • %o: 八进制
    • %x: 十六进制
    • 八进制和十六进制只是如何把数字表达为字符串,与内部如何表达数字无关
    • 十六进制很适合表达二进制数据,因为4位二进制正好是一个十六进制位
    • 八进制的一位数字正好表达3位二进制, 因为早期计算机的字长是12的倍数, 而非8
  • 进制转换

    • 二, 八, 十六进制 转 十进制 :
      在这里插入图片描述
    • 十进制 转 二, 八, 十六进制 :
      在这里插入图片描述
  • 代码:

#include <stdio.h>

int main() {
	char c = 012;
	int i = 0x12;
	printf("c = %d, i = %d\n", c, i);//c = 10, i = 18	
	return 0;
}

6.6. 选择Int

  • 选择整数类型:
    • C语言有那么多复杂的事情, 是因为早期的语言需要准确的表达计算机里头的东西, 比如, 内存, 寄存器,接口
    • 没有特殊需要, 就选择int
    • 现在的CPU的字长普遍是32位或64位, 一次内存读写就是一个int, 一次计算也是一个int, 选择更短的类型不会更快, 甚至可能更慢
    • 现代的编译器一般会设计内存对齐, 所以更短的类型实际在内存中有可能也占据一个int的大小(虽然sizeof告诉你更小)
    • unsigned与否只是输出的不同, 内部计算是一样的

6.7. 浮点类型

  • 浮点类型:

    	类型	字长	范围		有效数字
    	float	32		大概10^38		7
    	double	64		大概10^308		15
    
  • 输入输出:

    	类型	scanf	printf
    	float	%f		%f, %e
    	double	%lf		%f, %e(以科学计数法输出)
    
  • 科学计数法:
    -5.67E+16

    • 可选的+或-

    • 小数点也是可选的

    • 可以用e或E

    • 符号可以是-或+也可以省略(表+)

    • 整个词不能有空格

    • 假如值很大, 比如0.000000001有非常多的小数, 使用科学计数法就可以帮你直接帮你计算多少位小数

  • 输出精度:

    • 在%和f之间加上.n可以指定输出小数点后几位, 这样的输出是做四舍五入的

      printf(“%.3f\n”, -0.0049);// -0.005
      printf(“%.30f\n”, -0.0049);// -0.004899999999999999841793218991 这个结果是离散在0.0049附近的
      printf(“%.3f\n”, -0.00049); //-0.000

  • 代码:

#include <stdio.h>

int main() {
	/*double d;
	float f;
	scanf("%lf %f", &d, &f);
	printf("%e %f\n", d, f);*/

	printf("%.3f\n", -0.0049);// -0.005
	printf("%.30f\n", -0.0049);// -0.004899999999999999841793218991
	printf("%.3f\n", -0.00049); //-0.000

	//printf("sizeof(float) = %ld\n", sizeof(float));		//4
	//printf("sizeof(double) = %ld\n", sizeof(double));	//8
	//printf("sizeof(long double) = %ld\n", sizeof(long double));		//8
	return 0;
}

6.8. 浮点类型的范围

  • 超过范围的浮点数:

    • printf输出inf表示超过范围的浮点数: ±∞
    • printf输出nan表示不存在的浮点数
    	double zero = 0.0;
    	printf("%f\n", 12.0 /zero ); //inf
    	printf("%f\n", -12.0 / zero);//- inf
    	printf("%f\n", 0.0 / zero);//- nan(ind)
    
    • 无穷大可以用浮点数表达, 但是不能用整数来表达
  • 浮点运算的精度:

    • 浮点运算是没有精度的, 所以两个浮点数直接判断是否相等可能会失败
      f1==f2可能失败
    	float a, b, c;
    	a = 1.345f;	//带小数点的字面量是double而非float, float需要用f或F后缀来表明身份
    	b = 1.123f;
    	c = a + b;
    	if (c == 2.468) {
    		printf("相等\n");
    	}
    	else
    	{
    		printf("不相等! c=%.10f, 或%f\n", c, c);//不相等! c=2.4679999352, 或2.468000
    	}
    
  • 浮点数的内部表达:

    • 浮点数的内部是一种编码形式, 浮点数在计算时是由专用的硬件部件实现的, 计算double和float的部件是一样的
  • 选择浮点类型:

    • 如果没有特殊需要, 只是用double
    • 现代CPU能直接对double做硬件运算, 性能不会比float差, 在64位的机器上, 数据存储的速度也不比float慢
  • 程序中的错误:

    	printf("%f\n", 12.0 / 0.0 );
    	
    	错误信息: 被零除或对零求模
    	错误原因: 对零进行除法运算
    	解决办法: 把零赋值给一个变量, 让这个变量代替零做运算
    
  • 代码:

#include <stdio.h>

int main() {
	//double zero = 0.0;
	//printf("%f\n", 12.0 /zero ); //inf
	//printf("%f\n", -12.0 / zero);//- inf
	//printf("%f\n", 0.0 / zero);//- nan(ind)

	//int ling = 0;
	//printf("%d", 12 / ling);//错误
	
	float a, b, c;
	a = 1.345f;	//带小数点的字面量是double而非float, float需要用f或F后缀来表明身份
	b = 1.123f;
	c = a + b;
	
	if (c == 2.468) {
		printf("相等\n");
	}
	else
	{
		printf("不相等! c=%.10f, 或%f\n", c, c);//不相等! c=2.4679999352, 或2.468000
	}
	return 0;
}

6.9. 字符类型

  • 字符(character)类型:

    • char是一种整数, 也是一种特殊的类型: 字符, 这是因为:
      • 用单引号表示的字符字面量: ‘a’, ‘1’
      • ''也是一个字符
      • printf和scanf里面用%c来输入输出字符
  • 字符的输入输出:

    • 如何输入’1’这个字符给char c?
      	char c;
      	scanf("%c", &c);	// 1
      	printf("c = %d\n", c);// 49
      	printf("c = '%c'\n", c); // '1'
      
      	int i;
      	char c;
      	scanf("%d", &i);//读进去的是一个整数
      	c = i;	//整数赋给了c
      	printf("c = %d\n", c);//c作为整数形式输出为49
      	printf("c = '%c'\n", c);//c作为字符形式输出为'1'
      
    • ‘1’的ASCII编码是49, 所以当c==49时, 它代表’1’
      if (49 == ‘1’) {
      printf(“相等\n”);//相等
      }
  • 混合输入:

    	int i;
    	char c;
    	scanf("%d %c", &i, &c);//%d要把整数以及后面的空格都读掉, 后面的给%c
    	scanf("%d%c", &i, &c);//%d只读到整数结束为止, 后面的给%c
    	printf("i = %d, c = %d, c = '%c'\n", i, c, c);
    
  • 字符计算:

    • 一个字符加一个数字得到ASCII码表中那个数之后的字符
      char c = ‘A’;
      c++;
      printf(“%c\n”, c);//B

    • 两个字符的减, 得到它们在表中的距离
      int i = ‘Z’ - ‘A’;
      printf(“%d\n”, i);//25

  • 大小写转换:

    • 字母在ASCII码表中是顺序排列的, ‘a’到’z’, ‘A’到’Z’

    • 大写字母和小写字母是分开排列的, 并不在一起

    • ‘a’-'A’可以得到两段之间的距离

    • 大小写字母转换:
      printf(“%d\n”, ‘a’ - ‘A’);//32
      printf(“%d\n”, ‘A’ - ‘a’);//-32
      printf(“%c\n”, ‘B’ + ‘a’ - ‘A’);//b
      printf(“%c\n”, ‘b’ + ‘A’ - ‘a’);//B

  • 代码:

#include <stdio.h>

int main() {

	//char c;
	//char d;
	//c = 1;
	//d = '1';
	//if (c == d) {
	//	printf("相等\n");
	//}
	//else {
	//	printf("不相等\n");	//不相等
	//}
	//printf("c = %d\n", c);//c=1
	//printf("d = %d\n", d);//d=49

	//int i;
	//char c;
	//scanf("%d", &i);//读进去的是一个整数
	//c = i;	//整数赋给了c
	//printf("c = %d\n", c);//c作为整数形式输出为49
	//printf("c = '%c'\n", c);//c作为字符形式输出为'1'

	/*if (49 == '1') {
		printf("相等\n");
	}*/
	
	//int i;
	//char c;
	scanf("%d %c", &i, &c);
	//scanf("%d%c", &i, &c);
	//printf("i = %d, c = %d, c = '%c'\n", i, c, c);
	
	//char c = 'A';
	//c++;
	//printf("%c\n", c);//B
	//int i = 'Z' - 'A';
	//printf("%d\n", i);//25

	printf("%d\n", 'a' - 'A');//32
	printf("%d\n", 'A' - 'a');//-32
	printf("%c\n", 'B' + 'a' - 'A');//b
	printf("%c\n", 'b' + 'A' - 'a');//B
	return 0;
}

6.10. 逃逸字符

  • 逃逸字符:
    • 也叫做转义字符, 用来表达无法打印出来的控制字符或特殊字符, 他由一个反斜杠""开头, 后面跟上另一个字符, 这个两个字符合起来, 组成了一个字符.
    	字符	意义
    	\b		回退一格, 如果\b后面有东西, 则把后面要覆盖前面一格, 如果\b后面没有东西了, 那么不覆盖
    	\t		制表符tab
    	\n		换行, 在早期的打字机上面回车和换行是两个动作, 但是在此shell当中\n就代替了这两个动作
    	\r		回车
    	\"		双引号
    	\'		单引号
    	\\		反斜杠本身
    
  • 调试控制台:
    • 它是一个程序, 叫做shell, 它在程序员和计算机之间做了一个桥梁的作用, 相当于一个翻译官的角色, 程序员通过键盘输入代码, shell来执行我们的代码, 来传递给计算机底层, 计算机接收到之后, 会将结果给shell, shell对这个结果加工处理, 最终变成了程序员能看懂的东西.

    • 也就是说, 不同的编译器有不同的shell, 不同的shell执行同一段代码会有不同的结果, 这个是毋庸置疑的, 比如说\b在不同的shell当中呈现出的结果是不一样的

    • printf(“123\b\n456\n”);

      • 123
        456
      • 这是当前的shell的运行结果, 而在另一个shell中, 123后面还有个看不懂是什么玩意儿的东西
  • 代码:
#include <stdio.h>

int main() {
	printf("123\b\n456\n");//123换行456
	printf("123\bA\n456\n");//12A换行456
	return 0;
}

6.11. 类型转换

  • 自动类型转换:

    • 当运算符的两边出现不一致的类型时, 会自动转换成较大(也就是表达的数的范围更大)的类型

      • char -> short -> int -> long -> long long
      • int -> float -> double
    • 对于printf, 任何小于int的类型会被转换成int, float会被转换成double, 但是scanf不会, 要输入short, 需要%hd

  • 强制类型转换:

    • 要把一个类型强制转换成另一个类型(通常是较小的类型)

    • 格式: (类型)值

    • 比如:

      • (int)10.2
      • (short)32
    • 注意这时候的安全性, 小的变量不总能表达大的量

      • (short)32768
      • printf(“%d\n”, (short)32768);//-32768 因为short的能表示的最大整数为32767, 现在已经超出了所能承受的范围
    • 它只是从那个变量计算出一个新的类型的值, 它并不改变那个变量, 无论是值还是类型都不改变

      • int i = 32768;
      • short s = (short)i;
      • printf(“%d\n”, i); //32768
  • 优先级:

    • 强制类型转换的优先级是高于四则运算的
      	double a = 1.0;
      	double b = 2.0;
      	int i = (int)(a / b);//要想先算四则运算, 可以加上()
      	printf("%d", i);
      
  • 代码:

#include <stdio.h>

int main() {
	//int i = 32768;
	//short s = (short)i;
	//printf("%d\n", (int)10.2);//10
	//printf("%d\n", i);//32768
	//printf("%d\n", s);//-32768

	double a = 1.0;
	double b = 2.0;
	int i = (int)(a / b);
	printf("%d", i);
	return 0;
}

6.12. 逻辑类型

  • bool:

    • 布尔类型

    • #include <stdbool.h>, 才能使用bool和true, false

  • 代码:

#include <stdio.h>
#include <stdbool.h>

int main() {
	bool b = 6 > 5;
	bool t = true;
	printf("%d\n", b);//1
	printf("%d\n", t);//1
	return 0;
}

6.13. 逻辑计算

  • 逻辑运算:

    • 逻辑运算是对逻辑量进行的运算, 结果只有0或1

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

    	运算符	描述	实例	结果
    
    	!		逻辑非	!a		如果a是true(false), 结果就是false(true)
    	&&		逻辑与	a && b	如果a和b都是true, 结果就是true, 否则就是false
    	||		逻辑或	a || b	如果a和b有一个是true, 结果就是true, 两个都是false, 结果才为false
    
  • 区间:

    • 如果要表达数学中的区间, 比如: x∈(4,6)或x∈[4,6], 应该如何写C的表达式

      • 开区间: x > 4 && x < 6
      • 闭区间: x >= 4 && x <= 6
    • 如何判断一个字符c是否为大写字母?

      • c >= ‘A’ && c <= ‘Z’
  • 理解一下:

    • age > 20 && age <30 : age∈(20,30)
    • index < 0 || index > 99 : index∈(-∞,0]∪[99,+∞)
    • !age < 20 : age∈[20,+∞)
    • 虽然逻辑运算符的优先级低于比较运算符, 但是还有一条规则是, 单目运算符的优先级要高于双目运算符,而逻辑非就是单目运算符, 所以应该先算!age, 再算< 20
  • 优先级:

    • ! > && > ||
      • !done && (count > MAX)
    	优先级	运算符		结合性
    
    	1		()			从左往右
    	2		! + - ++ --	从右向左(单目的+-)
    	3		* / %		从左向右
    	4		+ -			从左向右
    	5		< <= > >=	从左向右
    	6		== !=		从左向右
    	7		&&			从左向右
    	8		||			从左向右
    	9	= += -= *= /= %=从右向左
    
    • 赋值运算是最低的, 逻辑运算比比较运算低, 往上是四则运算, 再往上是单目运算符, 最高的是()
  • 短路:

    • 逻辑运算是自左向右进行的, 如果左边的结果已经能够决定结果了, 就不会做右边的计算了

    • 比如:

      • a==6 && b++

      • a==6 && b++ // 当a!=6时, b++就不会执行, 即短路

      • 对于&&, 左边是false时就不做右边了; 对于||, 左边是true时就不做右边了

      • 不要把赋值, 包括复合赋值组合进逻辑运算表达式

  • 代码:

#include <stdio.h>

int main() {
	if ('C' >= 'A' && 'C' <= 'Z') {
		printf("是");
	}
	//int i, j, k;
	//if (i != j) {
	//	if (i != k) {
	//		if (j != k) {
	//			//第一种
	//		}
	//	}
	//}
	//if (i != j && i != k && j != k) {
	//	//第二种
	//}
	// 有了逻辑运算符之后, 我们就可以将第一种写成第二种形式, 看起来更简洁

	int a = 5;
	int b = 1;
	if (a > 6 && b++) {	//b++会短路
		printf("ok");
	}
	printf("%d %d", a, b);//5 1
	return 0;
}

6.14. 条件和逗号计算

  • 条件运算符:

    count = (count > 20) ? count - 10 : count + 10;
    			条件	?	条件满足时的值 : 条件不满足时的值
    
    • 相当于:
      	if(count > 20){
      		count -= 10;
      	}else {
      		count += 10;
      	}
      
  • 优先级:

    • 条件运算符的优先级高于赋值运算符, 但是低于其他运算符
  • 嵌套条件表达式:

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

    • 不建议使用嵌套的条件表达式, 太过于复杂, 可读性差

  • 逗号表达式:

    • 逗号用来连接两个表达式, 并以其右边的表达式的值作为它的结果

    • 优先级: 逗号的优先级是所有的运算符中最低的, 比赋值运算符还低

      	int i;
      	i = 3 + 4, 5 + 6;
      	printf("i = %d", i);//i = 7
      
      	i = (3 + 4, 5 + 6);//i = 11
      
    • 在for中使用:
      for(i = 0, j = 10; i < j; i++, j–)
      目前来说, 逗号表达式就只有这一个用处, 就是在for当中使用

  • 代码:

#include <stdio.h>

int main() {
	/*int count = 40;
	count = (count > 20) ? count - 10 : count + 10;
	printf("%d", count);*/

	/*int i;
	i = 3 + 4, 5 + 6;
	printf("i = %d", i);*/

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

6.15. PAT

  • 06-0. 混合类型数据格式化输入(5)

    • 本题要求编写程序,顺序读入浮点数1、整数、字符、浮点数2,再按照字符、整数、浮点数1、浮点数2的顺序输出。

    • 输入格式:
      输入在一行中顺序给出浮点数1、整数、字符、浮点数2,其间以1个空格分隔。

    • 输出格式:
      在一行中按照字符、整数、浮点数1、浮点数2的顺序输出,其中浮点数保留小数点后2位。

    • 输入样例:
      2.12 88 c 4.7

    • 输出样例:
      c 88 2.12 4.70

    • 分析:

      • 1.输入
      • 2.输出并保留两位小数
    #include <stdio.h>
    
    int main() {
    	//输入
    	double num1, num2;
    	int i;
    	char c;
    	scanf("%lf %d %c %lf", &num1, &i, &c, &num2);
    	//输出
    	printf("%c %d %.2f %.2f", c, i, num1, num2);
    	return 0;
    }
    
  • 06-1. 简单计算器(20)

    • 疑问:

      • 如何接收这些不固定的四则运算符, 这一题不会

      • 已解决, 刷两遍错题就行了

    • 模拟简单运算器的工作。假设计算器只能进行加减乘除运算,运算数和结果都是整数,4种运算符的优先级相同,按从左到右的顺序计算。

    • 输入格式:
      输入在一行中给出一个四则运算算式,没有空格,且至少有一个操作数。遇等号”=”说明输入结束。

    • 输出格式:
      在一行中输出算式的运算结果,或者如果除法分母为0或有非法运算符,则输出错误信息“ERROR”。

    • 输入样例:
      1+2*10-10/2=

    • 输出样例:
      10

    #include <stdio.h>
    
    int main() {
    	char c = 'a';
    	int flag = 1;
    	int ret;
    	scanf("%d", &ret);
    	while (c != '=') {
    		scanf("%c", &c);
    		if (c == '=') {
    			break;
    		}
    		int i;
    		scanf("%d", &i);
    		if (c == '+') {
    			ret += i;
    		}
    		else if (c == '-') {
    			ret -= i;
    		}
    		else if (c == '*') {
    			ret *= i;
    		}
    		else if (c == '/') {
    			if (i != 0) {
    				ret /= i;
    			}
    			else {
    				flag = 0;
    			}
    		}
    		else {
    			flag = 0;
    		}
    	}
    	if (flag == 0) {
    		printf("ERROR\n");
    	}
    	else {
    		printf("%d", ret);
    	}
    	return 0;
    }
    
  • 06-2. 字符串字母大小写转换(10)

    • 输入一个以#结束的字符串,本题要求将小写字母全部转换成大写字母,把大写字母全部转换成小写字母,其它字符不变。

    • 输入格式:
      输入在一行中给出一个长度不超过40的、以#结束的非空字符串。

    • 输出格式:
      在一行中按照要求输出转换后的字符串。

    • 输入样例:
      Hello World! 123#

    • 输出样例:
      hELLO wORLD! 123

    • 分析:

      • 1.循环,每次接收一个字符
      • 2.判断条件!=‘#’
      • 3.判断小写字母并转大写
      • 4.判断大写字母并转小写
      • 5.其他的不用管,直接输出
    #include <stdio.h>
    
    int main() {
    	//字符变量
    	char c = 'a';
    	//循环每次接收一个字符
    	//判断条件
    	while (c != '#') {
    		scanf("%c", &c);
    		//判断小写
    		if (c >= 'a' && c <= 'z') {
    			//小写转换大写
    			c += 'A' - 'a';
    		}
    		//判断大写
    		else if (c >= 'A' && c <= 'Z') {
    			//大写转换小写
    			c += 'a' - 'A';
    		}
    		//转换完成之后, 其他的不用动, 输出
    		printf("%c", c);
    	}
    	return 0;
    }
    
  • 06-3. 单词长度(15)

    • 你的程序要读入一行文本,其中以空格分隔为若干个单词,以‘.’结束。你要输出每个单词的长度。这里的单词与语言无关,可以包括各种符号,比如“it’s”算一个单词,长度为4。注意,行中可能出现连续的空格;最后的‘.’不计算在内。

    • 输入格式:
      输入在一行中给出一行文本,以‘.’结束。

    • 提示:用scanf(“%c”,…);来读入一个字符,直到读到‘.’为止。

    • 输出格式:
      在一行中输出这行文本对应的单词的长度,每个长度之间以空格隔开,行末没有最后的空格。

    • 输入样例:
      It’s great to see you here.

    • 输出样例:
      4 5 2 3 3 4

    • 分析:

      • 1.循环读入每个字符
      • 2.判断条件!=‘.’
      • 3.每次循环count++,遇到空格,把count输出
    #include <stdio.h>
    
    int main() {
    	//字符变量
    	char c = 'a';
    	//计数变量
    	int count = 0;
    	//循环读入每个字符
    	//判断条件
    	while (c != '.') {	//It's great to see you here.
    		scanf("%c", &c);	//It's great to see you here
    		if (c == ' ') {		//12340123450120123012301234
    			printf("%d ", count);
    			count = -1;
    		}
    		count++;
    	}
    	printf("%d", count - 1);
    	return 0;
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值