C++ Primer 学习笔记——第一章

第一章 开始

前言

介绍大部分C++的基础内容:类型、变量、表达式、语句及函数。简单介绍如何编译及运行程序。

编写一个简单的程序,如编写记录书籍信息的程序,其必然包括一下内容:

  • 定义变量
  • 进行输入与输出
  • 使用数据结构保存数据
  • 检测两条记录是否存在相同的ISBN
  • 循环处理每条记录

1.1 编写一个简单的C++程序

每一个C++程序都包含一个或多个函数(function),其中一个必须使用main命名。

int main(){
    return 0;
}

一个函数的定义包含四个部分,包括返回类型(return type)、函数名(function
name)、参数列表(parameter list,运行为空)以及函数体(function body)。

main函数的返回类型必须为int,即为整数类型。int类型是一种内置类型
(built-in-type),即语言自身定义的类型。

函数定义定义的最后一部分为函数体,它是一个以左花括号(curly brace)开始,以右花括号结束的语句块
(block of statements):

{
    return 0;
}

return用于结束函数的执行,同时会返回一个值。当return语句包括一个值时,此返回值的类型必须与函数的返回类型相同。

在大多数系统中,main的返回值被用来指示状态。返回值0表示成功,非0的返回值的含义由系统定义,通常用来指出错误类型。

1.1.1 编译、运行程序

程序源文件命名约定

无论使用的是命令行界面还是IDE(Integrated Developed Environment 集成开发环境),大多数编译器都要求程序
源码存储在一个或多个文件中。程序文件通常被成为源文件(source file)。文件后缀名用于告诉系统这个文件是一个
C++程序。不同编译器使用不同的后缀名,在接下来笔者一直使用.cpp文件后缀名。

从命令行运行编译器

在GNU/Linux下使用:

g++ -o main main.cpp
./main
echo $?

使用G++编译器编译main.cpp文件,运行并通过echo $?命令查看返回值结果


1.2 初识输入输出

C++语言并未定义任何输入输出(IO)语句,取而代之,包含了一个全面的标准库(standard library)来
提供IO机制。

iostrem库,包含两个基础类型istremostream,分别表示输入流和输出流。一个流就是一个字符序列,即从IO设备
读出或写入IO设备的。术语“流(stream)”想要表达的是,随着时间的推移,字符是顺序生成或消耗的。

标准输入输出对象

标准库定义了4个IO对象。处理输入名为cin的istream类型对象,这个对象被称为标准输入(standard input)。
处理输出,则用cout的ostream类型对象。也被称为标准输出(standard output)。此外,还定义了两个其他ostream
对象,名为cerrclog。cerr用来输出警告和错误信息,也被称为标准错误(standard
error)。clog用来输出程序运行时的一般性信息。

C++ 中的clog对象是类ostream的对象。它与标准 C 错误输出流stderr相关联。

clog 和 cerr 都与 stderr 相关联,但它与 cerr 的不同之处在于 clog 中的流被缓冲并且不会自动与 cout 绑定。

缓冲输出比无缓冲输出更有效。在缓冲输出的情况下,所有输出都保存到一个变量中并一次全部写入磁盘。对于无缓冲的输出,我们必须继续写入磁盘。

缓冲输出不适用于严重错误。在系统崩溃的情况下,可能会出现输出仍在缓冲区中并且没有写入磁盘并且无法检索错误消息的情况。我们不能在系统崩溃的情况下丢失错误数据,因此即使速度较慢,我们也会继续将严重错误写入磁盘。

clog 通常用于记录目的。对于非关键事件日志记录,效率更为重要,因此clog优于cerr

#include <iostream>

int main() {
    std::cout << "Enter two numbers: " << std::endl;
    int value1=0, value2=0;
    std::cin >> value1 >> value2;
    std::cout << "The sum of " << value1 << " and " << value2 << " is " << value1 + value2
              << std::endl;
    return 0;
}

程序第一行告诉编译器需要使用iostream库。尖括号中的名字指出一个头文件(header)。通常情况下,一般将程序的所有

include指令放在源文件的开始位置。

向流写入数据

在上述示例中,main的函数体的第一条语句执行了一个表达式(expression)。在C++中,一个表达式产生一个计算结果
,它由一个或多个运算对象和(通常是)一个运算符组成。这条语句中使用了输出运算符(<<
)在标准输出上打印信息。

<<运算符接受两个运算对象,左侧对象必须是一个ostream对象,右侧对象是打印的值。此运算符将给定的值写到给定的ostream对象中。
输出运算符的计算结果就是其左侧运算对象。

在第一条语句中第一个运算符的结果成为第二个运算符的左侧运算对象。这样,我们就可以将输出请求连接起来。

"Enter two numbers: 为一个字符串字面值常量(string literal),是用一对双引号包围的字符序列。

endl被称为操纵符(manipulator)的特殊值。写入endl的效果是结束当前行。并将设备关联的
缓冲区(buffer)中的内容刷到设备中
。缓冲刷新操作可以保证到目前为止程序中所产生的所有输出都真正的写入输出流中,而不是仅停留在内存中等待写入流。

使用标准库中的名字

再看示例,前缀std::指出名字cout和endl是定义在名为std命名空间(namespace)中的。

命名空间可以帮助我们避免不经意的名字定义冲突,以及使用库中相同名字导致的冲突。标准库定义的所有名字都在
命名空间std中。

通过命名空间使用标准库有一个副作用:当使用标准库中的一个名字时,必须显式说明我们想要使用来自命名空间std中的名字。
例如,需要写入std::cout,通过使用作用域运算符(::)来访问标准库中的名字cout。

从流读取数据

在代码块中语句int value1=0, value2=0。将int类型的变量初始化(initialize)为0。即初始化一个变量,就是在变量创建
的同时为它赋予一个值。建议,每定义的变量都赋予初值。

std::cin>>value1>>value2;

它读入输入数据。输入运算符(>>)与输出运算符类似。它接受一个istream作为其左侧运算对象,接受一个对象作为
其右侧运算对象。它从给定的istream读入数据,并存入给定对象中。与输出运算符类似,输出运算符返回其左侧运算对象作为其计算结果。

例如:

(std::cin>>value1)>>value2;

std::cin>>value1;
std::cin>>value2;

上述代码,其第一条语句执行结果等同于第二第三条执行结果。


1.3 注释简介

注释(comments)。注释可以帮助人类读者理解程序。应该明白的是代码是给人类读的,只是恰好机器能够明白!

注释通常用于概述算法(算法是一组完成任务的指令),确定变量的用途,或者解释晦涩难懂的代码段。

当修改代码时,不要忘记同时更新注释! 因为错误的注释往往比完全没有注释更糟糕!

C++中注释有两种:

  • 单行注释,以“//”开头,换行符结束。
  • 多行注释,以界定符“/”开头,“*/”结束。编译器会将“/*/”中所有文本内容忽略掉。

注释界定符可以跨越程序中的多行,但者并不是必须的。
当注释界定符跨越多行时,最好能显式指出其内部的程序行都属于注释的一部分。

采用的风格是,注释内的每一行都以一个星号开头,从而指出整个范围都是多行注释的一部分。

程序中通常同时包含两种形式的注释。注释界定符对通常用于多行注释,而双斜线注释常用于半行和单行附注。

注释界定符不能嵌套,加入我们需要在调试期间注释一些代码,最好的方式是用单行注释方式注释掉代码段的每一行。


1.4控制流

语句一般是顺序执行的,但程序设计语言提供了多种不同的控制流语句,允许我们写出更为复杂的执行路径。

1.4.1 while语句

while语句允许反复执行一段代码,直至给定条件为假为止。

while语句的形式为:

while (condition)
    statement

while语句的执行过程是交替地检测condition条件和执行关联的语句statement,直至condition为假
停止。所谓条件(condition)就是一个产生真或假的结果的表达式。

1.4.2 for语句

每个for语句都包含两部分:循环头和循环体。循环头控制循环体的执行次数,它由三部分组成
:一个初始化语句(init-statement)、一个循环条件(condition)以及一个表达式(expression)

1.4.3 读取数量不定的输入数据

如题:
编写程序,实线对用户输入的一组数求和。

#include <iostream>

int main(){
    int sum=0,value=0;
    /* 读取数据直到遇到文件尾,计算所有读入的值的和 */
    while(std::cin>>value){
        sum+=value;
    }
    std::cout<<"Sum is: "<<sum<<std::endl;
    return 0;
}

while语句中的表达式表示从标准输入读取下一个数,并赋值(保存在)给value。输入运算符返回其左侧运算对象,即std::cin
。因此,其循环条件其实检测的是std::cin

当我们使用一个istream对象作为条件时,其效果是检测流的状态。如果流是有效的,那么检测成功。就可以通过while检测。
而当遇见遇见文件解释符(EOF end-of-while),流状态就变为无效。while判断便无法通过。

其实还可以写成这种情况,就可以使用回车结束当前循环:

#include <iostream>

void Exercise_1_4::OutputSum() {
    int sum = 0, value = 0;

    while (std::cin >> value) {
        sum += value;
        if (std::cin.get()=='\n'){
            break;
        }
    }
    std::cout << "Sum is: " << sum << std::endl;
}

PS:

编译器其实无法检测代码是否符合开发者要求,编译器能做的是检测代码形式(form)或者说语法上的错误。

常见的编译器错误:

1、语法错误(syntax error)
2、类型错误(type error)
3、声明错误(declaration error)

明白了编译器提供的错误提示就应该马上修改,因为错误往往具有传递效应。同时还需要做到错误修改完成立刻重新
编译。即“编辑-编译-调试”(edit-compile-debug)周期。

1.4.4 if语句

用于判断表达式的真假

PS:

C++程序的缩进和格式

无论使用什么格式,当做出该代码格式时应该明白为什么要这样做?有什么影响?有什么好处?
如果明白其格式作用,那么就应该坚持下去,切不可三心二意。

我的格式清单:

1、代码长度不超过100个字符
2、左侧花括号应该与其代码处于同一行(借鉴java)
3、上下邻居的输出输出运算符应该排列整齐


1.5 类简介

一个(class)定义了一个类型,以及与其关联的一组操作。

类机制是C++最重要的特性之一。C++最初的设计焦点就是能定义使用上像内置类型一样自然的类类型(class type)

使用类,需要明白三件事:

类名是什么?
类在哪里定义?
类支持什么操作?

头文件根据其中定义的类的名字来命名。一般通常使用.h后缀名来作为头文件命名,当然也可以使用其他后缀名比如:.H、
.hpp或hxx。标准库头文件通常不带后缀。编译器也不会关心文件名的形式。

类作者决定了类类型对象上可以使用的所有操作。

在引入头文件时,在源文件使用尖括号(< >)包围标准头文件,而不属于标准头文件,则用双引号(" ")包围。

PS:

文件重定向

文件重定向一般有两种实现三种方式。

第一种方式:代码内编写

可以使用函数:freopen()rdbuf()

第二种方式:控制台实现
例如存在main.cpp文件,首先运行文件生成可执行文件(如:mian
通过使用“<”和“>”实现重定向,

main <in.txt >out.txt

成员函数(member function)是定义为类的一部分的函数,有时也被称为方法(method)。笔者更愿意称为方法,
原因是类作为C++的高级特性,称呼为方法表明该函数存在于类中,与传统的函数做区分。

通过使用点运算符(.)用来表示“名为xxx的对象的xxx成员”,例如常见的cin.get()。点运算符只能用于类类型的对象。
其左侧运算对象必须是一个类类型的对象,右侧运算对象必须是该类类型的一个成员名,运算结果为右侧对象指定成员。

当访问一个成员函数(方法)时,我们想要调用该方法,则需要使用调用运算符(())。在其内放置实参(argument)列表。

posted @ 2023-05-10 14:42  木木亚伦  阅读(82)  评论(0编辑  收藏  举报