学习c++的第八天

目录

引用

C++ 引用 vs 指针

C++ 中创建引用

把引用作为参数

把引用作为返回值

日期 & 时间

当前日期和时间

基本的输入输出

I/O 库头文件

标准输出流(cout)

扩展知识

标准输入流(cin)

标准错误流(cerr)

标准日志流(clog)


引用

C++ 引用 vs 指针

引用很容易与指针混淆,它们之间有三个主要的不同:

  1. 不存在空引用:引用必须连接到一块合法的内存,而不能为null。这意味着在声明引用时,必须将其初始化为一个有效的对象。这很好地保证了引用的安全性,因为它不会指向未知的内存区域。
  2. 不能重新指向其他对象:一旦引用被初始化为一个对象,就不能将它重新指向到另一个对象。引用绑定后不可更改。这使得引用在函数参数传递中更加安全,因为它确保了在函数内部不会意外地修改传入的参数。
  3. 引用必须在创建时被初始化:引用在创建时必须立即初始化为一个对象,而指针可以在任何时间进行初始化。这意味着在使用引用时,我们可以放心地假设它已经被正确初始化并与一个对象相关联,而无需对其进行额外的检查。

需要注意的是,在某些情况下,指针可能更加灵活和有用。例如,当需要动态分配内存或者在函数中返回指向局部变量的指针时,指针是更好的选择。

总之,引用和指针在C++中都是重要的工具,但它们在某些方面有明显的区别。

C++ 中创建引用

在 C++ 中,可以使用“&”符号来声明一个引用。引用是一个变量的别名,它提供了一种简化并改善代码可读性的方式,使得代码更易于理解。以下是创建引用的示例:

#include 

int main() {
    int num = 10;
    int& ref = num;

    std::cout << num << std::endl; // 输出:10
    std::cout << ref << std::endl; // 输出:10

    ref++; // 修改引用也会修改原始变量
    std::cout << num << std::endl; // 输出:11
    std::cout << ref << std::endl; // 输出:11

    return 0;
}

在此示例中,我们首先声明了一个整型变量 num 并将其初始化为10。然后,我们声明了一个引用 ref,它被绑定到 num 变量上。这意味着 ref 现在是 num 的别名,并且两者引用同一块内存地址。

然后,我们使用 ref 来更改变量值,这也会更改 num 的值,因为它们指向相同的变量。最后,我们输出了 num 和 ref 的值,以验证它们确实相同。

需要注意的是,引用必须在声明时初始化,并且不能重新绑定到其他变量。这保证了引用的安全性和稳定性,以避免产生未定义行为。除此之外,在使用引用时,我们无需特别地解引用或使用指针运算符,而是直接像使用变量一样使用它。

引用通常用于函数参数列表和函数返回值。下面列出了 C++ 程序员必须清楚的两个与 C++ 引用相关的重要概念:

把引用作为参数

在 C++ 中,可以将引用作为函数的参数传递,这样可以实现对传入参数的直接修改或访问。使用引用作为参数可以避免拷贝大的对象,提高程序的效率。以下是使用引用作为参数的示例:

#include 

void increment(int& num) {
    num++;
}

int main() {
    int num = 10;
    std::cout << "Before increment: " << num << std::endl;  // 输出:Before increment: 10

    increment(num);
    std::cout << "After increment: " << num << std::endl;  // 输出:After increment: 11

    return 0;
}

在上面的示例中,我们定义了一个名为 increment 的函数,该函数接受一个整型引用作为参数。在函数内部,我们通过引用直接修改传入的参数值。然后,在 main 函数中,我们声明一个整型变量 num 并初始化为 10。我们调用 increment 函数并将 num 作为参数传递。由于传递的是引用,函数中对参数的修改会直接影响到原始变量 num。

最后,我们输出两次 num 的值,分别是递增前和递增后的值。可以看到,通过引用作为参数传递后,函数中的修改对原始变量产生了影响。

需要注意的是,使用引用作为参数传递时,函数内部对参数的修改会直接反映到原始变量上,因此应谨慎使用。此外,传递引用作为参数时,函数的声明和定义中都需要显式地指定参数为引用类型。

把引用作为返回值

在 C++ 中,可以将引用作为函数的返回值。返回引用可以使函数返回一个别名,以便于对函数返回的对象进行修改或访问。这在一些情况下可以提高代码的效率和可读性。以下是使用引用作为返回值的示例:

#include 

int& getLargest(int& num1, int& num2) {
    if (num1 > num2) {
        return num1;
    }
    else {
        return num2;
    }
}

int main() {
    int num1 = 10;
    int num2 = 20;

    int& largest = getLargest(num1, num2);
    largest = 30;

    std::cout << "Largest number: " << largest << std::endl;   // 输出:Largest number: 30
    std::cout << "num1: " << num1 << std::endl;   // 输出:num1: 10
    std::cout << "num2: " << num2 << std::endl;   // 输出:num2: 30

    return 0;
}

在上面的示例中,我们定义了一个名为 getLargest 的函数,该函数接受两个整型引用作为参数,并返回其中较大的那个引用。在函数内部,我们通过比较两个参数的大小确定要返回的引用。

然后,在 main 函数中,我们声明了两个整型变量 num1 和 num2,并将它们分别初始化为 10 和 20。我们调用 getLargest 函数,并将 num1 和 num2 作为参数传递。由于函数返回的是引用,我们可以将其赋值给一个引用变量 largest。

接下来,我们通过 largest 引用修改了其指向的变量的值,即将其修改为 30。由于 largest 引用和 num1 引用同一块内存地址,所以对 largest 的修改也会影响到 num1。

最后,我们输出了 largest 的值以及 num1 和 num2 的值,以验证它们的确发生了改变。

需要注意的是,当将引用作为返回值时,应确保返回的引用不会指向局部变量或临时对象,以避免产生未定义行为。同时,在使用返回引用的函数时,我们需要注意引用的生命周期,确保返回引用所引用的对象仍然有效。

日期 & 时间

C++ 标准库没有提供所谓的日期类型。C++ 继承了 C 语言用于日期和时间操作的结构和函数。为了使用日期和时间相关的函数和结构,需要在 C++ 程序中引用 头文件。

有四个与时间相关的类型:clock_t、time_t、size_t 和 tm。类型 clock_t、size_t 和 time_t 能够把系统时间和日期表示为某种整数。

结构类型 tm 把日期和时间以 C 结构的形式保存,tm 结构的定义如下:

struct tm {
  int tm_sec;   // 秒 (0~60)
  int tm_min;   // 分钟 (0~59)
  int tm_hour;  // 小时 (0~23)
  int tm_mday;  // 当月的日数 (1~31)
  int tm_mon;   // 月份 (0~11)
  int tm_year;  // 年份,其值为实际年份减去1900
  int tm_wday;  // 星期几 (0~6),其中0代表周日
  int tm_yday;  // 当年的天数 (0~365)
  int tm_isdst; // 夏令时标识符,正常为0,表示当前时区不使用夏令时
};

C++ 标准库提供了一些函数和结构来处理日期和时间操作。下面是一些常用的函数和结构:

  1. time_t time(time_t *time):该函数返回系统的当前日历时间,自 1970 年 1 月 1 日以来经过的秒数。如果系统没有时间,则返回 -1。可以通过传入一个 time_t 类型的指针来获取当前时间。
  2. char *ctime(const time_t *time):该函数将 time_t 类型的时间转换为一个表示本地时间的字符串,并返回一个指向该字符串的指针。字符串的格式为 "day month year hours:minutes:seconds year\n\0"。
  3. struct tm *localtime(const time_t *time):该函数将 time_t 类型的时间转换为一个 tm 结构指针,其中包含了表示本地时间的各个字段信息,如秒、分钟、小时、日期等。
  4. clock_t clock(void):该函数返回程序执行起(一般为程序的开头),处理器时钟所使用的时间。如果时间不可用,则返回 -1。
  5. char *asctime(const struct tm *time):该函数将 tm 结构指针表示的时间转换为一个字符串,并返回一个指向该字符串的指针。字符串的格式为 "day month date hours:minutes:seconds year\n\0"。
  6. struct tm *gmtime(const time_t *time):该函数将 time_t 类型的时间转换为一个 tm 结构指针,其中包含了表示格林尼治标准时间(GMT)的各个字段信息。
  7. time_t mktime(struct tm *time):该函数将一个 tm 结构指针表示的时间转换为一个 time_t 类型的时间。
  8. double difftime(time_t time2, time_t time1):该函数返回两个 time_t 类型时间之间相差的秒数。
  9. size_t strftime():该函数用于格式化日期和时间为指定的格式,并返回格式化后的字符串长度。可以将 tm 结构中的日期和时间信息按照指定的格式打印或存储到字符串中。

当前日期和时间

tm 结构在 C/C++ 中处理日期和时间相关的操作时,显得尤为重要。tm 结构以 C 结构的形式保存日期和时间。大多数与时间相关的函数都使用了 tm 结构。

下面是一个使用 C++ 标准库来获取当前系统时间、本地时间和协调世界时(UTC)的例子:

#define _CRT_SECURE_NO_WARNINGS

#include 
#include 
#include 

using namespace std;
using namespace std::chrono;

int main()
{
	// 获取当前系统时间
	system_clock::time_point now = system_clock::now();

	// 转换为 time_t 类型的本地时间和协调世界时(UTC)
	time_t now_t = system_clock::to_time_t(now);
	struct tm* local_tm = localtime(&now_t);
	struct tm* utc_tm = gmtime(&now_t);

	// 输出本地时间和协调世界时(UTC)
	char buf[100];
	strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", local_tm);
	cout << "Local time: " << buf << endl;

	strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", utc_tm);
	cout << "UTC: " << buf << endl;

	return 0;
}

输出结果为:

Local time: 2023-11-04 02:51:55
UTC: 2023-11-04 02:51:55

在这个例子中,我们首先使用 system_clock::now() 函数获取当前系统时间的时间点。然后,我们将该时间点转换为 time_t 类型的时间,并使用 localtime() 和 gmtime() 函数将其转换为本地时间和协调世界时(UTC)。最后,我们使用 strftime() 函数将时间格式化为指定的格式,并将其输出到控制台上。

在 strftime() 函数中,第一个参数 buf 是输出字符串的缓冲区,第二个参数 sizeof(buf) 是缓冲区的大小,第三个参数是输出字符串的格式,其中 %Y-%m-%d %H:%M:%S 表示输出年、月、日、小时、分钟和秒,各字段之间用 - 和 : 连接。

基本的输入输出

C++ 的 I/O 发生在流中,流是字节序列。如果字节流是从设备(如键盘、磁盘驱动器、网络连接等)流向内存,这叫做输入操作。如果字节流是从内存流向设备(如显示屏、打印机、磁盘驱动器、网络连接等),这叫做输出操作

I/O 库头文件

在C++编程中,以下头文件对于I/O操作是很重要的:

  • :该头文件定义了cin、cout、cerr 和 clog对象,分别对应于标准输入流、标准输出流、非缓冲标准错误流和缓冲标准错误流。通过使用这些对象,可以进行从控制台读取输入和向控制台输出数据。
  • :该头文件提供了一些参数化的流操纵器(如setw和setprecision),用于声明执行标准化I/O时有用的服务。这些操纵器可以用来设置输出字段的宽度、精度等。
  • :该头文件为用户控制的文件处理声明服务。它提供了用于打开、读取、写入和关闭文件的类和函数。通过使用这些类和函数,可以进行文件的输入和输出操作。

这些头文件是C++标准库提供的,可以在C++程序中使用它们来处理输入和输出。例如,可以使用cin对象从控制台读取用户输入,使用cout对象向控制台输出数据,使用fstream类来读写文件等。

下面是一个简单的示例,演示了如何使用这些头文件进行基本的输入和输出操作:

#include 
#include 
#include 
#include 

int main() {
    // 输入输出到控制台
    int num;
    std::cout << "请输入一个整数: ";
    std::cin >> num;
    std::cout << "你输入的整数是: " << num << std::endl;

    // 输入输出到文件
    std::ofstream outputFile("output.txt");
    if (outputFile.is_open()) {
        outputFile << "这是一行文本" << std::endl;
        outputFile.close();
    }

    std::ifstream inputFile("input.txt");
    if (inputFile.is_open()) {
        std::string line;
        while (std::getline(inputFile, line)) {
            std::cout << line << std::endl;
        }
        inputFile.close();
    }

    return 0;
}

在这个示例中,我们使用iostream头文件中的cin和cout对象来进行基本的控制台输入和输出。同时,我们使用fstream头文件中的ofstream和ifstream类来进行文件的写入和读取操作。

值得注意的是,要正确使用文件流,需要确保文件存在且可访问。上述示例中,我们假设存在名为output.txt和input.txt的文件。

这些头文件提供了丰富的工具和功能,可以满足各种输入和输出需求,使得C++编程中的I/O操作更加灵活和方便。

标准输出流(cout)

标准输出流 cout 是 C++ 标准库中最常用的流之一,它用于向控制台或终端输出数据。cout 是一个对象,属于 std 命名空间,定义在 头文件中。

使用 cout 可以将数据输出到标准输出。以下是一些使用 cout 的示例:

#include 

int main() {
    int number = 10;
    std::cout << "Hello, world!" << std::endl;  // 输出字符串:Hello, world!
    std::cout << "The value of number is: " << number << std::endl;  // 输出变量值:The value of number is : 10

    double pi = 3.14159;
    std::cout << "The value of pi is: " << pi << std::endl;  // 输出浮点数:The value of pi is : 3.14159

    return 0;
}

在上述示例中,我们使用 << 运算符将数据插入到 cout 流中,并使用 std::endl 操纵符来插入换行符。std::endl 可以实现换行并刷新输出缓冲区。

cout 对象还支持格式化输出,可以使用 std::setw() 和 std::setprecision() 等操纵器来设置输出字段的宽度和精度。例如:

#include 
#include 

int main() {
    double pi = 3.14159;
    std::cout << "Default precision: " << pi << std::endl;    //输出结果:Default precision : 3.14159
    std::cout << std::setprecision(4) << "Precision 4: " << pi << std::endl;    //输出结果:Precision 4 : 3.142
    std::cout << std::setprecision(2) << "Precision 2: " << pi << std::endl;    //输出结果:Precision 2 : 3.1

    int num = 25;
    std::cout << "Default width: " << num << std::endl;      //输出结果:Default width : 25
    std::cout << std::setw(6) << "Width 6: " << num << std::endl;              //输出结果:Width 6 : 25
    std::cout << std::setw(2) << "Width 2: " << num << std::endl;              //输出结果:Width 2 : 25

    return 0;
}





 在上述示例中,我们使用 std::setprecision() 设置浮点数的输出精度,使用 std::setw() 设置整数的输出宽度。

除了上述示例中的基本用法外,cout 还可以与其他流操纵符和 C++ 中的各种数据类型一起使用,以实现更复杂的输出需求。通过灵活使用 cout,可以方便地输出各种数据类型和格式的内容到控制台。

扩展知识

  • cout.setf 和 setiosflags 是相同的,它们都是用来设置输出流的格式标志位的。通过这些标志位,我们可以控制输出流的各种格式,如数值的显示方式、对齐方式等。
  • cout.precision 和 setprecision 也是相同的,它们都是用来设置浮点数的精度的。通过设置精度,我们可以控制浮点数输出的小数位数。
  • cout.unsetf 和 resetiosflags 是相同的,它们都是用来清除输出流的格式标志位的。通过这些函数,我们可以将之前设置的标志位恢复到默认状态。

cout.setf 常见的标志:

标志 功能
boolalpha 可以使用单词”true”和”false”进行输入/输出的布尔值.
oct 用八进制格式显示数值.
dec 用十进制格式显示数值.
hex 用十六进制格式显示数值.
left 输出调整为左对齐.
right 输出调整为右对齐.
scientific 用科学记数法显示浮点数.
fixed 用正常的记数方法显示浮点数(与科学计数法相对应).
showbase 输出时显示所有数值的基数.
showpoint 显示小数点和额外的零,即使不需要.
showpos 在非负数值前面显示”+(正号)”.
skipws 当从一个流进行读取时,跳过空白字符(spaces, tabs, newlines).
unitbuf 在每次插入以后,清空缓冲区.
internal 将填充字符回到符号和数值之间.
uppercase 以大写的形式显示科学记数法中的”e”和十六进制格式的”x”.

iostream 中定义的操作符:

操作符 描述 输入 输出
boolalpha 启用boolalpha标志
dec 启用dec标志
endl 输出换行标示,并清空缓冲区
ends 输出空字符
fixed 启用fixed标志
flush 清空流
hex 启用 hex 标志
internal 启用 internal 标志
left 启用 left 标志
noboolalpha 关闭boolalpha 标志
noshowbase 关闭showbase 标志
noshowpoint 关闭showpoint 标志
noshowpos 关闭showpos 标志
noskipws 关闭skipws 标志
nounitbuf 关闭unitbuf 标志
nouppercase 关闭uppercase 标志
oct 启用 oct 标志
right 启用 right 标志
scientific 启用 scientific 标志
showbase 启用 showbase 标志
showpoint 启用 showpoint 标志
showpos 启用 showpos 标志
skipws 启用 skipws 标志
unitbuf 启用 unitbuf 标志
uppercase 启用 uppercase 标志
ws 跳过所有前导空白字符

iomanip 中定义的操作符:

操作符 描述 输入 输出
resetiosflags(long f) 关闭被指定为f的标志
setbase(int base) 设置数值的基本数为base
setfill(int ch) 设置填充字符为ch
setiosflags(long f) 启用指定为f的标志
setprecision(int p) 设置数值的精度(四舍五入)
setw(int w) 设置域宽度为w

标准输入流(cin)

标准输入流(cin)是C++中用于从用户输入读取数据的输入流对象。它是iostream库中的一个对象,用于与键盘或其他输入设备进行交互。

使用cin对象可以接收不同类型的输入数据,如整数、浮点数、字符、字符串等。以下是一些常见的用法:

1、读取整数:

int num;
cin >> num;

2、读取浮点数:

float num;
cin >> num;

3、读取字符:

char ch;
cin >> ch;

4、读取字符串:

string str;
cin >> str;

需要注意的是,cin以空格、制表符或换行符作为数据的分隔符。当使用>>运算符读取数据时,它会自动忽略前导空白字符,并在遇到分隔符时停止读取。

此外,cin还提供了一些其他功能和成员函数,如判断是否达到文件末尾(eof())、清除错误状态(clear())、忽略指定数量的字符(ignore())等。

以下是一个示例,演示如何使用cin读取用户输入的整数并进行计算:

#include 

int main() {
    int num1, num2;

    std::cout << "Enter the first number: ";
    std::cin >> num1;

    std::cout << "Enter the second number: ";
    std::cin >> num2;

    int sum = num1 + num2;
    std::cout << "The sum is: " << sum << std::endl;

    return 0;
}

以上代码将提示用户输入两个整数,并计算它们的和,最后输出结果。

总之,标准输入流(cin)是C++中用于从用户输入读取数据的对象。它的使用方式简单且灵活,可以方便地获取用户的输入并进行相应的处理。

标准错误流(cerr)

标准错误流(cerr)是C++中用于输出错误信息的输出流对象。它是iostream库中的一个对象,用于将错误信息输出到屏幕或其他错误输出设备。

与标准输出流(cout)不同,标准错误流不受缓冲区的影响,即错误信息不会被缓存,而是立即输出到目标设备。这使得错误信息能够及时地显示给用户,而不会因为缓冲而产生延迟。

使用cerr对象输出错误信息非常简单,只需使用插入运算符(<<)将错误信息插入到cerr对象中即可。以下是一个示例:

#include 

int main() {
    int dividend = 10;
    int divisor = 0;
    
    if (divisor == 0) {
        std::cerr << "Error: Division by zero!" << std::endl;
    } else {
        int result = dividend / divisor;
        std::cout << "Result: " << result << std::endl;
    }
    
    return 0;
}

在上述示例中,当除数为0时,我们使用cerr对象输出错误信息"Error: Division by zero!"。该错误信息将会立即显示在屏幕上,不会被缓存。

除了使用cerr对象,还可以使用标准错误流的另一个对象——clog。clog与cerr类似,也是用于输出错误信息的对象,但与cerr不同的是,clog的输出可以被缓存。这意味着错误信息可以在一定条件下进行缓冲,然后一次性输出。这在某些情况下可能更有利于错误信息的处理。

总结起来,标准错误流(cerr)是C++中用于输出错误信息的对象,不受缓冲区影响,能够及时地将错误信息输出到目标设备。它与标准输出流(cout)一起提供了一种方便的方式来管理程序的输入和输出。

标准日志流(clog)

标准日志流(clog)是C++中的一个预定义对象,也是iostream库中的一个输出流对象。类似于标准错误流cerr,clog也用于输出程序的日志信息。不同的是,clog对象会缓存输出的日志信息,并在一定条件下进行刷新,以提高程序的效率。

使用clog对象输出日志信息与使用cerr对象非常类似,只需使用插入运算符(<<)将日志信息插入到clog对象中即可。以下是一个示例:

#include 

int main() {
    int x = 10;
    int y = 20;

    std::clog << "Starting calculation..." << std::endl;

    //执行一些计算并输出中间结果
        for (int i = 1; i <= 10; i++) {
            int result = x * i + y;
            std::clog << "Iteration " << i << ": Result = " << result << std::endl;
        }

    std::clog << "Calculation completed." << std::endl;

    return 0;
}

在上述示例中,我们使用clog对象输出了程序的日志信息,包括开始计算、每次迭代的结果以及计算完成等。这些日志信息被缓存在clog对象中,并在程序执行完毕后一次性输出。

需要注意的是,clog对象的输出可以被缓存,但并不保证缓冲区满后就会立即输出。因此,在需要立即输出日志信息的场景下,建议使用cerr对象。

总之,标准日志流(clog)是C++中用于输出程序日志信息的对象。它与标准输出流(cout)和标准错误流(cerr)一起提供了一种方便的方式来管理程序的输入和输出。

你可能感兴趣的:(C++,学习,c++,开发语言)