程序设计与算法 | (3) 输入输出与运算符、表达式

本专栏主要基于北大郭炜老师的程序设计与算法系列课程进行整理,包括课程笔记和OJ作业。该系列课程有三部分: (一) C语言程序设计;(二) 算法基础;(三) C++面向对象程序设计

(一) C语言程序设计 课程链接

1. 输入输出进阶

输入输出控制符

在printf和scanf中可以使用以"%"开头的控制符,指明要输入或输出的数据的类型以及格式。

int n = 3;
printf("I want to buy %d books for %f dollars",3,4.5); //也可以用%lf
double f;
scanf("%d%f",&n,&f); //也可以用%lf

程序设计与算法 | (3) 输入输出与运算符、表达式_第1张图片

用scanf读入不同类型的变量

用scanf可以一次读入多个类型不同的变量,只要输入的各项之间用空格分隔即可。

#include  
#include  
using namespace std; 
int main()
{
int n; char c; float f;
scanf("%d%c%f",&n,&c,&f); //依次输入一个整数,一个字符, 再一个小数,则它们会被分别放入n,c,m; &n代表“取n的地址” ; %c表示等待输入一个字符;%f表示等待输入一个float小数
printf("%d %c %f",n,c,f); //%f用于输出double或float类型的值,默认保留小数点后面6位
return 0;
}

在这里插入图片描述

输入字符类型数据时(%c),不会跳过空格(空格也会被当作字符读入),输入其他类型的数据时,会跳过空格。

#include  
#include  
using namespace std; 
int main()
{
	int n; char c; float f;
	scanf("%d%c%f",&n,&c,&f);
	printf("%d %c %f",n,c,f);
	return 0;
}

在这里插入图片描述
%c不会跳过空格,此时他会读入一个空格到c中,再读入f时,对应输入是’k’,导致出错。

用scanf跳过输入中的字符

如果在输入中有scanf中出现的非控制字符(可以自行设置格式字符串),则这些字符会被跳过。

#include  
#include  
using namespace std; 
int main()
{
	int n,m; char c; float f; 
	scanf("%d %c,%f:%d",&n,&c,&f,&m); //输入中对应位置的 空格 , :会被跳过
	printf("%d,%c,%f,%d",n,c,f,m); 
	return 0;
}

在这里插入图片描述

控制printf 输出整数的宽度

在这里插入图片描述

int n = 123;
printf("%05d,%5d,%5d,%05d",n,n,123456,123456);

在这里插入图片描述

控制printf 输出浮点数的精度

在这里插入图片描述

float a = 123.45;
double b = 22.37362723; 
printf("%.5f %.2f %.12f",12.3,a,b);

在这里插入图片描述

尽量使用double
  • double 精度高于float,所以一般尽量使用double!
  • double类型的变量用 %lf 输入! float和double输出都可以用%f
    程序设计与算法 | (3) 输入输出与运算符、表达式_第2张图片
格式控制符%x和%u
  • %x: 以十六进制形式读入或输出整数
  • %u: 以无符号整数形式输出整数
printf("%x,%d,%u",0xffffffff, 0xffffffff,0xffffffff);

在这里插入图片描述

int n;
scanf("%x",&n); //读入一个十六进制数
printf("%d",n); //输出对应的十进制数

程序设计与算法 | (3) 输入输出与运算符、表达式_第3张图片

用C++的cout进行输出
#include  
using namespace std; 
int main() 
{
int n=5;
double f = 3.9;
char c = 'a';
cout << "n=" << n << ",f=" << f << endl; //endl换行 
cout << 123 << ", c=" << c;
return 0;
}

在这里插入图片描述

用C++的cin进行输入
#include  
using namespace std; 
int main() 
{
	int n1,n2;
	double f;
	char c;
	cin >> n1 >> n2 >> c >> f;
	cout << n1 << "," << n2 << "," << c << "," << f; 
	return 0;
}

程序设计与算法 | (3) 输入输出与运算符、表达式_第4张图片
cin会跳过空格,对于所有的类型包括字符类型,此时在输入的10,k之间加一个空格的话,该空格会被跳过,字符类型变量c读入的仍是k。

用cin读入所有输入的字符,包括空格,回车
#include  
using namespace std; 
int main()
{
	int c;
	while((c = cin.get()) != EOF) {
    	cout << (char)c ;
    }
	return 0;
} 

cin.get()会读入所有输入字符,不会跳过空格和回车等。他的返回值是int,即读入字符的ASCII码,由于字符是一个字节,而int是4个字节,因此返回的int类型值始终>=0(最高位/符号位是0)。当读取完毕(没有数据可读时),返回EOF(-1),注意EOF不是输入数据结束的标志,输入数据结尾没有这个符号。 由于返回的是ASCII码,输出时需要用(char)c转换为字符。

用scanf读入所有输入的字符,包括空格,回车
#include  
#include  
using namespace std; 
int main()
{
	char c;
	while(scanf("%c",&c) != EOF) { 
		printf("%c",c);
	}
	return 0;
}

由于scanf中的字符类型%c,在输入时,不会跳过空格,因此可以读入所有输入的字符,包括空格,回车。没有数据可读时,返回EOF。

用cin,cout和scanf,printf
  • cin,cout 速度比scanf,printf慢,输入输出数据量大时用后者;小的时候用前者,比较方便
  • 一个程序里面不要同时用cin和scanf,不要同时用cout和printf

2. 算数运算符和算数表达式

赋值运算符

赋值运算符用于给变量赋值,常用有以下六种:=、+=、 -=、 *=、 /=、 %=

int a;
a = 1;  // a的值变为1
a = a + 1; // a的值变为2
a = 4 + a;  // a的值变为6
a += b ;//等效于 a = a + b,但是执行速度更快

-=, *= ,/= ,%= 用法与+=类似; 表达式 x = y 的值,就是y的值

算术运算符

七种算术运算符用于数值运算 运算符+操作数构成表达式:
加+、减-、 乘* 、除/ 、求余数 % 、自增 ++ 、自减 –

  • 加、减、乘运算符
    a+b、a-b、a*b这三个表达式的值,就是操作数a和b做算术运算的结果 。表达式的值的类型,以操作数中精度高的类型为准。
    精度:

  • 加、减、乘运算的溢出
    1)两个整数类型进行加、减、乘都可能导致计算结果超出了结果类型所能表示的范围,这种情况就叫做溢出
    2)计算结果的溢出部分直接被丢弃。
    3)实数(浮点数)运算也可能溢出,结果不易预测。

#include  
using namespace std; 
int main()
{
	unsigned int n1 = 0xffffffff; 
	cout << n1 << endl; //输出4294967295,无符号int最大表示结果
	unsigned int n2 = n1 + 3; //导致溢出 
	cout << n2 << endl; //输出2  0xffffffff + 3 的结果,应该是 0x100000002,9个十六进制位,超出的一位十六进制位直接丢弃,结果就是0x00000002=2
	return 0;
} 

4)有时计算的最终结果似乎不会溢出,但中间结果可能溢出,这也会导致程序出错,例如:(a+b)/2 未必等于 a/2+b/2:

printf("%d",(2147483646 + 6)/2); //2147483646是int最大能表示的数字 先加6中间结果会溢出 导致最终结果出错 -1073741822
printf("%d",2147483646/2 + 6/2); // 如果先除以2,中间结果不会溢出,最终结果是正确的  1073741826

5)解决溢出的办法是尽量使用更高精度的数据类型(两个int进行运算会溢出, 用两个 long long 进行运算可能就不会溢出)。如果是几百位的数,就涉及到高精度计算,此时需要用到数组。

除法运算
  • 除法的计算结果类型和操作数中精度高的类型相同
  • 两个整数做除法,结果是商。余数直接忽略
    在这里插入图片描述
int main() 
{
	int a = 10;
	int b = 3;
	double d = a/b; // a/b 的值也是整型,其值是3 
	cout << d << endl; //输出 3
	d = 5/2; //d的值变为2.0
	cout << d << endl; //输出 2
	d = 5/2.0; //结果是操作数中精度较高的那一个 即double
	cout << d << endl; //输出 2.5
	d = (double)a/b;  //为得到更精确的值 可以把操作数强制转换为double
	cout << d << endl; //输出 3.33333
	return 0;
}
模运算

求余数的运算符“%”也称为模运算符。它是双目运算符,两个操作数都是整数类型的。a % b 的值就是a除以b的余数。
在这里插入图片描述
除法运算和模运算的除数都不能为0,否则程序会崩溃!!!

自增/自减运算符
  • 单目运算符,操作数为整数类型变量或实数型变量
  • 有前置和后置两种用法
  • 前置用法:++a; 将a的值加1,表达式返回值为a加1后的值
  • 后置用法:a++; 将a的值加1,表达式返回值为a加1前的值
#include  
using namespace std; 
int main()
{
	int n1, n2=5;
	n2 ++; // n2变成6
	++n2; //n2变成7
	n1 = n2 ++; // n2变成8,n1变成7
	cout << n1 << "," << n2 << endl; //输出 7,8 
	n1 = ++ n2; //n1和n2都变成9
	cout << n1 << "," << n1 << endl; //输出 9,9
	return 0; 
}
  • 自减运算符“–”,用于将整型或实数型变量的值减1。它的用法和“++”相同
取相反数运算符 -

单目运算符 “-”,用于取整型或实数型变量的值的相反数:

int a = 4;
int b = -a;
int c = -5*3;

3. 关系运算符和逻辑表达式

关系运算符
  • 六种关系运算符用于数值的比较
    相等 ==、不等 !=、大于 >、小于 <、 大于等于 >= 、小于等于 <=
  • 比较的结果是bool类型,成立则为true,反之为false
  • bool类型变量只有两种取值,true或false
  • false等价于0, true等价于非0整型值(一般是1)
int n = true,m = false;
printf("%d,%d",n,m);  // 1,0
int main()
{
int n1 = 4, n2 = 5,n3;
n3 = ( n1 > n2 ); // n3 的值变为 0   ()可以使表达式关系更清晰 可以不加;
cout<<n3<<",";  //输出0,
n3 = ( n1 < n2);  // n3 的值变为非0值
cout << n3 << ","; // 输出 1,
n3 = (n1 == 4);  // n3 的值变为非 0 值
cout << n3 << ","; // 输出 1,
n3 = (n1 != 4); // n3 的值变为0
cout << n3 << ","; // 输出 0,
n3 = (n1 == 5);// n3 的值变为0
cout << n3 ; // 输出 0,
return 0;
}
逻辑运算符和逻辑表达式

逻辑运算符用于表达式的逻辑操作,有 &&, || , ! 三种, 操作的结果是true或false。
表达式由操作数和运算符(关系运算符、算术运算符等)组成

  • 与 &&
    exp1 && exp2 当且仅当exp1和exp2的值都为真(或非0)时,结果为true
int n = 4;
n > 4 && n < 5    //false
n >= 2 && n < 5   //true
5 && 0 //false  C++中非0整数为真,0为假
4 && 1  //true
  • 或 ||
    exp1 || exp2 当且仅当exp1和exp2的值都为假(或0)时,结果为false
int n = 4;
n > 4 || n < 5  // true
n <= 2 || n > 5  //false
  • 非 !
    ! exp exp值为真(或非0),结果为false,exp值为false(0),结果为true
!(4 < 5 )  // false
!5   //false
!0   // true
短路计算

逻辑表达式是短路计算的,即对逻辑表达式的计算,在整个表达式的值已经能够断定的时候即会停止。

  • exp1 && exp2 : 如果已经算出表达式exp1为假,那么整个表达式的值肯定为 假,于是表达式exp2就不需要再计算
  • exp1 || exp2 :如果已经算出exp1为真,那么整个表达式必定为真,于是exp2 也不必计算
#include  
using namespace std; 
int main()
{
	int a = 0,b = 1;
	bool n= (a++)&&(b++); //b++不被计算 
	cout << a << "," << b << endl; //输出 1,1
	n= a++&&b++;  //a++和b++都要计算 
	cout << a << "," << b << endl; //输出 2,2
	n = a ++ || b ++ ;  //b++不被计算
	cout << a << "," << b << endl; //输出 3,2 
	return 0;
}

4. 其他运算符及运算优先级

强制类型转换运算符
  • 类型名本身就是一个运算符,叫“强制类型转换运算符” 用于将操作数转换为指定类型
double f = 9.14;
int n = (int) f; //n=9
f = n / 2; //f=4.0 
f = double(n) / 2; //f=4.5
部分运算符的优先级

程序设计与算法 | (3) 输入输出与运算符、表达式_第5张图片

  • 可以用()改变运算顺序/优先级,如 a*(b+c)。勤用括号以避免优先级错误, 得到自己想要的运算顺序
printf("%d,%d",a+++b,a); //a+++b 等价于(a++)+b

你可能感兴趣的:(程序设计与算法)