c++c语言运行没有结果结果为什么是最后一个?前面两个为什么没有输出?

三亿文库3y.uu456.com包含各类专业文献、中学教育、行业资料、高等教育、文学作品欣赏、各类资格考试、16??????c++???????
????_??????等内容。
 C++程序设计基础(第 5 版) (上) 习题与解答第 1 章练习题同步练习 1.1 一、选择题 1.一个最简单的 C++程序,可以只有一个( (A)库函数 2.函数名是( ...  7.10 MALLOC/FREE 的使用要点 7.11 NEW/DELETE 的使用要点 7.12 一些心得体会 第 8 章 C++函数的高级特性 8.1 函数重载的概念 8.2 成员函数的重载、覆盖...  C++常用算法归纳_互联网_IT/计算机_专业资料。C++常用算法归纳一、基本算法 1、两数交换借助第三数例:任意读入 2 个整数,然后按从小到大的顺序输出这两个数。 ...  www.gybdqn.com C++的应用领域有哪些? C++是一门运用很广泛的计算机编程语言,适合于多种操作系统,因此也有着很广阔 的运用领域。 据不完全数据统计,C++在游戏、...  C++语言实际上是几种不同语言的聚集地, 你可以把 他看成一种语言,也可以把他看成一种语言,要进行对C++程序地开发,那么复杂性会大幅 度地增加,这就是C++在...  C++首创_法律资料_人文社科_专业资料。C++/C 试题的答案与评分标准一、请填写 BOOL , float, 指针变量 与“零值”比较的 if 语句。 (10 分) 请写出 BOOL ...  (1)不调用 C++/C 的字符串库函数,请编写函数 strcpy char *strcpy(char *strDest,const char *strSrc){ int n=0; while(strSrc[n]!=NULL){ n++: } ...  如何在 C#的程序中调用 C++? 的程序中调用 ? api 函数是构筑 windws 应用程序的基石,每一种 windows 应用程序开发工具,它 提供的底层函数都间接或直接地调用了...小木虫 --- 700万学术达人喜爱的学术科研平台
热门搜索:
&&【求助】dev c++编译结束,运行后怎么样输出结果?
【求助】dev c++编译结束,运行后怎么样输出结果?
& && &int c,
& && &nl=0;
& && &while((c=getchar())!=EOF)
& && &if(c=='\n')
& && &printf("%d\n",nl);
结果是这样的?
我该怎么才能让它出来正确结果,我是输入后按enter键的!
只计换号符的个数?
加上大括号,哪怕只有一句,这是一个好习惯。
while((c=getchar())!=EOF)
& && & if(c=='\n')
& && && &++
& && && &printf("%d\n",nl);
谢谢你!真是高手,随便一点就解决了我困惑了好久的问题,我是学化工的,假期想学学c,现在正在努力,您有关于devc++的使用说明吗,给我一份看看!感激不尽!我的邮箱
& && &for (nc=0;getchar() != EOF; ++nc)
& && &printf("%.0f\n",nc);
& && &sys("pause");
结果怎么会是这样呢?
你肯定是高手,能告诉我你的邮箱或者qq吗,有问题时能找你!谢谢
学术必备与600万学术达人在线互动!
扫描下载送金币
北京学而思教育科技有限公司 地址:北京市海淀区北三环甲18号中鼎大厦A座1层102室 电话:010-传智播客旗下品牌:& & | && | &
改变中国IT教育,我们正在行动 &&&&全国咨询热线:400-618-4000
全国校区 
扫描二维码
关注传智播客QQ空间账号
?微信公众号
扫描二维码
关注传智播客微信公众账号
扫描二维码
关注传智播客新浪微博账号
400-618-4000下次自动登录
现在的位置:
& 综合 & 正文
C语言为何如此长寿并实用?C++为什么有那么多精彩?指针可以说是C/C++中的灵魂所在,虽然早期中pascal也有指针,但是和C/C++比起来不是一个级别的.今天为大家深入浅出的解析一下指针的有关笔试,面试题.所有题目来源网络,分析也不是我写的...
0.预备知识,最基础的指针
其实最基础的指针也就应该如下面代码:int a;int* p=&a;也就是说,声明了一个int变量a,然后声明一个int 的指针,*p指向a的地址,&也就是取地址符号,而*是指针中取内容的符号,仅仅在声明的时候标记这个变量是指针.可能有点绕口,但是看代码来的容易的多...
1.与const在一起的时候
常常声明的时候会让人一头雾水,比如下面的声明,均是声明一个char* p的指针:char * const p;
// 指针不可改,也就说指针只能指向一个地址,不能更改为其他地址char const *
// 所指内容不可改,也就是说*p是常量字符串char const * const p; // 内容和指针都不能改const char * const p; // 同上...内容和指针不能改额...别晕,别晕....其实方法很简单...你别真死记硬背...其实可以以*为分界符,在*左边有const就说明内容不能改,在*右边就说明指针不能改,而左边的char和const顺序是不要紧的...呵呵...你也可以理解成const是修饰后面的,正常顺序应该这样:const char * const p; 是不是看起来简单了?
2.忽悠人的陷阱,str[]和*str的区别
先告诉你哦,下面的题目可是陷阱啊....说说程序结果...char str1[] = “abc”;char str2[] = “abc”;
const char str3[] = “abc”;const char str4[] = “abc”;
const char *str5 = “abc”;const char *str6 = “abc”;
char *str7 = “abc”;char *str8 = “abc”;
cout && ( str1 == str2 ) &&cout && ( str3 == str4 ) &&cout && ( str5 == str6 ) &&cout && ( str7 == str8 ) &&怎么样?都输出true?那显然你中标了...而且cout输出bool值的时候,就算全是真也应该都输出1啊...4个1?那也不对...答案是0011,不信你试试...为什么呢?其实都说了这题是个大陷阱,因为这题根本不是比较字符串内容!而是比较字符串的地址.哦...恍然大悟...那为什么前两个是假呢?因为这可是说是一个深拷贝/浅拷贝的问题.当字符串是数组形式声明并初始化,编译器认为是新数组,分配新空间,但不是深拷贝,因为根本就不算拷贝.而如果是相同的字符串,用指针声明,那就是比较如果有一样的字符串,就直接把新指针指过去,这是正宗的浅拷贝.哇哈...你就中计了...
3.str[]用sizeof判断会出错么?
应该说我们常常用指针有很多时候是解决字符串的问题,一般我们用strlen,这当然没有问题,但是要你编一个呢?看看下面这个MyStrlen有问题么?int MyStrlen(char str[]){
return (int)(sizeof(str)-1);}呵呵...咱们上当过一次..这个当然也是不对的...不错...这个函数是错的...为什么呢?首先,可以告诉你,无论何时,返回的总是3...额...是不是很奇怪,为什么不是数组长度呢?str不是char数组指针么?不错...确实是数组的指针,但是,当用函数传递的数组指针的时候就自动退化为指针了,而指针的长度是4,你减去1了自然就是3了.但是如果按照下面代码就可以得到正常的值.char str[]="hello world";int len=sizeof(str)-1;
//记得减1哦,最后有'/0'结尾cout&&这样输出的是正常值,也就是你所希望的11;
4.注意数组指针和指针
继续上面的话题,刚刚提到了数组指针和指针,现在看看下面这端程序代码:int a[5]={1,2,3,4,5};int *ptr=(int *)(&a+1);cout&&*(a+1)&&*(ptr-1);呵呵...BaihowFF总是给陷阱..肯定不是想当然的说就是21...确实...答案是25...额...奇怪吧..为什么呢?首先,a是一个数组,所以编译器解释&a就是a的全部长度,就是说(&a+1)也就是说移动了一个数组,指向了并不存在的a[5],所以ptr-1才会指向a数组的最后一个元素a[4],而a+1和a[1]是一样的...所以答案是25,如果你去掉了(&a+1)的括号,那么答案就是想当然的21了...呵呵...很微妙吧....
5.注意指针要分配给足够的空间
新手在刚刚接触指针的时候经常会忘记给指针分配空间,直接用肯定是有问题的,那么下面的程序呢?char a;char *str=&a;strcpy(str,”hello”);cout&&BaihowFF是坏蛋..总会下套...呵呵..确实是圈套...这段程序能够输出hello,但是输出后就崩溃了...原因就在你分配str指针的时候仅仅给了1字节的空间,但是你拷贝了6字节过去(不要忘记了最后的'/0'结束).运行输出后程序因为访问了没有分配的呵呵空间,当然崩溃了.如果你只strcpy(str,"");那程序是可以正常运行的.
6.小心编译器的指针字符串初始化
经常我们想自己处理字符串,但是像下面的初始化是很危险的!!!char* s="AAA";cout&&s&&s[0]='B';cout&&s&&你可以拿这段程序去编译...没错!编译器报告正常!...这是最要命的...其实程序不能运行的...输出AAA后就崩溃了..为什么?因为当你在第一句初始化的时候,编译器就认为这是个字符串常量了...再做数组操作的时候肯定错了罗...最好的习惯是声明一个指针,用new分配空间,然后用库函数操作,比如strcpy,strcat等等...
7.让人一眼看上去迷糊的函数指针
看看这句代表什么意思?int (*s[10])(int);咦...这是什么?其实这是一个函数指针数组,指向了一组int fun(int)的函数,第一眼确实让人有点迷糊...但是请习惯这样...
8.注意函数传递指针的时候是副本
副本?又下副本?...汗...老兄...不是这个意思...别沉浸在WOW里了啊...看看下面程序的问题:void GetMemory(char *p){ p=new char[100];strcpy(p,"hello world");}
void main(void){char *str=NULL;GetMemory(str);cout&&delete []str=NULL;}当然了..喜欢下套的BaihowFF又给了错程序....错在哪呢?看上去是对的,而且编译器编译也正确啊..怎么就是不能通过呢?而且还崩溃了...好费解吧...其实原因很简单...GetMemory这个函数出问题了!函数参数是不能传递分配空间的...因为传递过去实际上是一个副本p...不能返回的...而且你在delete那就是件很危险的事情..因为压根没有内容...那我实在想这样用函数分配怎么办呢?像下面这样改一下就ok了:void GetMemory(char **p)
// 改成晦涩难懂的指针的指针{ *p=new char[100];
//给*p的分配地址strcpy(*p,"hello world");
// 拷贝内容到*p}
void main(void){char *str=NULL;GetMemory(&str);
//这地方取地址cout&&delete []str=NULL;}这样就能正常工作了,但是看起来好别扭啊...嗯..确实...但是还可以用其他方法哦....你想想...肯定有办法的...
9.请时刻记住要初始化字符串
嗯...这点大家都知道...那你猜猜下面的程序结果是多少?char a[10];cout&&strlen(a)&&答案应该让你以外...竟然是15...没道理吧?!其实strlen函数的结果和是否初始化有关的...虽然你分配了空间..但是没有初始化..库函数会出错的..sizeof不受影响...切忌初始化哦....
10.小括号,大区别
看看这两端声明,有什么不同?我直接在注释里告诉你答案吧...这样好看点...char (*str)[20];
//str是一个数组指针,即指向数组的指针.char *str[20];
//str是一个指针数组,其元素为指针型数据.千万别小看括号哦...区别大了吧....
最后给个完整程序想一下运行结果分析在最后
#include&iostream.h&
#include &string.h&
#include &malloc.h&
#include &stdio.h&
#include &stdlib.h&
#include &memory.h&
typedef struct
void main()
char cc[100];
strcpy(cc,"abcdefghijklmnopqrstuvwxyz");
memcpy(&aa,cc,sizeof(AA));
cout && aa.b1 &&
cout && aa.b2 &&
答案:-16和1首先sizeof(AA)的大小为4,b1和b2分别占5bit和2bit.经过strcpy和memcpy后,aa的4个字节所存放的值是: 0,1,2,3的ASC码,即10,所以,最后一步:显示的是这4个字节的前5位,和 之后的2位分别为:10000,和01,因为int是有正负之分
11. 以下代码中的两个sizeof 用法有问题吗?
char str[] ) // 将str 中的小写字母转换成大写字母
sizeof (str)/ sizeof (str[0]); ++i )
'a' &=str[i] && str[i]&= 'z' )
字符长度为sizeof (str)/ sizeof (str[0]) &&
答:函数内的sizeof 有问题。根据语法,sizeof 如用于数组,只能测出静态数组的大小,无法检测动态分配的或外部数组大小。函数外的str 是一个静态定义的数组,因此其大小为,函数内的str 实际只是一个指向字符串的指针,没有任何额外的与数组相关的信息,因此sizeof 作用于上只将其当指针看,一个指针为个字节,因此返回。
12. 非C++ 内建型别A 和B ,在哪几种情况下B 能隐式转化为A ?
public A { …… } // B 公有继承自,可以是间接继承的
operator A( ); } // B 实现了隐式转化为的转化
const B& ); } // A 实现了的参数为(可以有其他带默认值的参数)构造函数
const A& ); // 赋值操作,虽不是正宗的隐式类型转换,但也勉强算一个
13. 以下代码有什么问题?
答:变量b 定义出错。按默认构造函数定义对象,不需要加括号。
14. 以下代码有什么问题?
?1: "0" ) &&
答:三元表达式“?: ”问号后面的两个操作数必须为同一类型。
15. 以下代码能够编译通过吗,为什么?
const size1 = 2;
const size2 =
答:str2 定义出错,size2 非编译器期间常量,而数组定义要求长度必须为编译期常量。
16. 以下反向遍历array 数组的方法有什么错误?
array .size()-1; i&=0; --i ) // 反向遍历数组
答:首先数组定义有误,应加上类型参数:vector&int& array 。其次vector::size_type 被定义为unsigned int ,即无符号数,这样做为循环变量的i 为时再减就会变成最大的整数,导致循环失去控制。
17. 以下代码中的输出语句输出吗,为什么?
答:不能。在默认构造函数内部再调用带参的构造函数属用户行为而非编译器行为,亦即仅执行函数调用,而不会执行其后的初始化表达式。只有在生成对象时,初始化表达式才会随相应的构造函数一起调用。
<p class="MsoNormal" style="margin: 0in 0i
&&&&推荐文章:
【上篇】【下篇】C++jichusljc-p-海文库
全站搜索:
您现在的位置:&>&&>&计算机硬件及网络
C++jichusljc-p
1.1C++程序结构(Structureofaprogram)下面我们从一个最简单的程序入手看一个C++程序的组成结构。//myfirstprograminC++#include&iostream.h&intmain(){cout&&“HelloWorld!”;return0;}上面左侧显示了我们的第一个程序的源代码,代码文件名称为hellowworld.cpp。右边显示了程序被编译执行后的输出结果。编辑和编译一个程序的方法取决于你用的是什么编译器,根据它是否有图形化的界面及版本的不同,编译方法也有可能不同,具体请参照你所使用的编译器的使用说明。以上程序是多数初学者学会写的第一个程序,它的运行结果是在屏幕上打出”HelloWorld!”这句话。虽然它可能是C++可写出的最简单的程序之一,但其中已经包含了每一个C++程序的基本组成结构。下面我们就逐个分析其组成结构的每一部分:HelloWorld!//myfirstprograminC++这是注释行。所有以两个斜线符号(//)开始的程序行都被认为是注释行,这些注释行是程序员写在程序源代码内,用来对程序作简单解释或描述的,对程序本身的运行不会产生影响。在本例中,这行注释对本程序是什么做了一个简要的描述。#include&iostream.h&以#标志开始的句子是预处理器的指示语句。它们不是可执行代码,只是对编译器作出指示。在本例中这个句子#include&iostream.h&告诉编译器的预处理器将输入输出流的标准头文件(iostream.h)包括在本程序中。这个头文件包括了C++中定义的基本标准输入-输出程序库的声明。此处它被包括进来是因为在本程序的后面部分中将用到它的功能。1/170C++标准函数库的所有元素都被声明在一个名空间中,这就是std名空间。因此为了能够访问它的功能,我们用这条语句来表达我们将使用标准名空间中定义的元素。这条语句在使用标准函数库的C++程序中频繁出现,本教程中大部分代码例子中也将用到它。intmain()这一行为主函数(mainfunction)的起始声明。mainfunction是所有C++程序的运行的起始点。不管它是在代码的开头,结尾还是中间C此函数中的代码总是在程序开始运行时第一个被执行。并且,由于同样的原因,所有C++程序都必须有一个mainfunction。main后面跟了一对圆括号(),表示它是一个函数。C++中所有函数都跟有一对圆括号(),括号中可以有一些输入参数。如例题中显示,主函数(mainfunction)的内容紧跟在它的声明之后,由花括号({})括起来。”;cout&&“HellowWorld!World!”这个语句在本程序中最重要。cout是C++中的标准输出流(通常为控制台,即屏幕),这句话把一串字符串(本例中为”HelloWorld”)插入输出流(控制台输出)中。cout在的声明在头文件iostream.h中,所以要想使用cout必须将该头文件包括在程序开始处。注意这个句子以分号(;)结尾。分号标示了一个语句的结束,C++的每一个语句都必须以分号结尾。(C++程序员最常犯的错误之一就是忘记在语句末尾写上分号)。return0;返回语句(return)引起主函数main()执行结束,并将该语句后面所跟代码(在本例中为0)返回。这是在程序执行没有出现任何错误的情况下最常见的程序结束方式。在后面的例子中你会看到所有C++程序都以类似的语句结束。你可能注意到并不是程序中的所有的行都会被执行。程序中可以有注释行(以//开头),有编译器预处理器的指示行(以#开头),然后有函数的声明(本例中main函数),最后是程序语句(例如调用cout&&),最后这些语句行全部被括在主函数的花括号({})内。本例中程序被写在不同的行中以方便阅读。其实这并不是必须的。例如,以下程序intmain(){cout&&&HelloWorld&;return0;}也可以被写成:intmain(){cout&&&HelloWorld&;return0;}以上两段程序是完全相同的。2/170在C++中,语句的分隔是以分号(;)为分隔符的。分行写代码只是为了更方便人阅读。以下程序包含更多的语句://mysecondprograminC++#include&iostream.h&intmain(){cout&&&HelloWorld!&;cout&&&I'maC++program&;return0;}在这个例子中,我们在两个不同的语句中调用了cout&&函数两次。再一次说明分行写程序代码只是为了我们阅读方便,因为这个main函数也可以被写为以下形式而没有任何问题:intmain(){cout&&&HelloWorld!&;cout&&&I'mtoC++program&;return0;}为方便起见,我们也可以把代码分为更多的行来写:intmain(){cout&&&HelloWorld!&;cout&&&I'maC++program&;return0;}它的运行结果将和上面的例子完全一样。这个规则对预处理器指示行(以#号开始的行)并不适用,因为它们并不是真正的语句。它们由预处理器读取并忽略,并不会生成任何代码。因此他们每一个必须单独成行,末尾不需要分号(;)HelloWorld!I'maC++program注释(Comments)注释(comments)是源代码的一部分,但它们会被编译器忽略。它们不会生成任何执行代码。使用注释的目的只是使程序员可以在源程序中插入一些说明解释性的内容。C++支持两中插入注释的方法:3/170//linecomment/*blockcomment*/第一种方法为行注释,它告诉编译器忽略从//开始至本行结束的任何内容。第二种为块注释(段注释),告诉编译器忽略在/*符号和*/符号之间的所有内容,可能包含多行内容。在以下我们的第二个程序中,我们插入了更多的注释。/*mysecondprograminC++withmorecomments*/#include&iostream.h&intmain(){cout&&&HelloWorld!&;//saysHelloWorld!cout&&&I'maC++program&;//saysI'maC++programreturn0;}如果你在源程序中插入了注释而没有用//符号或/*和*/符号,编译器会把它们当成C++的语句,那么在编译时就会出现一个或多个错误信息。HelloWorld!I'maC++program4/1701.2变量和数据类型(VariablesandDatatypes)你可能觉得这个“HellowWorld”程序用处不大。我们写了好几行代码,编译,然后执行生成的程序只是为了在屏幕上看到一句话。的确,我们直接在屏幕上打出这句话会更快。但是编程并不仅限于在屏幕上打出文字这么简单的工作。为了能够进一步写出可以执行更有用的任务的程序,我们需要引入变量(variable)这个的概念。让我们设想这样一个例子,我要求你在脑子里记住5这个数字,然后再记住2这个数字。你已经存储了两个数值在你的记忆里。现在我要求你在我说的第一个数值上加1,你应该保留6(即5+1)和2在你的记忆里。现在如果我们将两数相减可以得到结果4。所有这些你在脑子里做的事情与计算机用两个变量可以做的事情非常相似。同样的处理过程用C++来表示可以写成下面一段代码:a=5;b=2;a=a+1;result=a-b;很明显这是一个很简单的例子,因为我们只用了两个小的整数数值。但是想一想你的电脑可以同时存储成千上万这样的数值,并进行复杂的数学运算。因此,我们可以将变量(variable)定义为内存的一部分,用以存储一个确定的值。每一个变量(variable)需要一个标识,以便将它与其他变量相区别,例如,在前面的代码中,变量标识是a,b,和result。我们可以给变量起任何名字,只要它们是有效的标识符。5/170标识(Identifiers)有效标识由字母(letter),数字(digits)和下划线(_)组成。标识的长度没有限制,但是有些编译器只取前32个字符(剩下的字符会被忽略)。空格(spaces),标点(punctuationmarks)和符号(symbols)都不可以出现在标识中。只有字母(letters),数字(digits)和下划线(_)是合法的。并且变量标识必须以字母开头。标识也可能以下划线(_)开头,但这种标识通常是保留给为外部连接用的。标识不可以以数字开头。必须注意的另一条规则是当你给变量起名字时不可以和C++语言的关键字或你所使用的编译器的特殊关键字同名,因为这样与这些关键字产生混淆。例如,以下列出标准保留关键字,他们不允许被用作变量标识名称:asm,auto,bool,break,case,catch,char,class,const,const_cast,continue,default,delete,do,double,dynamic_cast,else,enum,explicit,extern,false,float,for,friend,goto,if,inline,int,long,mutable,namespace,new,operator,private,protected,public,register,reinterpret_cast,return,short,signed,sizeof,static,static_cast,struct,switch,template,this,throw,true,try,typedef,typeid,typename,union,unsigned,using,virtual,void,volatile,wchar_t,while另外,不要使用一些操作符的替代表示作为变量标识,因为在某些环境中它们可能被用作保留词:and,and_eq,bitand,bitor,compl,not,not_eq,or,or_eq,xor,xor_eq你的编译器还可能包含一些特殊保留词,例如许多生成16位码的编译器(比如一些DOS编译器)把far,huge和near也作为关键字。非常重要:C++语言是“大小写敏感”(“casesensitive”)的,即同样的名字字母大小写不同代表不同的变量标识。因此,例如变量RESULT,变量result和变量Result分别表示三个不同的变量标识.基本数据类型(FundamentalDatatypes)编程时我们将变量存储在计算机的内存中,但是计算机要知道我们要用这些变量存储什么样的值,因为一个简单的数值,一个字符,或一个巨大的数值在内存所占用的空间是不一样的。6/170计算机的内存是以字节(byte)为单位组织的。一个字节(byte)是我们在C++中能够操作的最小的内存单位。一个字节(byte)可以存储相对较小数据:一个单个的字符或一个小整数(通常为一个0到255之间的整数)。但是计算机可以同时操作处理由多个字节组成复杂数据类型,比如长整数(longintegers)和小数(decimals)。以下列表总结了现有的C++基本数据类型,以及每一类型所能存储的数据范围:数据类型(DATATYPES)名称charshortint(short)longint(long)字节数*12描述字符(character)或整数(integer),8位(bits)长范围*4int4floatdoublelongdoubleboolwchar_t48812有符号(signed):-128到127无符号(unsigned):0到255有符号(signed):-32768到短整数(integer)16位(bits)长32767无符号(unsigned):0到65535有符号(signed):-到长整数(integer)32位(bits)长无符号(unsigned):0到有符号(signed):-到整数(integer)无符号(unsigned):0到3.4e+/-38(7个数字浮点数(floatingpointnumber)(7digits))双精度浮点数(doubleprecision1.7e+/-308(15digits)floatingpointnumber)长双精度浮点数(longdouble1.7e+/-308(15digits)precisionfloatingpointnumber)布尔Boolean值。它只能是真(true)true或false或假(false)两值之一。宽字符(Widecharacter)。这是为一个宽字符(1wide存储两字节(2bytes)长的国际字符characters)而设计的类型。*字节数一列和范围一列可能根据程序编译和运行的系统不同而有所不同。这里列出的数值是多数32位系统的常用数据。对于其他系统,通常的说法是整型(int)具有根据系统结构建议的自然长度(即一个字oneword的长度),而4中整型数据char,short,int,long的长度必须是递增的,也就是说按顺序每一类型必须大于等于其前面一个类型的长度。同样的规则也适用于浮点数类型float,double和longdouble,也是按递增顺序。7/170除以上列出的基本数据类型外,还有指针(pointer)和void参数表示类型,我们将在后面看到。变量的声明(Declarationofvariables)在C++中要使用一个变量必须先声明(declare)该变量的数据类型。声明一个新变量的语法是写出数据类型标识符(例如int,short,float...)后面跟一个有效的变量标识名称。例如:以上两个均为有效的变量声明(variabledeclaration)。第一个声明一个标识为a的整型变量(intvariable),第二个声明一个标识为mynumber的浮点型变量(floatvariable)。声明之后,我们就可以在后面的程序中使用变量a和mynumber了。如果你需要声明多个同一类型的变量,你可以将它们缩写在同一行声明中,在标识之间用逗号(comma)分隔。例如:inta,b,c;以上语句同时定义了a、b、c3个整型变量,它与下面的写法完全等同:整型数据类型(char,short,long和int)可以是有符号的(signed)或无符号的(unsigned),这取决于我们需要表示的数据范围。有符号类型(signed)可以表示正数和负数,而无符号类型(unsigned)只能表示正数和0。在定义一个整型数据变量时可以在数据类型前面加关键字signed或unsigned来声明数据的符号类型。例如:unsignedshortNumberOfSsignedintMyAccountB如果我们没有特别写出signed或unsigned,变量默认为signed,因此以上第二个声明我们也可以写成:intMyAccountB因为以上两种表示方式意义完全一样,因此我们在源程序通常省略关键字signed。8/170唯一的例外是字符型(char)变量,这种变量独立存在,与signedchar和unsignedchar型均不相同。short和long可以被单独用来表示整型基本数据类型,short相当于shortint,long相当于longint。也就是说和两种声明是等价的。最后,signed和unsigned也可以被单独用来表示简单类型,意思分别同signedint和unsignedint相同,即以下两种声明互相等同:unsignedMyBirthYunsignedintMyBirthY下面我们就用C++代码来解决在这一节开头提到的记忆问题,来看一下变量定义是如何在程序中起作用的。//operatingwithvariables#include&iostream.h&intmain(){//declaringvariables:inta,b;//process:a=5;b=2;a=a+1;result=a-b;//printouttheresult:cout&&//terminatetheprogram:return0;}49/170如果以上程序中变量声明部分有你不熟悉的地方,不用担心,我们在后面的章节中很快会学到这些内容。变量的范围(Scopeofvariables)所有我们要使用的变量都必须事先声明过。C和C++语言的一个重要区别是,在C++语言中我们可以在源程序中任何地方声明变量,甚至可以在两个可执行(excutable)语句的中间声明变量,而不象在C语言中变量声明只能在程序的开头部分。然而,我们还是建议在一定程度上遵循C语言的习惯来声明变量,因为将变量声明放在一处对debug程序有好处。因此,传统的C语言方式的变量声明就是把变量声明放在每一个函数(function)的开头(对本地变量localvariable)或直接放在程序开头所有函数(function)的外面(对全局变量globalvariable)。一个变量可以是本地(local)范围内有效,叫做本地变量,也可以是全局(global)范围内有效,叫做全局变量。全局变量要定义在一个源码文件的主体中,所有函数(包括主函数main())之外。而本地变量定义在一个函数甚至只是一个语句块单元中。如下图所示:
全局变量Globalvariables可以在程序中任何地方任何函数(function)中被引用,只要是在变量的声明之后。本地变量localvariables的作用范围被局限在声明它的程序范围内。如果它们是在一个函数的开头被声明的(例如main函数),它们的作用范围就是整个main函数。在左图的例子中,这就意味着如果在main函数外还另有一个函数,main函数中声明的本地变量(Age,ANumber,AnotherOne)不能够被另一个函数使用,反之亦然。在C++中,本地变量(localvariable)的作用范围被定义在声明它的程序块内(一个程序块是被一对花括号(curlybrackets{})括起来的一组语句)。如果变量是在一个函10/170数(function)中被声明的,那么它是一个函数范围内的变量,如果变量是在一个循环中(loop)中被声明的,那么它的作用范围只是在这个循环(loop)之中,以此类推。除本地和全局范围外,还有一种外部范围,它使得一个变量不仅在同一源程序文件中可见,而且在其他所有将被链接在一起的源文件中均可见。变量初始化(Initializationofvariables)当一个本地变量(localvariable)被声明时,它的值默认为未定(undetermined)。但你可能希望在声明变量的同时赋给它一个具体的值。要想达到这个目的,需要对变量进行初始化。C++中有两种初始化方法:第一种,又叫做类C(c-like)方法,是在声明变量的时候加上一个等于号,并在后面跟上想要的数值:typeidentifier=initial_例如,如果我们想声明一个叫做a的int变量并同时赋予它0这个值,我们可以这样写:inta=0;另外一种变量初始化的方法,又叫做构造函数(constructor)初始化,是将初始值用小括号(parenthesis())括起来:typeidentifier(initial_value);例如:inta(0);在C++.中以上两种方法都正确并且两者等同。//变量初始化#include&iostream&intmain()11/1706{inta=5;//初始值为5intb(2);//初始值为2//不确定初始值a=a+3;result=a-b;cout&&return0;}字符串(strings)字符串是用来存储一个以上字符的非数字值的变量。C++提供一个string类来支持字符串的操作,它不是一个基本的数据类型,但是在一般的使用中与基本数据类型非常相似。与普通数据类型不同的一点是,要想声明和使用字符串类型的变量,需要引用头文件&string&,并且使用usingnamespace语句来使用标准名空间(std),如下面例子所示://C++字符串例题#include&iostream&#include&string&intmain(){stringmystring=&Thisisastring&;cout&&return0;}如上面例子所示,字符串变量可以被初始化为任何字符串值,就像数字类型变量可以被初始化为任何数字值一样。以下两种初始化格式对字符串变量都是可以使用的:12/170Thisisastringstringmystring=&Thisisastring&;stringmystring(&Thisisastring&);字符串变量还可以进行其他与基本数据类型变量一样的操作,比如声明的时候不指定初始值,和在运行过程中被重新赋值。//C++字符串例题2#include&iostream&#include&string&intmain(){mystring=&Thisistheinitialstringcontent&;cout&&mystring&&mystring=&Thisisadifferentstringcontent&;cout&&mystring&&return0;}要了解更加详细的C++字符串操作,建议参考Cplusplus上的string类reference。ThisistheinitialstringcontentThisisadifferentstringcontent1.3常量(Constants)一个常量(constant)是一个有固定值的表达式。字(Literals)字是用来在程序源码中表达特定的值。在前面的内容中我们已经用了很多的字来给变量赋予特定的值。例如:a=5;13/170这句代码中5就是一个字常量。字常量(literalconstant)可以被分为整数(IntegerNumbers),浮点数(Floating-PointNumbers),字符(Characters)和字符串(Strings)。整数(IntegerNumbers)1776707-273他们是整型常数,表示十进制整数值。注意表示整型常数时我们不需要些引号(quotes(&))或任何特殊字符。毫无疑问它是个常量:任何时候当我们在程序中写1776,我们指的就是1776这个数值。除十进制整数另外,C++还允许使用八进制(octalnumbers)和十六进制(hexadecimalnumbers)的字常量(literalconstants)。如果我们想要表示一个八进制数,我们必须在它前面加上一个0字符(zerocharacter),而表示十六进制数我们需要在它前面加字符0x(zero,x)。例如以下字常量(literalconstants)互相等值:75//十进制decimal0113//八进制octal0x4b//十六进制hexadecimal所有这些都表示同一个整数:75(seventyfive),分别以十进制数,八进制数和十六进制数表示。像变量一样,常量也是有数据类型的。默认的整数字常量的类型为int型。我们可以通过在后面加字母u或l来迫使它为无符号(unsigned)的类型或长整型(long)。7575u75l75ul////////intunsignedintlongunsignedlong这里后缀u和l可以是大写,也可以是小写。14/170浮点数(FloatingPointNumbers)浮点数以小数(decimals)和/或指数幂(exponents)的形式表示。它们可以包括一个小数点,一个e字符(表示&bytenattheXthheight&,这里X是后面跟的整数值),或两者都包括。3.1596.02e23//6.02x10^10231.6e-19//1.6x10^-193.0//3.0以上是包含小数的以C++表示的4个有效数值。第一个是PI,第二个是Avogadro数之一,第三个是一个电子(electron)的电量(electriccharge)(一个极小的数值)C所有这些都是近似值。最后一个是浮点数字常量表示数3。浮点数的默认数据类型为double。如果你想使用float或longdouble类型,可以在后面加f或l后缀,同样大小写都可以:3.14159L6.02e23f//longdouble//float字符和字符串(Charactersandstrings)此外还有非数字常量,例如:'z''p'&Helloworld&&Howdoyoudo?&前两个表达式表示单独的字符(character),后面两个表示由若干字符组成的字符串(string)。注意在表示单独字符的时候,我们用单引号(singlequotes(')),在表示字符串或多于一个字符的时候我们用双引号(doublequotes(&))。当以常量方式表示单个字符和字符串时,必须写上引号以便把他们和可能的变量标识或保留字区分开,注意以下例子:x'x'15/170x指一个变量名称为x,而'x'指字符常量'x'。字符常量和字符串常量各有特点,例如escapecodes,这些是除此之外无法在源程序中表示的特殊的字符,例如换行符newline(\n)或跳跃符tab(\t)。所有这些符号前面要加一个反斜杠invertedslash(\)。这里列出了这些escapecodes:\n换行符newline\r回车carriagereturn\t跳跃符tabulation\v垂直跳跃verticaltabulation\bbackspace\fpagefeed\a警告alert(beep)\'单引号singlequotes(')\&双引号doublequotes(&)\?问号question(?)\\反斜杠invertedslash(\)例如:'\n''\t'&Left\tRight&&one\ntwo\nthree&另外你可以数字ASCII码表示一个字符,这种表示方式是在反斜杠(\)之后加以8进制数或十六进制数表示的ASCII码。在第一种(八进制octal)表示中,数字必需紧跟反斜杠(例如\23或\40),第二种(十六进制hexacedimal),必须在数字之前写一个x字符(例如\x20或\x4A)。如果每一行代码以反斜杠invertedslash(\)结束,字符串常量可以分多行代码表示:&stringexpressedin\twolines&16/170你还可以将多个被空格blankspace、跳跃符tabulator、换行符newline或其他有效空白符号分隔开的字符串常量连接在一起:&weform&&asingle&&string&&ofcharacters&最后如果我们想让字符串使用宽字符(wchar_t),而不是窄字符(char),可以在常量的前面加前缀L:L&Thisisawidecharacterstring&宽字符通常用来存储非英语字符,比如中文字符,一个字符占两个字节。布尔型常量(BooleanLiterals)布尔型只有两个有效的值:true和false,其数据类型为bool。定义常量Definedconstants(#define)使用预处理器指令#define,你可以将那些你经常使用的常量定义为你自己取的名字而不需要借助于变量。它的格式是:#defineidentifiervalue例如:#definePI3.#defineNEWLINE'\n'#defineWIDTH100以上定义了三个常量。一旦做了这些声明,你可以在后面的程序中使用这些常量,就像使用其它任何常量一样,例如:circle=2*PI*r;cout&&NEWLINE;实际上编译器在遇到#define指令的时候做的只是把任何出现这些常量名(在前面的例子中为PI,NEWLINE或WIDTH)的地方替换成他们被定义为的代码(分别为3.,'\n'和100)。因此,由#define定义的常量被称为宏常量macroconstants。17/170#define指令不是代码语句,它是预处理器指令,因此指令行末尾不需要加分号semicolon(;)。如果你在宏定义行末尾加了分号(;),当预处理器在程序中做常量替换的时候,分号也会被加到被替换的行中,这样可能导致错误。声明常量declaredconstants(const)通过使用const前缀,你可以定义指定类型的常量,就像定义一个变量一样:constintwidth=100;constchartab='\t';constzip=12440;如果没有指定类型(如上面最后例子中最后一行),编译器会假设常量为整型int。1.4操作符/运算符(Operators)前面已经学习了变量和常量,我们可以开始对它们进行操作,这就要用到C++的操作符。有些语言,很多操作符都是一些关键字,比如add,equals等等。C++的操作符主要是由符号组成的。这些符号不在字母表中,但是在所有键盘上都可以找到。这个特点使得C++程序更简洁,也更国际化。运算符是C++语言的基础,所以非常重要。你不需要背下所有这一小节的内容,这些细节知识仅供你以后需要时参考。赋值Assignation(=)赋值运算符的功能是将一个值赋给一个变量。18/170a=5;将整数5赋给变量a。=运算符左边的部分叫做lvalue(leftvalue),右边的部分叫做rvalue(rightvalue)。lvalue必须是一个变量,而右边的部分可以是一个常量,一个变量,一个运算(operation)的结果或是前面几项的任意组合。有必要强调赋值运算符永远是将右边的值赋给左边,永远不会反过来。a=b;将变量b(rvalue)的值赋给变量a(lvalue),不论a当时存储的是什么值。同时考虑到我们只是将b的数值赋给a,以后如果b的值改变了并不会影响到a的值.例如:如果我们使用以下代码(变量值的变化显示在绿色注释部分)://赋值符号例子#include&iostream&intmain(){inta,b;a=10;b=4;a=b;b=7;coutcoutcoutcout&&&&&&&&&a:&;a;&b:&;b;a:4b:7//////////a:?,a:10,a:10,a:4,a:4,b:?b:?b:4b:4b:7return0;}以上代码结果是a的值为4,b的值为7。最后一行中b的值被改变并不会影响到a,虽然在此之前我们声明了a=b;(从右到左规则right-to-leftrule)。C++拥有而其他语言没有的一个特性是赋值符(=)可以被用作另一个赋值符的rvalue(或rvalue的一部分)。例如:19/170a=2+(b=5);等同于:b=5;a=2+b;它的意思是:先将5赋给变量b,然后把前面对b的赋值运算的结果(即5)加上2再赋给变量a,这样最后a中的值为7。因此,下面的表达式在C++中也是正确的:a=b=c=5;//将5同时赋给3个变量a,b和c。数学运算符Arithmeticoperators(+,-,*,/,%)C++语言支持的5种数学运算符为:?????+-*/%加addition减subtraction乘multiplication除division取模module加减乘除运算想必大家都很了解,它们和一般的数学运算符没有区别。唯一你可能不太熟悉的是用百分号(%)表示的取模运算(module)。取模运算是取两个整数相除的余数。例如,如果我们写a=11%3;,变量a的值将会为结果2,因为2是11除以3的余数。组合运算符Compoundassignationoperators(+=,-=,*=,/=,%=,&&=,&&=,&=,^=,|=)C++以书写简练著称的一大特色就是这些组合运算符compoundassignationoperators(+=,-=,*=和/=及其他),这些运算符使得只用一个基本运算符就可改写变量的值:value+=等同于value=value+a-=5;等同于a=a-5;20/170a/=b;等同于a=a/b;price*=units+1;等同于price=price*(units+1);其他运算符以此类推。例如://组合运算符例子#include&iostream&intmain(){inta,b=3;a=b;a+=2;cout&&a;return0;}5//相当于a=a+2递增和递减Increaseanddecrease书写简练的另一个例子是递增(increase)运算符(++)和递减(decrease)运算符(--)。它们使得变量中存储的值加1或减1。它们分别等同于+=1和-=1。因此:a++;a+=1;a=a+1;在功能上全部等同,即全部使得变量a的值加1。它的存在是因为最早的C编译器将以上三种表达式的编译成不同的机器代码,不同的机器代码运行速度不一样。现在,编译器已经基本自动实行代码优化,所以以上三种不同的表达方式编译成的机器代码在实际运行上已基本相同。这个运算符的一个特点是它既可以被用作prefix前缀,也可以被用作后缀suffix,也就是说它既可以被写在变量标识的前面(++a),也可以被写在后面(a++)。虽然在简单表达式如a++或++a中,这两种写法代表同样的意思,但当递增increase或递减decrease的运算结果被直接用在其它的运算式中时,它们就代表非常不同的意思了:当递增运算21/170符被用作前缀prefix(++a)时,变量a的值线增加,然后再计算整个表达式的值,因此增加后的值被用在了表达式的计算中;当它被用作后缀suffix(a++)时,变量a的值在表达式计算后才增加,因此a在增加前所存储的值被用在了表达式的计算中。注意以下两个例子的不同:例1例2B=3;B=3;A=++B;A=B++;//A的值为4,B的值为4//A的值为3,B的值为4在第一个例子中,B在它的值被赋给A之前增加1。而在第二个例子中B原来的值3被赋给A然后B的值才加1变为4。关系运算符Relationaloperators(==,!=,&,&,&=,&=)我们用关系运算符来比较两个表达式。如ANSI-C++标准中指出的,关系预算的结果是一个bool值,根据运算结果的不同,它的值只能是真true或false。例如我们想通过比较两个表达式来看它们是否相等或一个值是否比另一个的值大。以下为C++的关系运算符:==相等Equal!=不等Different&&大于Greaterthan小于Lessthan&=大于等于Greaterorequalthan&=小于等于Lessorequalthan下面你可以看到一些实际的例子:(7==5)将返回false.(5&4)将返回true.(3!=2)将返回true.(6&=6)将返回true.22/170(5&5)将返回false.当然,除了使用数字常量,我们也可以使用任何有效表达式,包括变量。假设有a=2,b=3和c=6,(a==5)将返回false.(a*b&=c)将返回true因为它实际是(2*3&=6)(b+4&a*c)将返回false因为它实际是(3+4&2*6)((b=2)==a)将返回true.注意:运算符=(单个等号)不同于运算符==(双等号)。第一个是赋值运算符(将等号右边的表达式值赋给左边的变量);第二个(==)是一个判断等于的关系运算符,用来判断运算符两边的表达式是否相等。因此在上面例子中最后一个表达式((b=2)==a),我们首先将数值2赋给变量b,然后把它和变量a进行比较。因为变量a中存储的也是数值2,所以整个运算的结果为true。在ANSI-C++标准出现之前的许多编译器中,就像C语言中,关系运算并不返回值为真true或假false的bool值,而是返回一个整型数值最为结果,它的数值可以为0,代表&false&或一个非0数值(通常为1)来代表&true&。逻辑运算符Logicoperators(!,&&,||)运算符!等同于boolean
运算NOT(取非),它只有一个操作数(operand),写在它的右边。它做的唯一工作就是取该操作数的反面值,也就是说如果操作数值为真true,那么运算后值变为假false,如果操作数值为假false,则运算结果为真true。它就好像是说取与操作数相反的值。例如:!(5==5)返回false,因为它右边的表达式(5==5)为真true.!(6&=4)返回true因为(6&=4)为假false.!true!false23/170返回假false.返回真true.逻辑运算符&&和||是用来计算两个表达式而获得一个结果值。它们分别对应逻辑运算中的与运算AND和或运算OR。它们的运算结果取决于两个操作数(operand)的关系:第一个操作数第二个操作数结果结果aba&&ba||btruetruefalsefalse例如:((5==5)&&(3&6))返回false(true&&false).((5==5)||(3&6))返回true(true||false).truefalsetruefalsetruefalsefalsefalsetruetruetruefalse条件运算符Conditionaloperator(?)条件运算符计算一个表达式的值并根据表达式的计算结果为真true或假false而返回不同值。它的格式是:condition?result1:result2(条件?返回值1:返回值2)如果条件condition为真true,整个表达式将返回esult1,否则将返回result2。7==5?4:3返回3,因为7不等于5.7==5+2?4:3返回4,因为7等于5+2.5&3?a:ba&b?a:b返回a,因为5大于3.返回较大值,a或b.//条件运算符例子#include&iostream&intmain(){24/1707inta,b,c;a=2;b=7;c=(a&b)?a:b;cout&&c;return0;}上面的例子中a的值为2,b的值为7,所以表达式(a&b)运算值为假(false),所以整个表达式(a&b)?a:b要取分号后面的值,也就是b的值7。因此最后输出c的值为7。逗号运算符(,)逗号运算符(,)用来分开多个表达式,并只取最右边的表达式的值返回。例如有以下代码:a=(b=3,b+2);这行代码首先将3赋值给变量b,然后将b+2赋值给变量a。所以最后变量a的值为5,而变量b的值为3。位运算符BitwiseOperators(&,|,^,~,&&,&&)位运算符以比特位改写变量存储的数值,也就是改写变量值的二进制表示:opasm&|^~AND逻辑与LogicANDOR逻辑或LogicORDescriptionXOR逻辑异或LogicalexclusiveORNOT对1取补(位反转)Complementtoone(bitinversion)&&SHL左移ShiftLeft25/170&&SHR右移ShiftRight变量类型转换运算符Explicittypecastingoperators变量类型转换运算符可以将一种类型的数据转换为另一种类型的数据。在写C++中有几种方法可以实现这种操作,最常用的一种,也是与C兼容的一种,是在原转换的表达式前面加用括号()括起的新数据类型:floatf=3.14;i=(int)f;以上代码将浮点型数字3.14转换成一个整数值(3)。这里类型转换操作符为(int)。在C++中实现这一操作的另一种方法是使用构造函数constructor的形式:在要转换的表达式前加变量类型并将表达式括在括号中:i=int(f);以上两种类型转换的方法在C++中都是合法的。另外ANSI-C++针对面向对象编程(objectorientedprogramming)增加了新的类型转换操作符(参考Section5.4,Advancedclasstype-casting).sizeof()这个运算符接受一个输入参数,该参数可以是一个变量类型或一个变量自己,返回该变量类型(variabletype)或对象(object)所占的字节数:a=sizeof(char);这将会返回1给a,因为char是一个常为1个字节的变量类型。sizeof返回的值是一个常数,因此它总是在程序执行前就被固定了。其它运算符在本教程后面的章节里我们将看到更多的运算符,比如指向指针的运算或面向对象编程特有的运算,等等,我们会在它们各自的章节里进行详细讨论。26/170运算符的优先度Precedenceofoperators当多个操作数组成复杂的表达式时,我们可能会疑惑哪个运算先被计算,哪个后被计算。例如以下表达式:a=5+7%2我们可以怀疑它实际上表示:a=5+(7%2)结果为6,还是a=(5+7)%2结果为0?正确答案为第一个,结果为6。每一个运算符有一个固定的优先级,不仅对数学运算符(我们可能在学习数学的时候已经很了解它们的优先顺序了),所有在C++中出现的运算符都有优先级。从最从最高级到最低级,运算的优先级按下表排列:优先级Level12::()[].-&++--dynamic_caststatic_castreinterpret_castconst_casttypeid++--~!sizeofnewdelete2131427/170操作符Operator说明结合方向DescriptionGrouping范围后缀一元(前缀)指针和取地址从右到左一元符号类型转换从右到左指向成员的指从左到右针乘、除、取模从左到右加减位移关系操作符按位与运算按位或运算逻辑与运算从左到右从左到右从左到右从左到右从左到右从左到右从左到右从左到右*&+-(type).*-&**/%+-&&&&&&&=&===!=&^|&&等于、不等于从左到右按位异或运算从左到右15161718||?:=*=/=%=+=-=&&=&&=&=^=|=,逻辑或运算条件运算赋值运算逗号从左到右从右到左从右到左从左到右结合方向Grouping定义了当有同优先级的多个运算符在一起时,哪一个必须被首先运算,最右边的还是最左边的。所有这些运算符的优先级顺序可以通过使用括号parenthesissigns(和)来控制,而且更易读懂,例如以下例子:a=5+7%2;根据我们想要实现的计算的不同,可以写成:a=5+(7%2);或者a=(5+7)%2;所以如果你想写一个复杂的表达式而不敢肯定各个运算的执行顺序,那么就加上括号。这样还可以使代码更易读懂。1.5控制台交互(Communicationthroughconsole)控制台(console)是电脑的最基本交互接口,通常包括键盘(keyboard)和屏幕(screen)。键盘通常为标准输入设备,而屏幕为标准输出设备。在C++的iostream函数库中,一个程序的标准输入输出操作依靠两种数据流:cin给输入使用和cout给输出使用。另外,cerr和clog也已经被实现DD它们是两种特殊设计的数据流专门用来显示出错信息。它们可以被重新定向到标准输出设备或到一个日志文件(logfile)。因此cout(标准输出流)通常被定向到屏幕,而cin(标准输入流)通常被定向到键盘。通过控制这两种数据流,你可以在程序中与用户交互,因为你可以在屏幕上显示输出并从键盘接收用户的输入。28/170输出Output(cout)输出流cout与重载(overloaded)运算符&&一起使用:cout&&&Outputsentence&;//打印Outputsentence到屏幕上cout&&120;//打印数字120到屏幕上cout&&x;//打印变量x的值到屏幕上运算符&&又叫插入运算符(insertionoperator)因为它将后面所跟的数据插入到它前面的数据流中。在以上的例子中,字符串常量Outputsentence,数字常量120和变量x先后被插入输出流cout中。注意第一句中字符串常量是被双引号引起来的。每当我们使用字符串常量的时候,必须用引号把字符串引起来,以便将它和变量名明显的区分开来。例如,下面两个语句是不同的:cout&&&Hello&;//打印字符串Hello到屏幕上cout&&H//把变量Hello存储的内容打印到屏幕上插入运算符insertionoperator(&&)可以在同一语句中被多次使用:cout&&&Hello,&&&&Iam&&&&aC++sentence&;上面这一行语句将会打印Hello,IamaC++sentence到屏幕上。插入运算符(&&)的重复使用在我们想要打印变量和内容的组合内容或多个变量时有所体现:cout&&&Hello,Iam&&&age&&&yearsoldandmyzipcodeis&&&如果我们假设变量age的值为24,变量zipcode的值为90064,以上句子的输出将为:Hello,Iam24yearsoldandmyzipcodeis90064必须注意,除非我们明确指定,cout并不会自动在其输出内容的末尾加换行符,因此下面的语句:cout&&&Thisisasentence.&;cout&&&Thisisanothersentence.&;将会有如下内容输出到屏幕:Thisisasentence.Thisisanothersentence.虽然我们分别调用了两次cout,两个句子还是被输出在同一行。所以,为了在输出中换行,我们必须插入一个换行符来明确表达这一要求。在C++中换行符可以写作\n:29/170cout&&&Firstsentence.\n&;cout&&&Secondsentence.\nThirdsentence.&;将会产生如下输出:Firstsentence.Secondsentence.Thirdsentence.另外,你也可以用操作符endl来换行,例如:cout&&&Firstsentence.&&&cout&&&Secondsentence.&&&将会输出:Firstsentence.Secondsentence.当操作符endl被用在bufferedstreams中时有一点特殊:它们被flushed。不过cout默认为unbuffered,所以不会被影响。你可以暂时不管这一点。你可以使用\n或endl来指定cout输出换行,请注意前面所讲的两者的不同用法。输入Input(cin)C++中的标准输入是通过在cin数据流上重载运算符extraction(&&)来实现的。它后面必须跟一个变量以便存储读入的数据。例如:cin&&声明一个整型变量age然后等待用户从键盘输入到cin并将输入值存储在这个变量中。cin只能在键盘输入回车键(RETURN)后才能处理前面输入的内容。因此即使你只要求输入一个单独的字符,在用户按下回车键(RETURN)之前cin将不会处理用户的输入的字符。在使用cin输入的时候必须考虑后面的变量类型。如果你要求输入一个整数,extraction(&&)后面必须跟一个整型变量,如果要求一个字符,后面必须跟一个字符型变量,如果要求一个字符串,后面必须跟一个字符串型变量。//i/oexample30/170Pleaseenteraninteger#include&iostream.h&intmain(){cout&&&Pleaseenteranintegervalue:&;cin&&i;cout&&&Thevalueyouenteredis&&&i;cout&&&anditsdoubleis&&&i*2&&&.\n&;return0;}value:702Thevalueyouenteredis702anditsdoubleis1404.使用程序的用户可以使引起错误的原因之一,即使是在最简单的需要用cin做输入的程序中(就像我们上面看到的这个程序)。因为如果你要求输入一个整数数值,而用户输入了一个名字(一个字符串),其结果可能导致程序产生错误操作,因为它不是我们期望从用户处获得的数据。当你使用由cin输入的数据的时候,你不得不假设程序的用户将会完全合作而不会在程序要求输入整数的时候输入他的名字。后面当我们看到怎样使用字符串的时候,我们将会同时看到一些解决这一类出错问题的办法。你也可以利用cin要求用户输入多个数据:cin&&a&&b;等同于:cin&&a;cin&&b;在以上两种情况下用户都必须输入两个数据,一个给变量a,一个给变量b。输入时两个变量之间可以以任何有效的空白符号间隔,包括空格,跳跃符tab或换行。cin和字符串我们可以像读取基本类型数据一样,使用cin和&&操作符来读取字符串,例如:cin&&但是,cin&&只能读取一个单词,一旦碰到任何空格,读取操作就会停止。在很多时候这并不是我们想要的操作,比如我们希望用户输入一个英文句子,那么这种方法就无法读取完整的句子,因为一定会遇到空格。31/170要一次读取一整行输入,需要使用C++的函数getline,相对于是用cin,我们更建议使用getline来读取用户输入。例如://读取字符串例子#include&iostream&#include&string&intmain(){cout&&&What'syourname?&;getline(cin,mystr);cout&&&Hello&&&mystr&&&.\n&;cout&&&Whatisyourfavoritecolor?&;getline(cin,mystr);cout&&&Ilike&&&mystr&&&too!\n&;return0;}你可能注意到在上面的例子中,两次调用getline函数我们都是用了同一个字符串变量(mystr)。在第二次调用的时候,程序会自动用第二次输入的内容取代以前的内容。What'syourname?AquaHelloAqua.Whatisyourfavoritecolor?blueIlikebluetoo!字符串流(stringstream)标准头文件&sstream&定义了一个叫做stringstream的类,使用这个类可以对基于字符串的对象进行像流(stream)一样的操作。这样,我们可以对字符串进行抽取和插入操作,这对将字符串与数值互相转换非常有用。例如,如果我们想将一个字符串转换为一个整数,可以这样写:stringmystr(&1204&);stringstream(mystr)&&这个例子中先定义了一个字符串类型的对象mystr,初始值为&1204&,又定义了一个整数变量myint。然后我们使用stringstream类的构造函数定义了这个类的对象,并以字符串变量mystr为参数。因为我们可以像使用流一样使用stringstream的对象,所32/170以我们可以像使用cin那样使用操作符&&后面跟一个整数变量来进行提取整数数据。这段代码执行之后变量myint存储的是数值1204。//字符串流的使用示例#include&iostream&#include&string&#include&sstream&intmain(){floatprice=0;intquantity=0;cout&&&Enterprice:&;getline(cin,mystr);stringstream(mystr)&&cout&&&Enterquantity:&;getline(cin,mystr);stringstream(mystr)&&cout&&&Totalprice:&&&price*quantity&&return0;}在这个例子中,我们要求用户输入数值,但不同于从标准输入中直接读取数值,我们使用函数getline从标注输入流cin中读取字符串对象(mystr),然后再从这个字符串对象中提取数值price和quantity。通过使用这种方法,我们可以对用户的输入有更多的控制,因为它将用户输入与对输入的解释分离,只要求用户输入整行的内容,然后再对用户输入的内容进行检验操作。这种做法在用户输入比较集中的程序中是非常推荐使用的。Enterprice:22.25Enterquantity:7Totalprice:155.7533/1702.1控制结构(ControlStructures)一个程序的语句往往并不仅限于线性顺序结构。在程序的执行过程中它可能被分成两支执行,可能重复某些语句,也可能根据一些判断结果而执行不同的语句。因此C++提供一些控制结构语句(controlstructures)来实现这些执行顺序。为了介绍程序的执行顺序,我们需要先介绍一个新概念:语句块(blockofinstructions)。一个语句块(Ablockofinstructions)是一组互相之间由分号semicolons(;)分隔开但整体被花括号curlybracketsigns:{and}括起来的语句。本节中我们将看到的大多数控制结构允许一个通用的statement做参数,这个statement根据需要可以是一条语句,也可以是一组语句组成的语句块。如果我们只需要一条语句做statement,它可以不被括在花括号({})内。但如果我们需要多条语句共同做statement,则必须把它们括在花括号内({})以组成一个语句块。34/170条件结构Conditionalstructure:ifandelse条件结构用来实现仅在某种条件满足的情况下才执行一条语句或一个语句块。它的形式是:if(condition)statement这里condition是一个将被计算的表达式(expression)。如果表达式值为真,即条件(condition)为true,statement将被执行。否则,statement将被忽略(不被执行),程序从整个条件结构之后的下一条语句继续执行。例如,以下程序段实现只有当变量x存储的值确实为100的时候才输出&xis100&:if(x==100)cout&&&xis100&;如果我们需要在条件condition为真true的时候执行一条以上的语句,我们可以花括号{}将语句括起来组成一个语句块:if(x==100){cout&&&xis&;cout&&x;}我们可以用关键字else来指定当条件不能被满足时需要执行的语句,它需要和if一起使用,形式是:if(condition)statement1elsestatement2例如:if(x==100)cout&&&xis100&;elsecout&&&xisnot100&;以上程序如果x的值为100,则在屏幕上打出xis100,如果x不是100,而且也只有在x不是100的时候,屏幕上将打出xisnot100。35/170多个if+else的结构被连接起来使用来判断数值的范围。以下例子显示了如何用它来判断变量x中当前存储的数值是正值,负值还是既不正也不负,即等于0。if(x&0)cout&&&xispositive&;elseif(x&0)cout&&&xisnegative&;elsecout&&&xis0&;记住当我们需要执行多条语句时,必须使用花括号{}将它们括起来以组成一个语句块blockofinstructions。重复结构Iterationstructures或循环loops循环Loops的目的是重复执行一组语句一定的次数或直到满足某种条件。while循环格式是:while(表达式expression)语句statement它的功能是当expression的值为真true时重复执行statement。例如,下面我们将用while循环来写一个倒计数程序://customcountdownusingwhile#include&iostream.h&intmain(){cout&&&Enterthestartingnumber&&;cin&&n;while(n&0){cout&&n&&&,&;--n;}cout&&&FIRE!&;36/170Enterthestartingnumber&88,7,6,5,4,3,2,1,FIRE!return0;}程序开始时提示用户输入一个倒计数的初始值。然后while循环开始,如果用户输入的数值满足条件n&0(即n比0大),后面跟的语句块将会被执行一定的次数,直到条件(n&0)不再满足(变为false)。以上程序的所有处理过程可以用以下的描述来解释:从main开始:1.用户输入一个数值赋给n.2.while语句检查(n&0)是否成立,这时有两种可能:otrue:执行statement(到第3步)ofalse:跳过statement.程序直接执行第5步.3.执行statement:cout&&n&&&,&;--n;(将n的值打印在屏幕上,然后将n的值减1).4.语句块结束,自动返回第2步。5.继续执行语句块之后的程序:打印FIRE!,程序结束。我们必须考虑到循环必须在某个点结束,因此在语句块之内(loop的statement之内)我们必须提供一些方法使得条件condition可以在某个时刻变为假false,否则循环将无限重复下去。在这个例子里,我们用语句--n;使得循环在重复一定的次数后变为false:当n变为0,倒计数结束。do-while循环格式:do语句statementwhile(条件condition);它的功能与while循环一抹一样,除了在do-while循环中是先执行statement然后才检查条件condition,而不想while循环中先检查条件然后才执行statement。这样,即使条件condition从来没有被满足过,statement仍至少被执行一次。例如,下面的程序重复输出(echoes)用户输入的任何数值,直到用户输入0为止。37/170//numberechoer#include&iostream.h&intmain(){do{cout&&&Enternumber(0toend):&;cin&&n;cout&&&Youentered:&&&n&&&\n&;}while(n!=0);return0;}Enternumber(0toend):12345Youentered:12345Enternumber(0toend):160277Youentered:160277Enternumber(0toend):0Youentered:0do-while循环通常被用在判断循环结束的条件是在循环语句内部被决定的情况下,比如以上的例子,在循环的语句块内用户的输入决定了循环是否结束。如果用户永远不输入0,则循环永远不会结束。for循环格式是:for(increase)它的主要功能是当条件condition为真true时重复执行语句statement,类似while循环。但除此之外,for还提供了写初始化语句initialization和增值语句increase的地方。因此这种循环结构是特别为执行由计数器控制的循环而设计的。它按以下方式工作:1.执行初始化initialization。通常它是设置一个计数器变量(countervariable)的初始值,初始化仅被执行一次。2.检查条件condition,如果条件为真true,继续循环,否则循环结束循环中语句statement被跳过。3.执行语句statement。像以前一样,它可以是一个单独的语句,也可以是一个由花括号{}括起来的语句块。4.最后增值域(increasefield)中的语句被执行,循环返回第2步。注意增值域中可能是任何语句,而不一定只是将计数器增加的语句。例如下面的例子中计数器实际为减1,而不是加1。下面是用for循环实现的倒计数的例子:38/170//countdownusingaforloop#include&iostream.h&intmain(){for(intn=10;n&0;n--){cout&&n&&&,&;}cout&&&FIRE!&;return0;}10,9,8,7,6,5,4,3,2,1,FIRE!初始化initialization和增值increase域是可选的(即可以为空)。但这些域为空的时候,它们和其他域之间间隔的分号不可以省略。例如我们可以写:for(;n&10;)来表示没有初始化和增值语句;或for(;n&10;n++)来表示有增值语句但没有初始化语句。另外我们也可以在for循环初始化或增值域中放一条以上的语句,中间用逗号coma(,)隔开。例如假设我们想在循环中初始化一个以上的变量,可以用以下的程序来实现:for(n=0,i=100;n!=i;n++,i--){//whateverhere...}这个循环将被执行50次,如果n和i
在循还内部都不被改变的话:n初始值为0,i初始值为100,条件是(n!=i)(即n不能等于i)。因为每次循环n加1,而且i减1,循环的条件将会在第50次循环之后变为假false(n和i都等于50)。分支控制和跳转(Bifurcationofcontrolandjumps)break语句通过使用break语句,即使在结束条件没有满足的情况下,我们也可以跳出一个循环。它可以被用来结束一个无限循环(infiniteloop),或强迫循环在其自然结束之前结束。例如,我们想要在倒计数自然结束之前强迫它停止(也许因为一个引擎故障):39/170//breakloopexample#include&iostream.h&intmain(){for(n=10;n&0;n--){cout&&n&&&,&;if(n==3){cout&&&countdownaborted!&;}return0;}10,9,8,7,6,5,4,3,countdownaborted!continue语句continue语句使得程序跳过当前循环中剩下的部分而直接进入下一次循环,就好像循环中语句块的结尾已经到了使得循环进入下一次重复。例如,下面例子中倒计数时我们将跳过数字5的输出://continueloopexample#include&iostream.h&intmain(){for(intn=10;n&0;n--){if(n==5)cout&&n&&&,&;}cout&&&FIRE!&;return0;}10,9,8,7,6,4,3,2,1,FIRE!goto语句通过使用goto语句可以使程序从一点跳转到另外一点。你必须谨慎只用这条语句,因为它的执行可以忽略任何嵌套限制。40/170跳转的目标点可以由一个标示符(label)来标明,该标示符作为goto语句的参数。一个标示符(label)由一个标识名称后面跟一个冒号colon(:)组成。通常除了底层程序爱好者使用这条语句,它在结构化或面向对象的编程中并不常用。下面的例子中我们用goto来实现倒计数循环://gotoloopexample#include&iostream.h&intmain(){intn=10;loop:cout&&n&&&,&;n--;if(n&0)cout&&&FIRE!&;return0;}10,9,8,7,6,5,4,3,2,1,FIRE!exit函数exit是一个在cstdlib(stdlib.h)库中定义的函数。exit的目的是一个特定的退出代码来结束程序的运行,它的原型(prototype)是:voidexit(intexitcode);exitcode是由操作系统使用或被调用程序使用。通常exitcode为0表示程序正常结束,任何其他值表示程序执行过程中出现了错误。选择结构TheselectiveStructure:switchswitch语句的语法比较特殊。它的目标是对一个表达式检查多个可能常量值,有些像我们在本节开头学习的把几个if和elseif语句连接起来的结构。它的形式是:switch(expression){caseconstant1:blockofinstructions141/170caseconstant2:blockofinstructions2...default:defaultblockofinstructions}它按以下方式执行:switch计算表达式expression的值,并检查它是否与第一个常量constant1相等,如果相等,程序执行常量1后面的语句块blockofinstructions1直到碰到关键字break,程序跳转到switch选择结构的结尾处。如果expression不等于constant1,程序检查表达式expression的值是否等于第二个常量constant2,如果相等,程序将执行常量2后面的语句块blockofinstructions2直到碰到关键字break。依此类推,直到最后如果表达式expression的值不等于任何前面的常量(你可以用case语句指明任意数量的常量值来要求检查),程序将执行默认区default:后面的语句,如果它存在的话。default:选项是可以省略的。下面的两段代码段功能相同:switchexampleswitch(x){case1:cout&&&xis1&;case2:cout&&&xis2&;default:cout&&&valueofxunknown&;}if-elseequivalentif(x==1){cout&&&xis1&;}elseif(x==2){cout&&&xis2&;}else{cout&&&valueofxunknown&;}前面已经提到switch的语法有点特殊。注意每个语句块结尾包含的break语句。这是必须的,因为如果不这样做,例如在语句块blockofinstructions1的结尾没有break,42/170程序执行将不会跳转到switch选择的结尾处(}),而是继续执行下面的语句块,直到第一次遇到break语句或到switch选择结构的结尾。因此,不需要在每一个case域内加花括号{}。这个特点同时可以帮助实现对不同的可能值执行相同的语句块。例如:switch(x){case1:case2:case3:cout&&&xis1,2or3&;default:cout&&&xisnot1,2nor3&;}注意switch只能被用来比较表达式和不同常量的值constants。因此我们不能够把变量或范围放在case之后,例如(case(n*2):)或(case(1..3):)都不可以,因为它们不是有效的常量。如果你需要检查范围或非常量数值,使用连续的if和elseif语句。2.2函数I(FunctionsI)通过使用函数(functions)我们可以把我们的程序以更模块化的形式组织起来,从而利用C++所能提供的所有结构化编程的潜力。一个函数(function)是一个可以从程序其它地方调用执行的语句块。以下是它的格式:typename(argument1,argument2,...)statement43/170这里:????type是函数返回的数据的类型name是函数被调用时使用的名argument是函数调用需要传入的参量(可以声明任意多个参量)。每个参量(argument)由一个数据类型后面跟一个标识名称组成,就像变量声明中一样(例如,intx)。参量仅在函数范围内有效,可以和函数中的其它变量一样使用,它们使得函数在被调用时可以传入参数,不同的参数用逗号(comma)隔开.statement是函数的内容。它可以是一句指令,也可以是一组指令组成的语句块。如果是一组指令,则语句块必须用花括号{}括起来,这也是我们最常见到情况。其实为了使程序的格式更加统一清晰,建议在仅有一条指令的时候也使用花括号,这是一个良好的编程习惯。下面看一下第一个函数的例子://functionexample#include&iostream.h&intaddition(inta,intb){r=a+b;return(r);}intmain(){z=addition(5,3);cout&&&Theresultis&&&z;return0;}记得在我们教程开始时说过:一个C++程序总是从main函数开始执行。因此我们从那里开始。我们可以看到main函数以定义一个整型变量z开始。紧跟着我们看到调用addition函数。我们可以看到函数调用的写法和上面函数定义本身十分相似:Theresultis844/170参数有明显的对应关系。在main函数中我们调用addition函数,并传入两个数值:5和3,它们对应函数addition中定义的参数inta和intb。当函数在main中被调用时,程序执行的控制权从main转移到函数addition。调用传递的两个参数的数值(5和3)被复制到函数的本地变量(localvariables)inta和intb中。函数addition中定义了新的变量(),通过表达式r=a+b;,它把a加b的结果赋给r。因为传过来的参数a和b的值分别为5和3,所以结果是8。下面一行代码:return(r);结束函数addition,并把控制权交还给调用它的函数(main),从调用addition的地方开始继续向下执行。另外,return在调用的时候后面跟着变量r(return(r);),它当时的值为8,
这个值被称为函数的返回值。函数返回的数值就是函数的计算结果,因此,z将存储函数addition(5,3)返回的数值,即8。用另一种方式解释,你也可以想象成调用函数(addition(5,3))被替换成了它的返回值(8)。接下来main中的下一行代码是:cout&&&Theresultis&&&z;它把结果打印在屏幕上。45/170变量的范围(Scopeofvariables)你必须考虑到变量的范围只是在定义该变量的函数或指令块内有效,而不能在它的函数或指令块之外使用。例如,在上面的例子里就不可能在main中直接使用变量a,b或r,因为它们是函数addition的本地变量(localvariable)。在函数addition中也不可能直接使用变量z,因为它是main的本地变量。因此,本地变量(localvariables)的范围是局限于声明它的嵌套范围之内的。尽管如此,你还可以定义全局变量(globalvariables),它们可以在代码的任何位置被访问,不管在函数以内还是以外。要定义全局变量,你必须在所有函数或代码块之外定义它们,也就是说,直接在程序体中声明它们。这里是另一个关于函数的例子://functionexample#include&iostream.h&intsubtraction(inta,intb){r=a-b;return(r);}intmain(){intx=5,y=3,z;z=subtraction(7,2);cout&&&Thefirstresultis&&&z&&'\n';cout&&&Thesecondresultis&&&subtraction(7,2)&&'\n';46/170TheTheTheThefirstresultis5secondresultis5thirdresultis2fourthresultis6cout&&&Thethirdresultis&&&subtraction(x,y)&&'\n';z=4+subtraction(x,y);cout&&&Thefourthresultis&&&z&&'\n';return0;}在这个例子中,我们定义了函数subtraction。这个函数的功能是计算传入的两个参数的差值并将结果返回。在main函数中,函数subtraction被调用了多次。我们用了几种不同的调用方法,因此你可以看到在不同的情况下函数如何被调用。为了更好的理解这些例子,你需要考虑到被调用的函数其实完全可以由它所返回的值来代替。例如在上面例子中第一种情况下(这种调用你应该已经知道了,因为我们在前面的例子中已经用过这种形式的调用):z=subtraction(7,2);cout&&&Thefirstresultis&&&z;如果我们把函数调用用它的结果(也就是5)替换,我们将得到:z=5;cout&&&Thefirstresultis&&&z;同样的cout&&&Thesecondresultis&&&subtraction(7,2);与前面的调用有同样的结果,但在这里我们把对函数subtraction的调用直接用作cout的参数。这可以简单想象成我们写的是:cout&&&Thesecondresultis&&&5;因为5是subtraction(7,2)的结果。在cout&&&Thethirdresultis&&&subtraction(x,y);47/170中,与前面的调用唯一的不同之处是这里调用subtraction时的参数使用的是变量而不是常量。这样用时毫无问题的。在这个例子里,传入函数subtraction的参数值是变量x和y中存储的数值,即分别为5和3,结果为2。第四种调用也是一样的。只要知道除了z=4+subtraction(x,y);我们也可以写成:z=subtraction(x,y)+4;它们的结果是完全一样的。注意在整个表达式的结尾写上分号semicolonsign(;)。它并不需要总是跟在函数调用的后面,因为你可以有一次把它们想象成函数被它的结果所替代:z=4+2;z=2+4;没有返回值类型的函数,使用void.如果你记得函数声明的格式:typename(argument1,argument2...)statement就会知道函数声明必须以一个数据类型(type)开头,它是函数由return语句所返回数据类型。但是如果我们并不打算返回任何数据那该怎么办呢?假设我们要写一个函数,它的功能是打印在屏幕上打印一些信息。我们不需要它返回任何值,而且我们也不需要它接受任何参数。C语言为这些情况设计了void类型。让我们看一下下面的例子://void函数示例#include&iostream&voidprintmessage(){cout&&&I'mafunction!&;}I'mafunction!48/170intmain(){printmessage();return0;}void还可以被用在函数参数位置,表示我们明确希望这个函数在被调用时不需要任何参数。例如上面的函数printmessage也可以写为以下形式:voidprintmessage(void){cout&&&I'mafunction!&;}虽然在C++中void可以被省略,我们还是建议写出void,以便明确指出函数不需要参数。你必须时刻知道的是调用一个函数时要写出它的名字并把参数写在后面的括号内。但如果函数不需要参数,后面的括号并不能省略。因此调用函数printmessage的格式是printmessage();函数名称后面的括号就明确表示了它是一个函数调用,而不是一个变量名称或其它什么语句。以下调用函数的方式就不对:2.3函数II(FunctionsII)49/170参数按数值传递和按地址传递(Argumentspassedbyvalueandbyreference)到目前为止,我们看到的所有函数中,传递到函数中的参数全部是按数值传递的(byvalue)。也就是说,当我们调用一个带有参数的函数时,我们传递到函数中的是变量的数值而不是变量本身。例如,假设我们用下面的代码调用我们的第一个函数addition:intx=5,y=3,z;z=addition(x,y);在这个例子里我们调用函数addition同时将x和y的值传给它,即分别为5和3,而不
是两个变量:这样,当函数addition被调用时,它的变量a和b的值分别变为5和3,但在函数addition内对变量a或b所做的任何修改不会影响变量他外面的变量x和y的值,因为变量x和y并没有把它们自己传递给函数,而只是传递了他们的数值。但在某些情况下你可能需要在一个函数内控制一个函数以外的变量。要实现这种操作,我们必须使用按地址传递的参数(argumentspassedbyreference),就象下面例子中的函数duplicate://passingparametersbyreference#include&iostream.h&voidduplicate(int&a,int&b,int&c){a*=2;b*=2;c*=2;}intmain(){intx=1,y=3,z=7;duplicate(x,y,z);50/170x=2,y=6,z=14cout&&&x=&&&x&&&,y=&&&y&&&,z=&&&z;return0;}第一个应该注意的事项是在函数duplicate的声明(declaration)中,每一个变量的类型后面跟了一个地址符ampersandsign(&),它的作用是指明变量是按地址传递的(byreference),而不是像通常一样按数值传递的(byvalue)。当按地址传递(passbyreference)一个变量的时候,我们是在传递这个变量本身,我
们在函数中对变量所做的任何修改将会影响到函数外面被传递的变量。用另一种方式来说,我们已经把变量a,b,c和调用函数时使用的参数(x,y和z)联系起来了,因此如果我们在函数内对a进行操作,函数外面的x值也会改变。同样,任何对b的改变也会影响y,对c的改变也会影响z&。这就是为什么上面的程序中,主程序main中的三个变量x,y和z在调用函数duplicate后打印结果显示他们的值增加了一倍。如果在声明下面的函数:voidduplicate(int&a,int&b,int&c)时,我们是按这样声明的:voidduplicate(inta,intb,intc)也就是不写地址符ampersand(&),我们也就没有将参数的地址传递给函数,而是传递了它们的值,因此,屏幕上显示的输出结果x,y,z的值将不会改变,仍是1,3,7。这种用地址符ampersand(&)来声明按地址&byreference&传递参数的方式只是在C++中适用。在C语言中,我们必须用指针(pointers)来做相同的操作。按地址传递(Passingbyreference)是一个使函数返回多个值的有效方法。例如,下面是一个函数,它可以返回第一个输入参数的前一个和后一个数值。//morethanonereturningvalue51/170Previous=99,Next=101#include&iostream.h&voidprevnext(intx,int&prev,int&next){prev=x-1;next=x+1;}intmain(){intx=100,y,z;prevnext(x,y,z);cout&&&Previous=&&&y&&&,Next=&&&z;return0;}参数的默认值(Defaultvaluesinarguments)当声明一个函数的时候我们可以给每一个参数指定一个默认值。如果当函数被调用时没有给出该参数的值,那么这个默认值将被使用。指定参数默认值只需要在函数声明时把一个数值赋给参数。如果函数被调用时没有数值传递给该参数,那么默认值将被使用。但如果有指定的数值传递给参数,那么默认值将被指定的数值取代。例如://defaultvaluesinfunctions#include&iostream.h&intdivide(inta,intb=2){r=a/b;return(r);}intmain(){cout&&divide(12);cout&&cout&&divide(20,4);return0;}我们可以看到在程序中有两次调用函数divide。第一次调用:52/17065divide(12)只有一个参数被指明,但函数divide允许有两个参数。因此函数divide假设第二个参数的值为2,因为我们已经定义了它为该参数缺省的默认值(注意函数声明中的intb=2)。因此这次函数调用的结果是6(12/2)。在第二次调用中:divide(20,4)这里有两个参数,所以默认值(intb=2)被传入的参数值4所取代,使得最后结果为5(20/4).函数重载(Overloadedfunctions)两个不同的函数可以用同样的名字,只要它们的参量(arguments)的原型(prototype)不同,也就是说你可以把同一个名字给多个函数,如果它们用不同数量的参数,或不同类型的参数。例如://overloadedfunction#include&iostream.h&intdivide(inta,intb){return(a/b);}floatdivide(floata,floatb){return(a/b);}intmain(){intx=5,y=2;floatn=5.0,m=2.0;cout&&divide(x,y);cout&&&\n&;cout&&divide(n,m);cout&&&\n&;return0;}53/17022.5在这个例子里,我们用同一个名字定义了两个不同函数,当它们其中一个接受两个整型(int)参数,另一个则接受两个浮点型(float)参数。编译器(compiler)通过检查传入的参数的类型来确定是哪一个函数被调用。如果调用传入的是两个整数参数,那么是原型定义中有两个整型(int)参量的函数被调用,如果传入的是两个浮点数,那么是原型定义中有两个浮点型(float)参量的函数被调用。为了简单起见,这里我们用的两个函数的代码相同,但这并不是必须的。你可以让两个函数用同一个名字同时完成完全不同的操作。Inline函数(inlinefunctions)inline指令可以被放在函数声明之前,要求该函数必须在被调用的地方以代码形式被编译。这相当于一个宏定义(macro)。它的好处只对短小的函数有效,这种情况下因为避免了调用函数的一些常规操作的时间(overhead),如参数堆栈操作的时间,所以编译结果的运行代码会更快一些。它的声明形式是:inlinetypename(arguments...){instructions...}它的调用和其他的函数调用一样。调用函数的时候并不需要写关键字inline,只有在函数声明前需要写。递归(Recursivity)递归(recursivity)指函数将被自己调用的特点。它对排序(sorting)和阶乘(factorial)运算很有用。例如要获得一个数字n的阶乘,它的数学公式是:n!=n*(n-1)*(n-2)*(n-3)...*1更具体一些,5!(factorialof5)是:5!=5*4*3*2*1=120而用一个递归函数来实现这个运算将如以下代码://factorialcalculator#include&iostream.h&54/170Typeanumber:9!9=362880longfactorial(longa){if(a&1)return(a*factorial(a-1));elsereturn(1);}intmain(){cout&&&Typeanumber:&;cin&&l;cout&&&!&&&l&&&=&&&factorial(l);return0;}注意我们在函数factorial中是怎样调用它自己的,但只是在参数值大于1的时候才做调用,因为否则函数会进入死循环(aninfiniterecursiveloop),当参数到达0的时候,函数不继续用负数乘下去(最终可能导致运行时的堆栈溢出错误(stackoverflowerror)。这个函数有一定的局限性,为简单起见,函数设计中使用的数据类型为长整型(long)。在实际的标准系统中,长整型long无法存储12!以上的阶乘值。函数的声明(Declaringfunctions)到目前为止,我们定义的所有函数都是在它们第一次被调用(通常是在main中)之前,而把main函数放在最后。如果重复以上几个例子,但把main函数放在其它被它调用的函数之前,你就会遇到编译错误。原因是在调用一个函数之前,函数必须已经被定义了,就像我们前面例子中所做的。但实际上还有一种方法来避免在main或其它函数之前写出所有被他们调用的函数的代码,那就是在使用前先声明函数的原型定义。声明函数就是对函数在的完整定义之前做一个短小重要的声明,以便让编译器知道函数的参数和返回值类型。它的形式是:typename(argument_type1,argument_type2,...);它与一个函数的头定义(headerdefinition)一样,除了:?55/170它不包括函数的内容,也就是它不包括函数后面花括号{}内的所有语句。??它以一个分号semicolonsign(;)结束。在参数列举中只需要写出各个参数的数据类型就够了,至于每个参数的名字可以写,也可以不写,但是我们建议写上。例如://声明函数原型#include&iostream.h&voidodd(inta);voideven(inta);intmain(){do{cout&&&Typeanumber:(0toexit)&;cin&&i;odd(i);}while(i!=0);return0;}voidodd(inta){if((a%2)!=0)cout&&&Numberisodd.\n&;elseeven(a);}voideven(inta){if((a%2)==0)cout&&&Numberiseven.\n&;elseodd(a);}这个例子的确不是很有效率,我相信现在你已经可以只用一半行数的代码来完成同样的功能。但这个例子显示了函数原型(prototypingfunctions)是怎样工作的。并且在这个具体的例子中,两个函数中至少有一个是必须定义原型的。这里我们首先看到的是函数odd和even的原型:voidodd(inta);voideven(inta);56/170Typeanumber(0toexit):9Numberisodd.Typeanumber(0toexit):6Numberiseven.Typeanumber(0toexit):1030Numberiseven.Typeanumber(0toexit):0Numberiseven.这样使得这两个函数可以在它们被完整定义之前就被使用,例如在main中被调用,这样main就可以被放在逻辑上更合理的位置:即程序代码的开头部分。尽管如此,这个程序需要至少一个函数原型定义的特殊原因是因为在odd函数里需要调用even函数,而在even函数里也同样需要调用odd函数。如果两个函数任何一个都没被提前定义原型的话,就会出现编译错误,因为或者odd在even函数中是不可见的(因为它还没有被定义),或者even函数在odd函数中是不可见的。很多程序员建议给所有的函数定义原型。这也是我的建议,特别是在有很多函数或函数很长的情况下。把所有函数的原型定义放在一个地方,可以使我们在决定怎样调用这些函数的时候轻松一些,同时也有助于生成头文件。57/1703.1数组(Arrays)数组(Arrays)是在内存中连续存储的一组同种数据类型的元素(变量),每一数组有一个唯一名称,通过在名称后面加索引(index)的方式可以引用它的每一个元素。也就是说,例如我们有5个整型数值需要存储,但我们不需要定义5个不同的变量名称,而是用一个数组(array)来存储这5个不同的数值。注意数组中的元素必须是同一数据类型的,在这个例子中为整型(int)。例如一个存储5个整数叫做billy
的数组可以用下图来表示:这里每一个空白框代表数组的一个元素,在这个例子中为一个整数值。白框上面的数字0到4代表元素的索引(ind

我要回帖

更多关于 c语言运行结果 的文章

 

随机推荐