基础框架
一个基础程序框架:
1 |
|
<iostream>
#include <stdio.h>
和 #include <iostream>
是C和C++编程语言中用于包含标准输入输出库的头文件语句。该编译指令导致预处理器将iostream文件的内容添加到程序中。#include编译指令导致iostream文件的内容随源
代码文件的内容一起被发送给编译器。实际上,iostream文件的内容将
取代程序中的代码行#include
注意:
将源代码文件和iostream组合成一个复合文件,编译的下一阶段将使用
该文件。
下面是这两条语句之间的主要区别:
1. 语言差异
#include <stdio.h>
是C语言的标准输入输出库头文件。stdio.h
是 “standard input-output header” 的缩写,它是C语言的一部分。#include <iostream>
是C++语言的标准输入输出库头文件。iostream
是 “input-output stream” 的缩写,它是C++语言的一部分。
2. 库类型
stdio.h
提供的是C语言风格的输入输出函数,例如printf()
,scanf()
,fprintf()
,fscanf()
等。这些函数通常是非面向对象的,并且它们直接处理字符和字节流。iostream
提供的是C++语言风格的输入输出流类,例如std::cout
,std::cin
,std::cerr
, 以及std::ofstream
,std::ifstream
等。这些是面向对象的,提供了更多的功能,例如类型安全和重载操作符。
3. 使用方式
- 使用
stdio.h
时,程序员通常需要指定格式化字符串,并且要注意类型匹配,以避免格式化错误或缓冲区溢出。 - 使用
iostream
时,类型信息是自动处理的,因为流操作符(如<<
和>>
)被重载以支持不同的数据类型。
4. 性能
stdio.h
中的函数通常比C++的iostream库更快,因为iostream库进行了更多的封装和类型检查。然而,现代编译器已经优化了iostream库,使得性能差距不像过去那样显著。
5. 头文件扩展名
- 注意到
stdio.h
有一个.h
扩展名,而iostream
没有。在C++中,标准库的头文件通常不带.h
扩展名。这是为了区分C和C++的标准库头文件。
6. 命名空间
iostream
中的对象和函数都是在std
命名空间中的,所以通常需要使用std::
前缀来访问它们,除非你使用了using namespace std;
语句。stdio.h
中的函数通常不需要命名空间前缀。
举例
以下是如何使用这两个头文件的简单例子:
使用 stdio.h
:
1 |
|
使用 iostream
:
1 |
|
总结来说,#include <stdio.h>
和 #include <iostream>
分别用于C和C++中处理输入输出,它们代表了两种不同的编程范式和风格。在实际使用中,应根据编程语言和项目需求选择合适的头文件。
using namespace
1 | using namespace std; |
这个using编译指令使得std名称空间中的所有名称都可用。这是一种偷懒的做法,在大型项目中一个潜在的问题。更好的方法是,只使所需的名称可用,这可以通过使用using声明来实现:
1 | using std::cout; |
使用cout进行C++输出
1 | cout << "Hello World" << endl; |
- 在C++中,用双引号括起的一系列字符叫做字符串,因为它是由若干字符组合而成的。
- <<符号表示该语句将把这个字符串发送给cout;该符号指出了信息流动的路径。
- cout是一个预定义的对象,知道如何显示字符串、数字和单个字符等
从概念上看,输出是一个流,即从程序流出的一系列字符。cout对象表示这种流,其属性是在iostream文件中定义的。cout的对象属性包括一个插入运算符(<<),它可以将其右侧的信息插入到流中。
因此,与其说程序显示了一条消息,不如说它将一个字符串插入到了输出流中。
初识运算符重载
如果熟悉C后才开始学习C++,则可能注意到了,插入运算符(<<)看上去就像按位左移运算符(<<),这是一个运算符重载的例子,通过重载,同一个运算符将有不同的含义。编译器通过上下文来确定运算符的含义。C本身也有一些运算符重载的情况。例如,&符号既表示地址运算符,又表示按位AND运算符;* 既表示乘法,又表示对指针解除引用。这里重要的不是这些运算符的具体功能,而是同一个符号可以有多种含义,而编译器可以根据上下文来确定其含义(这和确定“sound card”中的“sound”与“sound financial basic”中的“sound”的含义是一样的)。C++扩展了运算符重载的概念,允许为用户定义的类型(类)重新定义运算符的含义。
确实,C++中的 std::cout
可以用来输出不同类型的数据,包括整数和字符串。虽然从用户的角度来看,输出数字和字符串似乎没有太大区别,但在幕后,这两者处理方式是不同的。以下是详细解释:
- 字符串
- 字符串是由一系列字符组成的序列。在C++中,字符串通常表示为
std::string
类型或者以空字符\0
结尾的字符数组char[]
。 - 当
std::cout
输出字符串时,它会从内存中读取每个字符的编码(通常是ASCII或UTF-8编码),并将其逐个发送到输出设备。 - 例如,字符串
"25"
在内存中存储为两个字符:字符'2'
和字符'5'
,以及一个结束标记\0
。
- 字符串是由一系列字符组成的序列。在C++中,字符串通常表示为
- 整数
- 整数在计算机内部以二进制形式存储。例如,整数
25
在内存中以二进制形式表示,可能看起来像00011001
(这取决于具体的系统架构和整数的大小)。 - 当
std::cout
输出整数时,它不能直接将二进制数发送到输出设备,因为输出设备期望接收字符编码,而不是二进制数值。 - 因此,
std::cout
必须将整数转换为字符串形式。这个过程称为数值到字符串的转换,涉及以下步骤:
- 计算整数的每一位数字。
- 将这些数字转换为对应的字符。
- 将这些字符按正确的顺序组合成字符串。
- 输出字符串。
- 整数在计算机内部以二进制形式存储。例如,整数
- 自动类型转换
- 在C++中,
std::cout
使用操作符重载来处理不同类型的数据。当std::cout
遇到一个整数时,它会调用一个专门的重载版本的操作符<<
,这个版本知道如何将整数转换为字符串。 - 这个转换过程是自动进行的,所以程序员不需要编写额外的代码来将整数转换为字符串。这是C++的面向对象特性之一,允许操作符根据操作数的类型进行不同的操作。
- 在C++中,
endl
endl
是一个操纵符(manipulator),它在iostream库中被定义为输出一个换行符(通常是 \n
),并紧接着刷新输出缓冲区。刷新输出缓冲区意味着缓冲区中的所有数据都会被发送到输出设备(通常是屏幕),确保了这些数据在程序继续执行之前被立即显示。\n
是一个转义字符,用于在字符串中插入一个换行符。当使用 \n
时,iostream库会将一个换行符写入输出缓冲区,但不会立即刷新缓冲区。这意味着输出可能暂时留在缓冲区中,直到缓冲区满了或者程序结束,这时缓冲区才会被刷新。
system(“pause”);
不加:
加上:
system("pause");
是一个在C或C++程序中常用的语句,它用于暂停程序的执行,直到用户按下任意键。这个语句调用了操作系统的命令行界面来执行 pause
命令。
下面是对 system("pause");
语句的详细解释:
1. 作用
system("pause");
的主要作用是在程序执行完毕后暂停程序,尤其是在命令行界面(CLI)中运行程序时。这样可以让用户有机会查看程序的输出结果,而不是立即关闭命令行窗口。
2. 工作原理
system
是C和C++标准库中的一个函数,它位于<cstdlib>
或<stdlib.h>
头文件中。- 当调用
system
函数时,它会创建一个新的进程来执行其参数指定的命令。在system("pause");
中,参数是字符串"pause"
。 - 在Windows操作系统中,
pause
命令会暂停命令行进程,并显示消息"Press any key to continue . . ."
。用户必须按下任意键才能继续执行程序或关闭命令行窗口。
3. 跨平台问题
system("pause");
主要用于Windows操作系统。在Unix-like系统(如Linux或macOS)中,pause
命令通常不存在,因此这条语句在这些系统中不会按预期工作。- 为了实现跨平台兼容性,通常建议使用其他方法来暂停程序,例如在Unix-like系统中使用
getchar();
来实现类似的效果。
4. 安全性和性能
- 使用
system
函数通常不被认为是安全的,因为它会执行传递给它的任何命令,这可能导致安全漏洞,尤其是当命令包含用户输入时。 - 调用
system
函数创建新进程可能会影响程序的性能,因为它涉及到操作系统的进程管理。
5. 替代方案
- 如果你只是想等待用户按键,而不是关闭命令行窗口,可以使用以下代码作为替代方案,它具有更好的跨平台兼容性:或者,在Unix-like系统中:
1
2
3
4
5
6
int main() {
std::cout << "Press any key to continue . . ." << std::endl;
std::cin.get(); // 等待用户按键
return 0;
}这些替代方案不需要调用1
2
3
4
5
6
int main() {
printf("Press any key to continue . . .\n");
getchar(); // 等待用户按键
return 0;
}system
函数,因此它们更安全且更适合跨平台使用。
变量
给一段指定的内存空间起名,方便操作这段内存(一下子就清楚了)
使用声明语句来指出存储类型并提供位置标签。
变量存在的意义就是方便我们管理内存空间
常量
用于记录程序中不可更改的数据
定义常量的两种方式:
- #define 宏常量:
1
- const修饰的变量:
在变量定义前加const
Q:#define day 7这样子day代表的7是什么数据类型
在C或C++语言中,使用 #define
预处理器指令来定义宏。宏定义 #define day 7
不会指定数据类型,它仅仅是一个文本替换。当编译器看到 day
时,它会在编译前将其替换为 7
。
由于宏只是简单的文本替换,day
代表的 7
在编译后的代码中并没有特定的数据类型。它的数据类型取决于它被使用的上下文。例如:
- 如果
day
被用在需要整数的地方,它将被当作整数处理。 - 如果
day
被用在需要浮点数的地方,它可能会被隐式转换成浮点数。
下面是一些使用day
的例子,以及它如何根据上下文被解释:在这个例子中,1
2
3
4
5
6
7
8
9
int main() {
int days = day; // day 被当作整数
float days_float = day; // day 被隐式转换成浮点数
printf("Integer: %d\n", days);
printf("Float: %f\n", days_float);
return 0;
}day
被用作整数int
类型的值,也被用作float
类型的值。在编译时,预处理器将day
替换为7
,然后编译器根据变量声明决定7
的数据类型。在第一个例子中,7
是int
类型的,而在第二个例子中,7
被隐式转换为float
类型。
关键字
赋值语句
C++(和C)有一项不寻常的特性—可以连续使用赋值运算符。例如,下面的代码是合法的:
1 | a=b=c=2; |
赋值将从右向左进行。
首先,2被赋给c,然后c的值(2)被赋给b,然后b的值被赋给a;
使用cin
1 | cin >> carrots; |
从这条语句可知,信息从cin流向carrots。显然,对这一过程有更为正式的描述。就像C++将输出看作是流出程序的字符流一样,它也将输入看作是流入程序的字符流。iostream文件将cin定义为一个表示这种流的对象。输出时,<<运算符将字符串插入到输出流中;输入时,cin使用>>运算符从输入流中抽取字符。通常,需要在运算符右侧提供一个变量,以接收抽取的信息(符号<<和>>被选择用来指示信息流的方向)。