——输出二进制、十进制、八进制和十六进制总结
在C++中,默认状态下,数据按十进制输入输出。如果要求按八进制或十六进制输入输出,在cin或cout中必须指明相应的数据形式。
oct 为八进制,hex 为十六进制,dec 为十进制。但是二进制没有默认的输出格式,需要自己写函数进行转换。
#include <iostream> #include <bitset> using namespace std; int main(void) { int i,j,k,l; cout<<"Input i(oct),j(hex),k(hex),l(dec):"<<endl; cin>>oct>>i; //输入为八进制数 cin>>hex>>j; //输入为十六进制数 cin>>k; //输入仍为十六进制数 在cin或cout中指明数制后,该数制将一直有效,直到重新指明使用其他数制 cin>>dec>>l; //输入为十进制数 cout<<"hex:"<<"i = "<<hex<<i<<endl; cout<<"dec:"<<"j = "<<dec<<j<<'\t'<<"k = "<<k<<endl; cout<<"oct:"<<"l = "<<oct<<l; cout<<dec<<endl; //恢复十进制数输出状态 return (0); }调试运行
思考与提示
- 在接收输入时,必须在cin中指明数制,否则从键盘输入时,不认八进制和十六进制数开头的0和0x标志。指明后可省略0和0x标志。
- 进制控制只适用于整型变量,不适用于实型和字符型变量。
- 输入数据的格式、个数和类型必须与cin中的变量一一对应,否则不仅使输入数据错误,而且影响后面其他数据的正确输入。
- 在cin或cout中指明数制后,该数制将一直有效,直到重新指明使用其他数制。
C++中二进制输出的总结
#include <iostream> #include <list> #include <bitset> #include <iomanip> using namespace std; //递归输出二进制函数 void BinaryRecursion(int n) { int a; a = n % 2; // 取余 n = n >> 1; //右移一位 相当于除以2 if(0 != n) { BinaryRecursion(n); } cout<<a; } //使用容器转换二进制 void BinaryVector(int n) { int temp; temp = n; list <int> L; while(0 != temp) { L.push_front(temp % 2); temp = temp >> 1; } for(list <int>::iterator iter = L.begin(); iter != L.end(); iter++) { cout<<*iter; } cout <<endl; } //一般方法,32位,逐步与1做与运算 void Binarycout(int n) { for(int i = 31; i>= 0; i--) { cout<<((n>>i)&1); } cout<<endl; } //使用bitset转换二进制 void BinaryBitset(int n) { cout<<bitset<sizeof(int)*8>(n)<<endl; } int main() { int a = 1045, b = 2; int c; c = a + b; cout<<setw(20)<<"BinaryRecursion("<<c<<"):"; BinaryRecursion(c); cout<<endl; cout<<setw(20)<<"BinaryVector("<<c<<"):"; BinaryVector(c); cout<<setw(20)<<"Binarycout("<<c<<"):"; Binarycout(c); cout<<setw(20)<<"BinaryBitset("<<c<<"):"; BinaryBitset(c); return (0); }调试运行
思考与提示
//递归输出二进制函数 void BinaryRecursion(int n) { int a; a = n % 2; // 取余 n = n >> 1; //右移一位 相当于除以2 if(0 != n) { BinaryRecursion(n); } cout<<a; }递归层次
使用递归的代价是十分巨大的:它会消耗大量的内存!!递归循环时它用的是堆栈,而堆栈的资源是十分有限的。假设调用该递归函数的主函数为第0层,则从主函数调用递归函数进入第1层;从第i层递归调用本身为进入“下一层”,即第i+1层。反之,退出第i层递归应返回至“上一层”,即第i-1层。
为了保证递归函数正确执行,系统需设立一个“递归工作栈”作为整个递归函数运行期间使用的数据存储区。每一层递归所需信息构成一个“工作记录”,其中包括所有的实参、所有的局部变量以及上一层的返回地址。
每进入一层递归,就产生一个新的工作记录压入栈顶。每退出一层递归就从栈顶弹出一个工作记录,则当前执行层的工作记录必须是递归工作栈栈顶的工作记录,称这个记录为“活动记录”,并称指示活动记录的栈顶指针为“当前环境指针”。
如上图所示:当n 不等于0时,保存当前层的“工作记录”,然后递归调用进入下一层,直到n 等于0 ,此时是第四层,把当前层的a值 1 打印出来,然后退出第4层递归,返回至“上一层”即第4 – 1 层,即第3层。然后打印此层的a值 0,依次递归返回打印其余层。最后得到结果为 1010.
——输入输出格式控制
~输入输出宽度控制
setw(int n): 设置输入输出宽度,等价于io.width(n)头文件: #include<iomanip>
cout<< setw(10) << 123 << setw(10) << 456 <<endl //结果: 123 456
~浮点数输出格式控制
resetionsflags: 为默认设置,浮点数按浮点格式输出fixed: 浮点数按定点格式输出,保留小数点后6位scientific: 浮点数按指数格式(科学计数法)输出
cout<<314.15926535<<endl; cout<<fixed<<314.15926535<<endl; cout<<scientific<<314.15926535<<endl; //结果: 314.159 314.159265 3.141593e+002
~输出精度控制
setprecision(int n):设置浮点数的精度(有效位数或小数位数)
setprecision(n) 指定一个浮点数的精度默认设置输出的数字的 总位数 为n,包含整数和小数部分;其中setprecision(0)效果是跟c++默认的流输出数值一样,有效位是6位,包括整数和小数
fixed必须与setprecision(n)配合使用,用来控制小数位数,不够补0,只要写一次fixed,后面的setprecision(n)就都是指小数了。 fixed与setprecision谁先谁后没有关系,但通常是fixed在前先固定6位小数(若此时小数已经超出6位,则先四舍五入到6位)再precision(n)取n位小数(n<6)
#include <iostream> #include <iomanip> using namespace std; { double f = 3.123456789; cout<<f<<endl; //输出3.12346 (包含整数和小数,且四舍五入) cout<<setprecision(2)<<f<<endl; //输出3.1(包含整数和小数,共两位,且最后一位四舍五入),这条会作用到下一条去 cout<<fixed<<f<<endl; //输出3.123457 (仅包含小数,且四舍五入),没有上一条,则输出六位小数3.123457 cout<<setprecision(2)<<fixed<<f<<endl; //输出3.12 (小数2位,四舍五入) cout<<fixed<<setprecision(2)<<f<<endl; //效果同上 system("pause"); return 0; }
- 如果与setiosnags(ios::scientific)合用, 可以控制指数表示法的小数位数。setiosflags(ios::scientific)是用指数方式表示实数。
- resetiosflags(ios::fixed) 取消精度的设置。
1.)超出的位数会被四舍五入进去!!!
2)与setw()不同setprecision(n)一直作用到下一个setprecisin(n)之前,所以,只需要写一个setprecision(n)就可以。setw()要每次都写
2)与setw()不同setprecision(n)一直作用到下一个setprecisin(n)之前,所以,只需要写一个setprecision(n)就可以。setw()要每次都写
~对齐方式控制
left: 在设定的宽度内左对齐输出,右端使用设定的填充字符填充right: 为默认设置,在设定宽度内右对齐输出,左端使用设定的填充字符填满internal: 在设定的宽度内右对齐输出,但若有符号(-,+),符号至于最左端
double s = 12; cout << setw(10) << s << "OK" << endl; cout << left<< setw(10)<<s<< "OK" << endl; //结果: 12OK 12 OK
~小数点处理方式的控制
showpoint: 即使小数部分为0,也输出小数点及其后的无效0noshowpoint: 为默认设置,小数部分的最后的0不输出
cout<<12.0<<endl; cout<<showpoint<<12.0<<endl; //结果 12 12.0000
~填充字符控制
setfill(char c):设置填充字符
cout<<setw(10)<<12<<endl; cout<<setfill('*')<<setw(10)<<12<<endl; //结果: 12 ********12
——字符&字符串输入输出结束控制
~getchar( ) & EOF
1)getchar的两点总结:
<1>getchar是以行为单位进行存取的。
当用getchar进行输入时,如果输入的第一个字符为有效字符(即输入是文件结束符EOF,Windows下为组合键Ctrl+Z,Unix/Linux下为组合键Ctrl+D),那么只有当最后一个输入字符为换行符´\n´(也可以是文件结束符EOF,EOF将在后面讨论)时,getchar才会停止执行,整个程序将会往下执行。
while((c = getchar()) != EOF) { putchar(c); }对于getchar,肯定很多初学的朋友会问,getchar不是以字符为单位读取的吗?那么,既然我输入了第一个字符a,肯定满足while循环(c = getchar()) != EOF的条件阿,那么应该执行putchar(c)在终端输出一个字符a。不错,我在用getchar的时候也是一直这么想的,但是程序就偏偏不着样执行,而是 必需读到一个换行符或者文件结束符EOF才进行一次输出。
解释是: 在大师编写C的时候,当时并没有所谓终端输入的概念,所有的输入实际上都是按照文件进行读取的,文件中一般都是以行为单位的。因此,只有遇到换行符,那么程序会认为输入结束,然后采取执行程序的其他部分。同时,输入是按照文件的方式存取的,那么要结束一个文件的输入就需用到EOF(Enf Of File). 这也就是为什么getchar结束输入退出时要用EOF的原因。
<2>getchar( )的返回值一般情况下是字符,但也可能是负值,即返回EOF。
这里要强调的一点就是,getchar函数通常返回终端所输入的字符,这些字符系统中对应的ASCII值都是非负的。因此,很多时候,我们会写这样的两行代码:
这里要强调的一点就是,getchar函数通常返回终端所输入的字符,这些字符系统中对应的ASCII值都是非负的。因此,很多时候,我们会写这样的两行代码:
char c; c = getchar();这样就很有可能出现问题。因为getchar函数除了返回终端输入的字符外,在遇到Ctrl+D(Linux下)即文件结束符EOF时,getchar()的返回EOF,这个EOF在函数库里一般定义为-1。因此,在这种情况下,getchar函数返回一个负值,把一个负值赋给一个char型的变量是不正确的。
为了能够让所定义的变量能够包含getchar函数返回的所有可能的值,正确的定义方法如下(K&R C中特别提到了这个问题):
int c; c = getchar();
2)EOF的两点总结
<1>EOF作为文件结束符时的情况:
EOF虽然是文件结束符,但并不是在任何情况下输入Ctrl+D(Windows下Ctrl+Z)都能够实现文件结束的功能,只有在下列的条件下,才作为文件结束符。
- 遇到getcahr函数执行时,要输入第一个字符时就直接输入Ctrl+D,就可以跳出getchar(),去执行程序的其他部分;
- 在前面输入的字符为换行符时,接着输入Ctrl+D;
- 在前面有字符输入且不为换行符时,要连着输入两次Ctrl+D,这时第二次输入的Ctrl+D起到文件结束符的功能,至于第一次的Ctrl+D的作用将在下面介绍。
<2>EOF作为行结束符时的情况,这时候输入Ctrl+D并不能结束getchar(),而只能引发getchar()提示下一轮的输入。
这种情况主要是在进行getchar()新的一行输入时,当输入了若干字符(不能包含换行符)之后,直接输入Ctrl+D,此时的Ctrl+D并不是文件结束符,而只是相当于换行符的功能,即结束当前的输入。以上面的代码段为例,如果执行时输入abc,然后Ctrl+D,程序输出结果为:
abcabc
注意:第一组abc为从终端输入的,然后输入Ctrl+D,就输出第二组abc,同时光标停在第二组字符的c后面,然后可以进行新一次的输入。这时如果再次输入Ctrl+D,则起到了文件结束符的作用,结束getchar()。
abcabc
注意:第一组abc为从终端输入的,然后输入Ctrl+D,就输出第二组abc,同时光标停在第二组字符的c后面,然后可以进行新一次的输入。这时如果再次输入Ctrl+D,则起到了文件结束符的作用,结束getchar()。
如果输入abc之后,然后回车,输入换行符的话,则终端显示为:
abc //第一行,带回车
abc //第二行
//第三行
其中第一行为终端输入,第二行为终端输出,光标停在了第三行处,等待新一次的终端输入。
从这里也可以看出Ctrl+D和换行符分别作为行结束符时,输出的不同结果。
EOF的作用也可以总结为:当终端有字符输入时,Ctrl+D产生的EOF相当于结束本行的输入,将引起getchar()新一轮的输入;当终端没有字符输入或者可以说当getchar()读取新的一次输入时,输入Ctrl+D,此时产生的EOF相当于文件结束符,程序将结束getchar()的执行。
abc //第一行,带回车
abc //第二行
//第三行
其中第一行为终端输入,第二行为终端输出,光标停在了第三行处,等待新一次的终端输入。
从这里也可以看出Ctrl+D和换行符分别作为行结束符时,输出的不同结果。
EOF的作用也可以总结为:当终端有字符输入时,Ctrl+D产生的EOF相当于结束本行的输入,将引起getchar()新一轮的输入;当终端没有字符输入或者可以说当getchar()读取新的一次输入时,输入Ctrl+D,此时产生的EOF相当于文件结束符,程序将结束getchar()的执行。
~cout输出字符串和字符串地址
char *c="cadn\0hello"; cout<<c<<endl;输出的结果是:cadn
如果我们回归到C语言的话,例如用printf的话,如下:
printf("%x\n",&c[0]);输出的结果是:46f020
C++标准库中的I/O类对<<操作符重载,因此在遇到字符型指针的时候会将其作为字符串名进行处理,输出指针所指的字符串。
既然如此,我们就别让它知道那是字符串指针,所以,需要用到强制类型转换,把字符串指针转换成 无类型(或其他类型) 的指针。如下
cout<<(void *)c<<endl;除了cout<<(char *)c<<endl都行
——c++输入字符串的多种方法
~cin >>
它不跳过特殊字符(空格、换行),cin在遇到空格符、回车符时会认为字符串已经结束,自动在New的结尾添加 \0字符
通过cin输入 Hello World 按下Enter键,则cin只将Hello提取给输入变量,此时World还继续留在输入队列中。
#include <iostream> using namespace std; main () { int a,b; cin>>a>>b; cout<<a+b<<endl; }
输入:2[回车]3[回车] 输出:5注意: >> 是会过滤掉不可见字符(如 空格 回车,TAB 等)
cin>> noskipws >>input[j] //不想略过空白字符,那就使用 noskipws 流控制
~cin.getline()和cin.get()
此二者与cin>>的区别:这两种输入方式只会在遇到回车符时认为字符串结束,在遇到空格符时还会继续读取空格后面的字符。
cin.getline():在遇到回车符时,结束字符串输入并丢弃回车符。cin.get():在遇到回车符时,则会保留回车符在输入队列。
当输入的字符长度大于数组长度时:cin.getline():会设置失效位,后面的输入都无法再读取,可以利用这点来避免输入超过数组边界。但是cin.get():会继续将剩下的字符串保持在输入流中,但是会被吞掉一个字符(吞掉的字符就是被设置为空位符位置上的字符)。
1) cin.getline()
该函数有两个参数。第一个参数是用来储存输入行的数组名称,第二个参数是要读取的字符数。如果这参数为20,则函数最多读取19个字符,余下的空间用于储存自动在结尾处添加的空字符。getline()成员函数在读取指定数目的字符或者遇到换行符时停止读取。
上图说明:遇回车结束。
上图说明:‘\n’会被加到变量最后一位。由于getline指示读取5个字符大小的字符串,所以只读取了1234,最后一位由’\n’补齐。
getline()函数每次读取一行。它通过换行符来确定尾部,但不保存换行符。相反,在储存字符串时,它用空字符(’\0’)来替换换行符。
2) cin.get()
get(带参)不读取且不丢弃换行符,而是将其留在输入队列中。
例如: cin.get(name, 10); cin.get(blog, 10); 连续两个cin.get(带参).就出问题了。由于第一次调用后,换行符将留在输入队列中,因此第二次调用时看到的第一个字符就是换行符。因此get()认为已经达到行尾,而没有发现任何读取内容。
如果不借助帮助,get()将不能跨过该换行符。
不带任何参数的 cin.get() ,可以读取下一个字符(即使是换行符)。
所以我们可以改成如下: cin.get(name,10); cin.get(); cin.get(blog,10);
cin.get(ch)和ch = cin.get()的区别:
ch = cin.get() : 先调用cin.get()函数,然后将该函数的返回值赋给ch,语句的结果为ch的值。cin.get(ch): 在到达EOF值时,不会赋值给ch,ch只是接收输入字符。
属性 cin.get(ch) ch = cin.get() 传递输入字符的方式 赋值给参数ch 将函数返回值赋给ch 用于字符输入时函数的返回值 istream对象(执行bool转换后为true ) int类型的字符编码 到达EOF时函数的返回值 istream对象(执行bool转换后为false ) EOF
一般使用cin.get(ch),因其更符合对象方式,返回值是istream对象,这意味着可以讲它们拼接起来:cin.get(ch1).get(ch2);
注意:
char ch; while( (ch = cin.get())!= EOF ) {} ---正确(因为cin.get()那几个重载函数里面,只有不带参数的返回值是int型,而EOF为 -1) while( cin.get(ch)!= EOF ) {} ---错误(因为带参数的cin.get() 的返回值是流对象,即iostream对象)
3) cin.get(字符变量名)
可以用来接收一个字符
4) cin.get(字符数组名,接收字符数目)
用来接收一行字符串,可以接收空格。
上图说明:空格也能被接收。 刚好接收19个字符(20-1),最后一位由’\n’补齐。
~用string接收
1) getline()
接受一个字符串,可以接收空格并输出,需包含 #include<string>
说明:回车键结束输入。
和cin.getline()类似,但是cin.getline()属于istream流,而getline()属于string流,是不一样的两个函数
2) gets()
接受一个字符串,可以接收空格并输出,需包含 #include<string>