C++ Primer Plus学习笔记--开始学习(二)

进入C++

C++对大小写敏感,比如:将cout替换成Cout或COUT,都无法通过编译。

C++程序包括的元素:

  • 注释: 由前缀//标识
  • 预处理器编译指令#include
  • 函数头: int main()
  • 编译指令:using namespace
  • 函数体:用{}括起
  • 使用C++的cout工具显示消息的语句
  • 结束main()函数的return语句

main()

int main()
{
    statements
    return 0;
}

这几行代码构成了函数的定义。
定义由两部分组成:

  • 第一行:int main()叫函数头(functon definition),函数头对函数与程序其他部分之间的接口进行了总结;
  • 花括号中包括的部分叫做函数体,函数体指出函数应该做什么计算机指令。

作为接口的函数头

C++函数可以被其他函数调用,函数头描述了函数与调用函数之间的接口。

  • 位于函数名的前部分叫做函数的返回类型,他描述的是从函数返回给调用它的函数的信息。
  • 函数名括号中的部分叫做形参列表,或参数列表,它描述的是从调用函数传递给被调用的函数的信息。

注:main()通常不被程序的其他部分调用,而被启动代码调用,启动代码是由编译器添加到程序中的,是程序和操作系统之间的桥梁。

C++中合法的函数头:

int main()
int main(void)

main()中如果结尾未遇到返回语句,则默认添加语句结尾:retrun 0;,不适应于其他函数。

注释

//表示注释,单行注释

/*注释部分*/ 多行注释

预处理器和iostream文件

如果程序中使用到C++的输入或输出工具,必须提供如下两行代码:

#include 
using namespace std;

注意:以上代码在C++98标准中实现,如果编译器不接受上述两行代码,说明它没有遵守标准C++98。

#include 指令导致预处理将iostream文件中的内容添加到程序中。iostream中的io指的是输入和输出。C++的输入/输出方案涉及iostream文件中的多个定义。为了使用cout来显示消息,第一个程序需要这些定义。#include编译指令导致iostream文件的内容随源代码文件的内容一起被发送给编译器。实际上,iostream文件的内容将取代程序中的代码行#include 。源文件并没有被修改,而是源代码文件和iostream组合成的一个复合文件,编译的下一个阶段将使用到该文件。

头文件名

iostream这样的文件叫做包含文件(include file)—由于它被包含在其他文件中,也被叫做头文件(header file)—由于他被包含在文件的起始处。

C++包含了C中的头文件,C中的头文件以h为扩展名,比如:math.h,仍可以使用C中math.h头文件。C++中的头文件没有扩展名。注意,C中的有些头文件被转换为C++头文件,文件被重新命名,去掉扩展名h,并在文件名称前面添加前缀c(表明来自C语言)。例如:C++版本的math.h为cmath。

C++旧式风格,头文件以.h结尾,比如:iostream.h

命名空间

如果使用iostream,而不是iostream.h,则应使用下面的命名空间编译指令来使iostream中的定义对程序可用:

using namespace std;

这被称之为using编译指令。

命名空间支持是C++的一项特性,旨在让编写大型程序以及将多个厂商现有的代码组合起的程序时更容易,它还有助于组织程序。一个潜在的问题,当使用两个以及封装好的产品,而它们同时使用了wanda()函数。这样当使用wanda()函数的时候,编译器不知道指的哪个版本。

命名空间让厂商将其产品封装在一个叫做命令空间的单元中,这样可以用命名空间来指出想使用哪个厂商的产品。Microflop可以将其定义放到一个名为Microflop的命名空间中。这样,其的wanda()函数的全称为Microflop::wanda();同样,Piscine公司的wanda()版本表示为:Piscine::wanda()。这样,程序就可以使用命名空间来区分不同的版本。

类、变量和函数是C++编译器的标准组建,它们被放置在命名空间std中。仅当头文件没有扩展h时,情况才是如此。

实际中如上三种方式等级:

std:cin>> a;
std::cout <<"jjj";
std::cout<

使用cout进行C++输出

cout <<"come up"

<<表示把字符串发送给cout,该符号指出了信息流动的路径。cout是一个预定义的对象,知道如何显示字符串、数字和单个字符等等。

cout对象表示一个流,其属性是在iostream文件中定义的,cout的对象包括一个插入运算符”<<”,它可以将右侧的信息插入到流中。

上面代码,将字符串插入到输出流中,因此,与其说程序显示了一条消息,不如说它将一个字符串插入到了输出流中。

注意:插入运算符<<跟按位左移运算符<<一样,其实这是一个运算符重载的例子。通过重载,同一个符合将有不同的含义。编译器通过上下文来确定运算符的含义。C本身也有一些运算符重载,比如:&符合既有地址运算符,又表示AND运算符;*既表示乘法,又表示指针解除引用。

控制符endl

endl表示重起一行,在输出流中插入endl将导致屏幕光标移到下一行。endl同样也在头文件iostream中定义,且位于命名空间std中。

cout<<"The Good, the";
cout<<"Bad,";

输出结果:The Good, the Bad,

换行符

'/n'

cout<

两者区别:enld确保程序继续运行前刷新输出(即将其立即显示在屏幕上);而使用’\n’不能提供这样的保证。

C++源代码格式化

C++中使用’;’表示语句的结尾。因此在C++中,回车的作用就和空格或制表符相同。也就是几条语句可以放在同一行,用空格或制表符隔开。

C++代码风格:

  • 每条语句占一行
  • 每个函数都有一个开始花括号和一个结束花括号,这两个花括号各占一行。
  • 函数中的语句都要相对花括号进行缩进
  • 与函数名相关的圆括号周围没有空白

C++语句

C++程序是一组函数,而每个函数又是一组语句。C++有好几种语句:声明语句创建变量,复制语句给变量提供一个值。

声明语句和变量

int carrots

这条语句提供了两项信息:

  • 需要的内存以及该内存单元的名称,具体,这条语句指出程序需要足够的存储来存储一个整数。
  • 给存储单元指定名称,该声明语句指出,此后程序将使用名称carrots来标识存储在该单元中的值,carrots被称为变量。

声明变量的重要性

python中,在使用新名称时创建变量,而不用显式地进行声明。看上去比较友好,问题是如果变量名写错,将在不知情的情况下创建一个新的变量。如下:

castleDark = 34
castleDank = castleDark + MoreGhosts

print(castleDark)

由于castleDank拼写错误,因此所作的修改实践上并没有修改castleDark。这种错误很难发现,因为并没有违反python的任何规则。然后,在C++中,违反了使用变量前必须声明它的规则,因此编译器将捕获这种错误。

C中的变量声明通常位于函数的开头,不过C++的变量声明没有这种限制,C++的通常做法是在首次使用变量前声明它,这样不必再程序中查找,以了解变量的类型。

赋值语句

赋值语句将赋值给存储单元,例如:

carrots = 25;

将整数25赋给变量carrots表示的内存单元。

符号’=’叫做赋值运算符。C++和C有一项不寻常的特性—可以连续使用赋值运算符。例如:

int steinway;
int baldwin;
int yamaha;
yamaha = balwin = steinway = 88;

赋值将从右至左进行。首先,将88被赋值给steinway,然后,steinway的值被赋值给baldwin,继续进行。

赋值之前可以修改变量的值,比如:

carrots = carrots - 1;

cout的新花样

cout前面都是用来打印字符串,而它还可以用来打印变量:

cout << carrots;

程序没有打印carrots,而是打印存储在carrots中的值,即25。实际上,这将两个操作合而为一。首先,cout将carrots替换为其当前值25;然后,把值转换为合适的输出字符。打印之前,cout必须将整数形式转化为字符的形式。

字符串’15‘和整数25有天壤之别:

  • 字符串存储的是书写该该数字时使用的字符,即字符2和5。程序在内部存储的是字符2和字符5的编码。要打印字符串,cout只需要打印字符串中的各个字符即可。
  • 整数25被存储为数值,计算机不是单独存储每个数字,而是将25存储为二进制数。

C语言中,使用特殊代码(%s和%d)来指出打印字符串和整数。如果让printf()打印字符串,但又错误的提供了一个整数,由于printf()不够精密,因此根本发现不了错误,而是输出一串乱码。

printf("%s", "25");
printf("%d", 25);

而C++中cout比较智能,其智能来自C++的面向对象特性。实际中,C++插入运算符(<<)将根据其后的数据类型相应的调整其行为,这是一个运算符重载的例子。

其他C++语句

cin

cin >> carrots;

从这条语句,可知,信息从cin流向carrots。cin使用>>运算符从输入流中抽取字符,运算符右侧提供一个变量,以接受抽取的信息。”<<”和”>>”用来指示信息流的方向。

cin同样是一个智能对象,它可以将通过键盘输入的一系列字符(即输入)转换为接受信息的变量能过接受的形式。

int carrots;
cin >> carrots;

上述例子,程序将carrots声明为一个整性变量,因此输入被转换为计算机用来存储整数的数字形式。

cout进行封装

cout << "Now you have " << carrots << " carrots" << endl;

跟如下代码等价:

cout << "Now you have ";
cout << carrots ;
cout << " carrots";
cout << endl;

也可写成如下形式:

cout << "Now you have " 
    << carrots 
    << " carrots" 
    << endl;

类简介

类是用户定义的一种数据类型。类之于对象就像类型之于变量,即类定义描述的是数据格式及其用法,而对象则是根据数据格式创建的实体。比如:类就好比所有著名演员,则对象就是好比某个著名演员,如,蛙人Kermit。扩展这种类比,表示演员的类中包括该类可执行的操作的定义,如念某句台词,表达悲伤,接受奖励。

int carrotss;

上面的代码创建了一个类型为int的变量(carrots)。也就是说,carrots可以存储整型,可以按特定的方式使用—例如,用户加和减。

又如,cout是一个ostream类对象,ostream类定义描述了ostream对象表示的数据以及可以对它执行的操作。如将数字或字符串插入到输出流中。同样,cin是一个istream类,也定义在iostream中。

注意:类描述了一种数据类型的全部属性,包括可使用它执行的操作,对象是根据这些描述创建的实体。

类描述指定了可对类对象执行的所有操作,要对特定对象执行这些允许的操作,需要给该对象发送一条消息。例如:希望cout对象显示一个字符串,应向它发送一条消息,告诉它,“对象,显示这些内容!”。

C++提供了两种发送消息的方式:

  • 使用类方法(本质上就是函数调用);
  • 重新定义运算符,cin和cout采用的就是这种方式。

    cout << “I am not a crook”;

上面的语句使用重新定义<<运算符将‘显示的消息’发送给cout。消息带有一个参数—即显示的字符串。

函数

C++函数分为两类:有返回值和无返回值。

使用有返回值的函数

有返回值的函数将生成一个值,而这个值可赋给变量或在其他表达式中使用。例如,C/C++库中的sqrt()函数,它返回平方根,如下:

x = sqrt(6.25);

表达式sqrt(6.25)将调用sqrt()函数,表达式sqrt(6.25)被称为函数调用,被调用的函数被称为被调用函数(called function),包含函数调用的函数叫做调用函数

int main()
{
    x = sqrt(6.25)
}

其中的main()函数叫做调用函数, sqrt()叫做被调用函数。括号中的值6.25是发送给函数(sqrt())的消息,以这种方式发送给函数的值叫做参数。
被调用函数返回的值叫做函数的返回值(return value)。

函数原型之于函数就像变量声明之于变量—指出涉及的类型。例如,C++库将sqrt()函数定义成将一个看(可能)带小数部分的数字(6.25)作为参数,并返回一个相同类型的数字。sqrt()的函数原型如下:

double sqrt(double);//函数原型

第一个double意味着sqrt()返回一个double值,括号中的double一位sqrt()需要一个double参数。因此该原型对sqrt()的描述和下面代码中使用的函数相同:

double x;
x = sqrt(6.25);

原型结尾的分号表明它是一条语句,这使得它是一个原型,而不是函数头。如果省略分号,编译器将把这行代码解释为函数头,并要求提供函数体。

在程序中使用sqrt()是,必须通过原型,可以用两种方式提供来实现:

  • 在源代码文件中输入函数原型
  • 包含头文件cmath(老系统math.h),其中定义了原型

第二种方法更好,因为头文件更有可能使原型正确。对于C++库中的每个函数,都在一个或多个头文件中提供了其原型,可以通过手册或在线帮助查看函数描述来确定应使用哪个头文件。

函数原型和函数定义不要混淆,可以看出:

  • 函数原型只描述函数接口,也就是说,它描述的是发送给函数的信息和返回的信息
  • 而函数定义包含了函数的代码,如计算平方根的代码

C/C++将库函数的这两项特性(原型和定义)分开,库文件中包含了函数的编译代码,而头文件中则包含了原型。

# include 
# include 

int main()
{
    using namespace std;
    double area;
    cin >> area; //area = 152 ,cin智能地将其转化为152.0(double类型)
    double side;
    side =  sqrt(area); //double  side =  sqrt(area)//初始化
    cout << side;
    return 0;
}

使用函数库

C++库函数存储在库文件中,编译器编译程序时,它必须在库文件搜索您使用的函数。至于自动搜索哪个库文件,将因编译器而异。如果运行程序时,得到一条消息,指出_sqrt()是一个没有定义的外部函数,则很可能是由于编译器不能自动搜索math库,(编译器倾向于给函数名添加下划线前缀—提示它们对程序具有最后的发言权)。如果在Linux(Gnu编译器)中遇到该问题,可能需要在命令行末尾添加-lm选项:

g++ sqrt.cpp -lm

Unix系统,同样添加’-lm’选项。

函数变体

有些函数需要多项信息,这些函数使用多个参数,参数间使用都号分开。例如,数据函数pow()接受两个参数,返回值为以第一个参数为底,第二参数为指数的幂,该函数的原型如下:

double pow(double,double);

double answer = pow(5.0, 8.0);

不接受参数的函数,原型如下:

int rand(void)

没有返回值的函数,例如,编写一个函数,它按美元、美分格式蔑视数字,当向它传递参数23.5时,它将在屏幕上显示$23.5。原型如下:

void bucks(double)

用户自定义函数

#include 
void simon(int); //函数原型

int main()
{
    using namespace std;
    simon(3)//调用函数simon
    int count;
    cin >>count;
    simon(count);
    count << "Done!" << endl;
    return 0;
}

void simon(int n)//定义simon函数
{
    using namespace std;
    cout << "Simon says touch your toes " << n << " times." <

函数格式:

type functionsname(arguementlist)
{
    statements;
}

C++中定义的函数一般位于main()之后,不允许将函数定义嵌套在另一个函数定义中,每个函数的定义都是独立的,所有创建的函数的时平等的。

函数头:

上述程序的函数头为:

void simon(int n)

void表明没有返回值,因此调用simon()不会生成可在main()中将其赋给变量的数字。因此函数调用方式如下:

simon(3);

括号中的int n表明,使用simon()时,应提供一个int参数。函数调用时,传递的值将被赋值给n。

int main()

开头的int表明,main()返回一个整数值,空括号表明,main()没有参数。对于有返回值的函数,应使用关键字return来提供返回值,并结束函数。入main()函数末尾:

return 0;

main()函数的返回值返回给操作系统,并不是返回给程序的其他部分。通常的约定,退出值为0则意味着程序运行成功,为非0则意味着存在问题。如果,C++程序无法打开文件,可以将它设计为返回一个非零值。

关键字

关键字是计算机语言中的词汇,比如:int、void、return和double。因为这心关键字有专用,因此不能用作他用。另外main不是关键字,当最好不要将其用作变量名,不然会引发错误

用户定义的有返回值的函数

# include 
int stonetolb(int); //原型声明

int main()
{
    using namespace std;
    int stone = 4;
    int pounds = stonebolb(stont); //接受调用函数的返回值
    count << pounds << endl;
    return 0;
}

int stonetolb(int sts) //函数定义
{
    return 14 * sts; //函数返回值
}

在多函数程序中使用using编译指令

将编译指令放在函数外面,所有函数都可以访问命名空间std:

#include 
using neamespace std;
void simon(int);

int main()
{   
    sinmon(3);
    return 0;
} 

void simon(int n)
{
    cout << n;
}

当前通行的理念是,只让需要访问命名空间std的函数访问它是更好的选择。例如只有mian()函数使用cout,因此没必要让函数stonelb()能过访问命名空间std。因此编译指令放在main()函数中。

总之,让程序能够访问命名空间std的方法有多种,下面是其中的四种:

  • 将using namespace std; 放在函数定义之前,让文件中的所有函数都能够使用命名空间std中的所有的元素。
  • 将using namespace std;放在特定的函数定义中,让该函数能够使用命名空间std中的所有元素。
  • 在特定的函数中使用类似using std::cout;这样的编译指令,而不是using namespace std;,让该函数能过使用指代的元素,如cout。
  • 完全不使用编译指令using,而在需要使用命名空间std中的元素是,使用前缀std::,如下所示:
    std::cout << "I am using cout" << std::endl;

总结

C++程序有一个或多个被称为函数的模块组成。程序从main()函数开始执行,因此该函数必不可少。函数由函数头和函数体组成。函数头指出函数的返回值类型和函数期望通过参数传递给它的信息的类型。

C++语句有多种类型,包括如下6种:

  • 声明语句
  • 赋值语句
  • 消息语句:将消息发送给对象,激发某种行动
  • 函数调用:执行函数
  • 函数原型:声明函数的类型、函数接受的参数数量和类型
  • 返回语句:将一个值从被调用函数那里返回到调用函数

类是用户自定义的数据类型规范,详细描述了如何表示信息以及对数据执行的操作。对象是根据类规范创建的实体,就像简单变量是根据数据类型描述创建的实体一样。

C++提过了两个用户处理输入和输出的预定义对象(cin和cout),它们是istream和ostream类的实例,这两个类在iostream文件中定义。

你可能感兴趣的:(C++,C++)