程序员修炼之道:程序设计入门30讲
上QQ阅读APP看书,第一时间看更新

1.#include, using namespace std, int main分别是什么意思?我的第一个C程序

本节的目的就是让读者看一看C++程序长什么样,更重要的,我们希望读者能把原来初学时不明白的地方都弄明白。通过本节,读者会对C++有一个大体的认识。本节的知识较为基础,如果对于示例代码1.1没有任何疑问,完全可以跳过本节。如果对Java语言更感兴趣,也可以直接进入下一节。

Hello world!

相信每个程序员接触的第一个程序都是“Hello world”,我们要认识的第一个C++程序也不例外。

示例代码1.1

    #include <iostream>
    #define HELLO_WORLD "Hello world!"
    using namespace std;
    int main()
    {
       cout<<HELLO_WORLD<<endl;
       return 0;
    }

文件包含

示例代码1.1的第一行#include <iostream>是文件包含指令,该指令的作用是在编译预处理时,将指定源文件的内容复制到当前源文件中,如图1.1所示。以示例代码1.1为例,在该段代码被编译之前,iostream文件内容会被复制到当前文件的起始位置,替代原先的#include <iostream>。为什么要在文件的第一行写这样一句指令呢?我们希望在屏幕上打印“Hello world”,就需要用到标准输出cout,这是一个负责程序对外输出的对象,而该对象是在iostream文件中定义的。简单地说,iostream文件为我们提供了输入输出功能。

图1.1 文件包含指令作用示意图

读者你也许注意到了,在#include <iostream>后面并没有添加分号,所以这一行并不是一条C语句,而是一个预处理指令。预处理指令是编译器在将程序编译为机器语言之前首先会对程序进行的预处理。常见的预处理指令包括文件包含、宏定义和条件编译,接下来我们进一步了解宏定义的概念。

宏定义

示例代码1.1的第二行#define HELLO_WORLD "Hello world!"是一条宏定义,该指令的作用是在编译预处理时,将源文件中所有的HELLO_WORLD都替换为"Hello world!",于是示例代码1.1的第6行cout<<HELLO_WORLD<<endl;会变为cout<<"Hello world!"<<endl;。宏定义也是一种预处理指令,该指令在编译器编译之前被执行。

很多初学C语言的同学分不清宏定义与const常量的区别。宏定义只是在编译预处理阶段进行替换,并不会在内存中生成对应的变量。而const常量是一个在内存中分配了空间的只读变量。所以这两者有本质上的区别。

命名空间

示例代码1.1的第三行using namespace std;表示使用命名空间std。命名空间是指各种标识符的可见范围。C++标准程序库中的所有标识符都被定义在一个std的命名空间中。如果不在示例代码中使用using namespace std;这一行语句,想要使代码通过编译,就需要将示例代码第6行的cout<<HELLO_WORLD<<endl;修改为std::cout<<HELLO_WORLD<<std::endl;。

我们可以将命名空间想象成区号,将类名想象为一个电话号码。由于各省市的电话号码可能重复,就通过在电话号码前面加上区号使得该号码成为一个独一无二的表示。Java中也有类似的机制,包名就如同区号,类名就如同电话号码。

main函数

接下来代码进入了主体部分——main函数。main函数是C++程序的入口函数,是程序执行的起点。该函数与其他的函数在形式上没有什么区别,也由返回类型、函数名和函数参数组成。

返回类型:C++规定,main函数返回类型是int型。返回值用于告诉程序的调用者(即操作系统),程序的退出状态。若返回0,则表示程序正常退出,若返回其他非0值,表示程序异常退出,返回其他数字的含义由系统决定。所以在示例代码1.1的第7行,我们定义了语句return 0;用来告诉操作系统,函数正常执行完毕。该返回值并不属于打印到屏幕上的内容,很多初学者在一开始会混淆返回值和标准输出的概念。

函数参数:C++中,main函数一共有以下两种定义方式:

    int main( )
    int main( int argc, char *argv[] )

示例代码1.1采用的是第一种定义方式,即没有函数参数。本章最后的进阶部分给出了采用第二种定义方式的示例代码1.2,并阐述了函数参数所表达的意义。

函数主体:我们通过语句cout<<HELLO_WORLD<<endl;打印"Hello world!"到屏幕。cout是标准输出流对象,调用后会向输出设备输出内容;<<负责向对象cout发送输出的字符串;endl也是iostream中定义的一个对象,向标准输出发送endl类似于在控制台窗口中按下Enter键。

示例代码1.1的运行结果如图1.2所示。

图1.2 示例代码1.1的运行结果

进阶

对于main函数的第二种定义方式,argc表示传入main函数的参数的个数,argv[]存放着这些参数,在argv[]的这些参数中,第一个参数是程序的全名。我们提供一个以第二种方式定义main函数的程序,见示例代码1.2。

示例代码1.2

    #include <iostream>
    using namespace std;
    int main(int argc, char *argv[])
    {
       cout<<argv[1]<<" "<<argv[2]<<endl;
       cout<<argv[0]<<endl;
       return 0;
    }

在示例代码1.2的第5行cout<<argv[1]<<" "<<argv[2]<<endl;中,我们向标准输出打印了argv[]的第二和第三个参数,而在第6行,我们向标准输出打印了argv[]的第一个参数,为了验证该参数即为程序的全名。

我们在Visual Studio中设置向main函数传入的参数,第一个参数为Hello,第二个参数为world!,两个参数之间以空格隔开,如图1.3所示。

示例代码1.2的运行结果如图1.4所示。

图1.3 main函数参数设置

图1.4 示例代码1.2的运行结果

如图1.4所示,程序第一行输出了"Hello world!",即我们向main函数传递的参数。程序第二行输出了程序的全名,即argv[0]。