学习目标:
编写一个简答的C++程序
学习内容:
1、一个简单的c++程序
2、输入和输出
3、关于注释
4、控制流
5、类简介
6、书店程序
1.1 编写一个简单的c++程序
每个C++程序都包含一个或多个函数(function),其中一个必须命名为main。操作系统通过调用main来运行c++程序。
int main
{
return 0;
}
这是非常简单的的main函数,它什么也不干,只是返回给操作系统的一个值。
一个函数的定义包含四部分:返回类型(return type)、函数名(function name)、一个括号包围的形餐列表(parameter list,允许为空)以及函数体(functino body)。虽然mian函数在某种程度上比较特殊,但定义和其他函数一样。
在上面例子中,main的形参列表是空的。main函数的返回类型必须为int,即为整数类型。int类型是一种内置类型(built-intype),即语言自身定义的类型。函数定义的最后一部分是函数体,它是一个左花括号(curly brace)开始,以右花括号结束的语句块(block of statemnts):
{
return 0;
}
这个语句唯一的一条语句是return,它结束函数的执行,return会向调用者返回一个值。当return语句包括一个值时,此返回值的类型必须与函数返回类型相容。main的返回类型是int,返回值0的确是一个int类型的值。
1.1.1 编译、运行程序
编写好程序之后就可以编译它,可以使用IDE(Integrated Developed Environment,IDE)集成开发环境,编译器与其他程序创建和分析工具包装在在一起。
程序源文件命名约定
无论使用命令行界面还是IDE,大多数编译器都要求程序源码存储在一个或多个文件中。程序文件通常被称为源文件(source file)。在大多数系统中,源文件的名字以一个后缀为结尾,后缀是由一个句点后接成一个或多个字符组成的。后缀告诉系统这些文件是一个c++程序。不同的编译器使用不同的后缀名约定,常见的包括:cc、cxx、.cpp、cp及.c。
从命令行运行编译器
$ CC xxx.cc
$ xxx
$ .\xxx
“.”后跟一个反斜线指出该文件夹在当前目录中
为了在unix系统中运行一个可执行文件,要使用全文件名,包括文件扩展名:xxx.out
$ ./a.out
访问main的返回值的方法以依赖于系统。在unix和windows系统中,执行完一个程序后,都可以通过echo命令其获得返回值
在unix系统中,通过如下命令可以获得状态:
$ echo $?
在windows系统中查看:
$ echo %ERRORLEVEL%
运行GNU或微软编译器
在不同操作和编译系统中,运行c++编译器的命令也是各不相同,常用的是GNU编译器和微软的Visual Studio编译器。GNU编译器的命令是g++:
$ g++ -o xxx xxx.cc
此处,$是系统提示符。-o xxx是编译器参数,制定了可执行文件的文件名。在不同操作系统中,此命令声称一个xxx或xxx.exe可执行文件。在unix系统中,可执行文件没有后缀;
windows系统下后缀为.exe。
1.2 初识输入输出
c++语言并未对定义任何输入输出(IO)语句,取而代之,包含了一个全面的标准库(standard library)来提供IO机制(以及很多其他设施)。
在这里大多示例使用iostream库。iostream库包含两个基础类型istream和ostream,分别表示输入流和输出流。一个流就是一个字符序列,是从IO设备读出或写入IO设备的。术语“流”(stream)想要表达的是,随着时间的推移,字符是顺序生成或是消耗的。
标准输入输出对象
标准库定义了4个IO对象。为了处理输入,我们使用一个名为cin的istream类型的对象。这个对象也成为标准输入(standard input)。对于输出,我们使用一个名为cout的ostream类型的对象,名为cerr和clog。我们通常用cerr来输出警告和错误消息,因此也被称为标准错误(standard error)。
一个使用IO库的程序
#include <iostream> /*告诉编译器想用使用iosstream库*/
int main()
{
std::cout <<"Enter two numbers:"<< std::endl; /*向流写入数据,main的函数题的第一条语句执行了一个表达式(expression)*/
int v1 = 0,v2 = 0;
std::cin >> v1 >> v2;
std::cout << "The sum of " << v1 << " and " << v2
<< " is " << v1 + v2 << std::endl; /*操纵符(manipulator)的特殊值*/
/*写入endl的效果是结束当前行,并将与设备关联的缓冲区(buffer)中的内容刷到设备中*/
return 0;
}
程序开始在屏幕打印:Enter two numbers:
然后等待用户输入,如果输入
1 0
则会产生如下输出:
The sum of 1 and 0 is 1
1、编写程序,在标准输出上打印Hello,World
#include <iostream>
int main()
{
std::cout<< "Hello World!"<< std::endl;
}
2、我们的程序使用加法运算符+来将两个数相加。编写程序使用乘法运算符*,来打印两个数的积。
#include <iostream>
int main()
{
int input1 = 0,input2 = 0;
std::cout <<"Now we can use *" << std::endl;
std::cin >> input1 >> input2;
std::cout << "输入一个数" << input1 <<"和"<< input2
<< "它们的乘积数为:"<< input1*input2 << std::endl;
return 0;
}
3、我们将所有的运算对象的打印操作放在一条独立的语句中
#include <iostream>
int main()
{
int input1 = 0,input2 = 0;
std::cout <<"Now we can use *" << std::endl;std::cin >> input1 >> input2;std::cout << "输入一个数" << input1 <<"和"<< input2 << "它们的乘积数为:"<< input1*input2 << std::endl;return 0;
}
4、解释下面程序片段是否合法
std::cout << "The sum of "<< v1 ; << "and" << v2; << "is" << v1+v2 << std::endl;
答:不合法,因为输出运算符“<<”需要连接两个对象,第二行和第三行的输出运算符都缺少左侧输出,所以要在前面添加std::cout
1.3 注视简介
C++中有两种注释:单行(//)注释和界定注释对注释(/* */)。
#include <iostream>
/*
*简单主函数:
*读取两个数,求它们的和
*/
int main()
{
//提示用户输入两个数
std::cout<< "Enter two numbers:" << std::endl;
int v1 = 0,v2 = 0; //保存我们读入的输入数据的变量
std::cin >> v1 >> v2; //读取输入数据
std::cout << "The sum of"<< v1 << "and" << v2
<< "is" << v1+v2 << std::endl;
return 0;
}
注释界定符不能嵌套
1.4 控制流
语句一般是顺序执行:语句块的第一条语句首先执行,然后是第二语句,依次类推。
1.4.1 while 语句
while语句反复执行一段代码,直到给定条件为假为止。
#include <iostream>
int main()
{
int sum = 0,val = 1;
//只要val的值小于10,while循环就会持续执行
while (val <=10)
{
sum += val; //复合赋值运算符(+=),和sum=sum+val是相同的,将sum + val赋予sum。
++val; //等价于val=val+1,将val加1
}
std::cout << "Sum of 1 to 10 inclusive is:"
<< sum << std::endl;
return 0;
}
编译程序之后会输出:
Sum of 1 to 10 inclusive is:55
与之前的例子一样,包含头文件iostream,然后定义main,在mian里面定义两个int变量:sum用来保存和;val用来表示1-10的每个数。因为while语句的执行过程是交替地检测condition条件和执行关联的语句statement,知道condition为假时停止。条件(condition)就是产生真或假的结果的表达式。只要condition为真,statement就会被执行。执行完statement会再次检测condition,如果又为真,statement再次被执行。while语句就是交替的检测condition和执行statement,知道condition为假为止。
1、使用while循环将50到100的整数相加
#include <iostream>
int main()
{
int sum=0,val=50;
//只要val小于101,while循环就会持续执行
while(val <= 100)
{
sum += val; //将sum+val赋予sum
++val; //将val加1
}
std::cout << "Sum of 50 to 100 inclusive is:"
<< sum << std::endl;
return 0;
}
2、除了++运算符将运算对象的值加1之外,还有一个运算符(--)实现将值减少。编写程序,使用递减运算符在循环中按递减顺序打印10到0之间的整数
#include <iostream>
int main()
{
int sum=0,end=10;
while(end>=0)
{
sum = end;
--end;
std::cout << sum << std::endl;
}
return 0;
}
3、编写程序,提示用户输入两个整数,打印两个整数所指定的范围内的所有整数
#include <iostream>
int main()
{
std::cout <<"请输入两个数"<< std::endl;
int input1,input2;
std::cin >> input1 >> input2;
if(input1 > input2)
while (input1>input2)
{
std::cout << input1 << " ";
input1--;
}else{
while (input1<=input2)
{
std::cout << input1 <<" ";
input1++;
}
}
return 0;
}
1.4.2 for语句
在while循环例子里面,主要是用了变量来控制循环执行次数,然后在条件中检测初始变量的值,在while循环体中依次将初始变量值递增。但这种检测变量、在循环体中递增变量的模式使用非常频繁,因此专门定义了第二种循环语句-for语句,来简化符合这种模式的语句。
用for语句重写从1-10的程序:
#include <iostream>
int main()
{
int sum = 0;
//从1加到10
for (int val = 1;val <= 10;++val) //初始化语句、循环条件、表达式
sum += val; //等价于sum=sum+val;
std::cout << "Sum of 1 to 10 inclusive is:"
<< sum << std::endl;
return 0;
}
每个for语句都包含两部分:循环头和循环体。循环头控制循环体的执行次数,它由:一个初始化语句(init-statement)、一个循环条件(condition)以及一个表达方式(expression)。
1、下面的for循环完成了什么功能?sum的终值是多少
int sum = 0;
for (int i = -100; i <= 100; ++i)
sum += i;
答:这个for循环完成了从-100到100的求和功能,最终的值为0。
2、使用for循环重做以上运用while所有的练习:0-50求和、输入两个整数,打印两个整数所指定的范围内的所有整数。
//0-50求和
#include <iostream>
int main()
{
int sum=0;
for(int val=0;val<=50;val++){
sum+=val;
}
std::cout << sum << std::endl;
}
//打印两个整数所指定的范围内的所有整数。
#include <iostream>
int main()
{
std::cout <<"请输入两个数:"<< std::endl;
int input1,input2;
std::cin >> input1 >> input2;
if(input1 > input2)
for(;input1 > input2;input2++)
{
std::cout << input2 << std::endl;
}
else
{
3、对比for循环和while循环,两种的形式缺点各是什么?
答:可以对比一下for循环和while循环各自的格式:
for:一个初始化语句、一个循环条件以及一个表达方式;for循环可以节省内存以及代码简洁,在循环语句中定义一个局部变量,循环结束后,局部变量就被释放了
while:语句反复执行一段代码,直到给定条件为假为止,重复交替;尽管while形式上不如for语句简洁,但适用于循环次数不好预知的情况,并且通常需要在循环之前定义好变量。
1.4.3 读取数量不定的输入数据
扩展一个1到10个整数求和的方向是对用户输入的一组数来进行求和。在这种情况下我们根本不知道要对多少个数进行求和,这就需要不断读取数据直到没有新的输入为止:
#include <iostream>
int main
{
int sum = 0,value = 0;
//读取数据直到遇到文件尾,计算所有读入的值的和;
while (std::cin >> value )
sum += value; //等价于sum = sum + value;
std::cout << "Sum is: " << sum << std::endl;
return 0;
}
main的首行定义了两个名为sum和value的int变量,均初始化为0。value用来保存用户输入的每个数,数据读取操作是在while的循环条件中完成的,while循环条件的求值就是执行表达式,然后保存在value中。
从键盘输入文件结束符
当从键盘向程序输入数据时,对于如何指出文件结束,不同操作系统有不同的约定。在windows系统中,输入文件结束符的方法之敲Ctrl+z,然后enter;Unix系统中是输入Ctrl+D。
1.4.4 if语句
用if语句可以来写一个程序,统计在输入中每个值连续出现了多少次:
#include <iostream>
int main()
{
//currVal统计的数;读入的新值存入val
int currVal = 0,val = 0;
//读取第一个数,并确保有数据可以处理
if (std::cin >> currVal){
int cnt = 1; /保存正在处理的当前值的个数
while (std::cin >> val){ //读取剩余的数
if (val == currVal) //如果值相同
++cnt; //将cnt值加1
else{
std::cout << currVal << "occurs"
<< cnt <<"times" << std::endl;
currVal = val; //记住新值
cnt = 1;
}
} //while循环在这里结束
//记住打印文件中最后一个值的个数
std::cout << currVal << "occurs" << cnt << "times" << std::endl;
} //最外层的if语句在这里结束
return 0;
}
1.5 类简介
为了使用类,需要理解三件事情即可:
- 类是什么?
- 它是在哪里定义的?
- 它支持什么操作?
1.5.1 Sales_item类
Sales_item类的作用是表示一本书的总销售额、售出手册和平均售价。可以不关心这些数据如何存储、如何计算。为了使用一个类,不必去关心它是如何实现的,只需要知道类对象可以执行什么操作即可。
这里放Sales_item:
/*
* This file contains code from "C++ Primer, Fifth Edition", by Stanley B.
* Lippman, Josee Lajoie, and Barbara E. Moo, and is covered under the
* copyright and warranty notices given in that book:
*
* "Copyright (c) 2013 by Objectwrite, Inc., Josee Lajoie, and Barbara E. Moo."
*
*
* "The authors and publisher have taken care in the preparation of this book,
* but make no expressed or implied warranty of any kind and assume no
* responsibility for errors or omissions. No liability is assumed for
* incidental or consequential damages in connection with or arising out of the
* use of the information or programs contained herein."
*
* Permission is granted for this code to be used for educational purposes in
* association with the book, given proper citation if and when posted or
* reproduced.Any commercial use of this code requires the explicit written
* permission of the publisher, Addison-Wesley Professional, a division of
* Pearson Education, Inc. Send your request for permission, stating clearly
* what code you would like to use, and in what specific way, to the following
* address:
*
* Pearson Education, Inc.
* Rights and Permissions Department
* One Lake Street
* Upper Saddle River, NJ 07458
* Fax: (201) 236-3290
*/
/* This file defines the Sales_item class used in chapter 1.
* The code used in this file will be explained in
* Chapter 7 (Classes) and Chapter 14 (Overloaded Operators)
* Readers shouldn't try to understand the code in this file
* until they have read those chapters.
*/
#ifndef SALESITEM_H
// we're here only if SALESITEM_H has not yet been defined
#define SALESITEM_H
// Definition of Sales_item class and related functions goes here
#include <iostream>
#include <string>
class Sales_item {
// these declarations are explained section 7.2.1, p. 270
// and in chapter 14, pages 557, 558, 561
friend std::istream& operator>>(std::istream&, Sales_item&);
friend std::ostream& operator<<(std::ostream&, const Sales_item&);
friend bool operator<(const Sales_item&, const Sales_item&);
friend bool
operator==(const Sales_item&, const Sales_item&);
public:
// constructors are explained in section 7.1.4, pages 262 - 265
// default constructor needed to initialize members of built-in type
#if defined(IN_CLASS_INITS) && defined(DEFAULT_FCNS)
Sales_item() = default;
#else
Sales_item() : units_sold(0), revenue(0.0) { }
#endif
Sales_item(const std::string &book) :
bookNo(book), units_sold(0), revenue(0.0) { }
Sales_item(std::istream &is) { is >> *this; }
public:
// operations on Sales_item objects
// member binary operator: left-hand operand bound to implicit this pointer
Sales_item& operator+=(const Sales_item&);
// operations on Sales_item objects
std::string isbn() const { return bookNo; }
double avg_price() const;
// private members as before
private:
std::string bookNo; // implicitly initialized to the empty string
#ifdef IN_CLASS_INITS
unsigned units_sold = 0; // explicitly initialized
double revenue = 0.0;
#else
unsigned units_sold;
double revenue;
#endif
};
// used in chapter 10
inline
bool compareIsbn(const Sales_item &lhs, const Sales_item &rhs)
{
return lhs.isbn() == rhs.isbn();
}
// nonmember binary operator: must declare a parameter for each operand
Sales_item operator+(const Sales_item&, const Sales_item&);
inline bool
operator==(const Sales_item &lhs, const Sales_item &rhs)
{
// must be made a friend of Sales_item
return lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue &&
lhs.isbn() == rhs.isbn();
}
inline bool
operator!=(const Sales_item &lhs, const Sales_item &rhs)
{
return !(lhs == rhs); // != defined in terms of operator==
}
// assumes that both objects refer to the same ISBN
Sales_item& Sales_item::operator+=(const Sales_item& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// assumes that both objects refer to the same ISBN
Sales_item
operator+(const Sales_item& lhs, const Sales_item& rhs)
{
Sales_item ret(lhs); // copy (|lhs|) into a local object that we'll return
ret += rhs; // add in the contents of (|rhs|)
return ret; // return (|ret|) by value
}
std::istream&
operator>>(std::istream& in, Sales_item& s)
{
double price;
in >> s.bookNo >> s.units_sold >> price;
// check that the inputs succeeded
if (in)
s.revenue = s.units_sold * price;
else
s = Sales_item(); // input failed: reset object to default state
return in;
}
std::ostream&
operator<<(std::ostream& out, const Sales_item& s)
{
out << s.isbn() << " " << s.units_sold << " "
<< s.revenue << " " << s.avg_price();
return out;
}
double Sales_item::avg_price() const
{
if (units_sold)
return revenue / units_sold;
else
return 0;
}
#endif
每个类的实际上都定义了一个新的类型,类型名字就是类名。可以定义类类型的变量:
Sales_item item;
是想表达item是一个Sales_item类型的对象。除了定义Sales_item类型的变量之外,还可以:
- 调用一个名为isbn的函数从一个Sales_item对象中提取ISBN书号。
- 用输入符运算(>>)和输出运算符(<<)读、写Sales_item类型的对象。
- 用赋值运算符(=)将一个Sales_item对象的值赋予另一个Sales_item对象。
- 用加法运算符(+)将两个Sales_item对象相加。两个对象必须表示同一本书(相同的ISBN)。
- 使用复合赋值运算符(+=)将一个Sales_item对象加到另一个对象上。
关键概念:类定义了行为
读写Sales_item
下面的程序是从标准输入读入数据,存一个Sales_item对象中,然后将Sales_item的内容写回到标准输出:
#include <iostream>
#include "Sales_item.h"
int main(){
Sales_item book;
//读入ISBN号、售出的册数以及价格销售价格
std::cin >> book;
//写入ISBN、售出的册数、总销售额和平均价格
std::cout << book << std::endl;
return 0;
}
1.5.2 初识成员函数
将两个Sales_item对象相加的程序首先应该检查两个对象是否具有相同的ISBN:
#include <iostream>
#inlcude "Sales_item.h"
int main(){
Sales_item item1,item2;
std::cin >> item1 >> item2;
//首先检查item1和item2是否表示相同的书
if(item1.isbn()==item2.isbn()){
std::cout << item1+item2 << std::endl;
return 0; //表示成功
}else {
std::cerr << "Data must refer to same ISBN" << std::endl;
return -1; //表示失败
}
}
如上一个版本一样,程序打印计算结果,并返回0,表明成功。如果条件失败,执行跟在else之后的语句块,打印一条错误信息,并返回一个错误的标识。
什么是成员函数?
当调用名为isbn的成员函数(member function)。成员函数是定义为类的一部分的函数,有时也被称为方法(method),通常以一个类对象的名义来调用成员函数;使用点运算符(.)来表达我们需要“名为item1的对象的isbn成员”,点运算符只能用于类类型的对象;其右侧侧运算对象指定的成员。
1、编写程序,读取多条销售记录,并统计每个ISBN(每本书)有几条销售记录
#include<iostream>
#include "Sales_item.h"
int main() {
Sales_item trans1, trans2;
int num = 1;
std::cout << "Plz input" << std::endl;
if (std::cin >> trans1) {
while (std::cin >> trans2) {
if (compareIsbn(trans1, trans2))//Isbn相同
num++;
else {
std::cout << trans1.isbn() << "共有" << num << "条销售记录" << std::endl;
trans1 = trans2;
num = 1;
}
}//while end;
std::cout << trans1.isbn() << "共有" << num << "条销售记录" << std::endl;
}
else {
std::cout << "输入数据有误" << std::endl;
return -1;
}
return 0;
}
2、输入表示多个ISBN的多条销售记录来测试上一个程序,每个ISBN的记录应该聚在一起
#include <iostream>
#include "Sales_item.h"
int main(){
Sales_item total;
if(std::cin >> total){
Sales_item trans;
while(std::cin >> trans){
if(total.isbn()==trans.isbn()){
total += trans;
}else{
std::cout << total << std::endl;
total = trans;
}
}
std::cout << total << std::endl;
return -1;
}
return 0;
}
1.6 书店程序
#include <iostream>
#include "Sales_item.h"
int main(){
Sales_item total; //保存下一条交易记录的变量
//读入第一条交易记录,并确保有数据可以处理
if(std::cin >> total){
Sales_item trans; //保存和的变量
//读入并处理剩余交易记录
while(std::cin >> trans){
//如果我们仍在处理相同的书
if(total.isbn() == trans.isbn())
total += trans; //更新总销售额
else{
//打印前一本书的结果
std::cout << total << std::endl;
total = trans; //total现在表示下一本书的销售额
}
}
std::cout << total << std::endl; //打印最后一本书的结果
}else{
//没有输入!警告读者
std::cerr << "No data?!" << std::endl;
return -1;//表示失败
}
return 0;
}
小结:
定义一个main函数,它是操作系统执行你的程序的调用入口。了解如何定义变量进行输入和输出,以及编写if、for和while语句。最后了解了cpp中最基本的特性-类。