C++学习记录20--endl,'\n',\n

2024-04-14 06:38
文章标签 c++ 学习 记录 20 endl

本文主要是介绍C++学习记录20--endl,'\n',\n,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自:

  • http://blog.csdn.net/k346k346/article/details/49981695
  • http://blog.csdn.net/github_35383443/article/details/52040312

一、endl说明

1、endl的本质
cout<<”Hello world”<<endl;

由于endl会导致输出的文字换行,自然而然地我们会想到endl可能就是换行符’\n’。

但是,如果我们定义char c=endl;会得到一个编译错误,这说明endl并不是一个字符,所以应该到系统头文件中去查找endl的定义。通过VS2012转到定义,找到了endl的定义如下:

template<class _Elem,class _Traits> inline basic_ostream<_Elem, _Traits>&
__CLRCALL_OR_CDECL endl(basic_ostream<_Elem, _Traits>& _Ostr)
{   // insert newline and flush stream_Ostr.put(_Ostr.widen('\n'));_Ostr.flush();return (_Ostr);
}

从定义中看出,endl是一个函数模板,它实例化之后变成一个模板函数,其作用如这个函数模板的注释所示,插入换行符并刷新输出流。其中刷新输出流指的是将缓冲区的数据全部传递到输出设备并将输出缓冲区清空。

2、cout<< endl的介绍

endl是一个函数模板,再被使用时会实例化为模板函数。但是函数调用应该使用一对圆括号,也就是写成endl()的形式,而在语句cout<<”Hello world”<<endl;中并没有这样,原因何在?

在头文件iostream中,有这样一条申明语句:extern ostream& cout;这说明cout是一个ostream类对象。而<<原本是用于移位运算的操作符,在这里用于输出,说明它是一个经过重载的操作符函数。如果把endl当做一个模板函数,那么cout<

typedef basic_ostream<char, char_traits<char> > ostream;

所以,实际上应该在类模板basic_ostream中查找operator<<()的重载版本。在头文件ostream中查找basic_ostream的定义,发现其中operator<<作为成员函数被重载了17次,其中的一种:

typedef basic_ostream<_Elem, _Traits> _Myt;_Myt& __CLR_OR_THIS_CALL operator<<(_Myt& (__cdecl *_Pfn)(_Myt&))
{   // call basic_ostream manipulator_DEBUG_POINTER(_Pfn);return ((*_Pfn)(*this));
}

在ostream类中,operator<<作为成员函数重载方式如下:
这个重载正好与endl函数的申明相匹配,所以<<后面是可以跟着endl 。也就是说,cout对象的<<操作符接收到endl函数的地址后会在重载的操作符函数内部调用endl函数,而endl函数会结束当前行并刷新输出缓冲区。

为了证明endl是一个 函数模板,或者说endl是一个经过隐式实例化之后的模板函数,我们把程序改造如下:

#include <iostream>
using namespace std;
int main()
{cout<<"Hello world"<<&endl;
}

这个程序可以正常运行,并且结果完全同上一个程序。原因是对于一个函数而言,函数名本身就代表函数的入口地址,而函数名前加&也代表函数的入口地址。

3、endl其实是IO操纵符

实际上,endl被称为IO操纵符,也有翻译成IO算子的。IO操作符的本质是自由函数,他们并不封装在某个类的内部,使用时不采用显示的函数调用的形式。在< iostream>头文件中定义的操纵符有:

    endl:输出时插入换行符并刷新流endls:输出时在字符 插入NULL作为尾符flush:刷新缓冲区,把流从缓冲区输出到目标设备,并清空缓冲区ws:输入时略去空白字符dec:令IO数据按十进制格式hex:令IO数据按十六进制格式oct:令IO数据按八进制格式

在< iomanip>头文件中定义的操作符有:

    setbase(int)resetiosflags(long)setiosflags(long)setfill(char)setprecision(int)setw(int)

这些格式控制符大致可以替代ios的格式函数成员的功能,且使用比较方便。例如,为了把整数345按16进制输出,可以采用两种方式:

    int i=345;cout.setf(ios::hex,ios::basefield);cout<<i<<endl;

或者:

cout<<hex<<i<<endl;

可以看出采用格式操纵符比较方便,二者的区别主要在于:格式成员函数是标准输出对象cout的成员函数,因此在使用时必须和cout同时出现,而操纵符是自由函数,可以独立出现,使用格式成员函数要显示采用函数调用的形式,不能用IO运算符”<<”和”>>”形成链式操作。

4、自定义格式操纵符

除了利用系统预定义的操纵符来进行IO格式的控制外,用户还可以自定义操纵符来合并程序中频繁使用的IO读写操作。定义形式如下:
输出流自定义操纵符:

ostream &操纵符名(ostream &s)
{自定义代码return s;
}

输入流自定义操纵符:

istream &操纵符名(istream &s{自定义代码return s;
}

示例代码如下:

#include <iostream>
#include <iomanip>
using namespace std;std::ostream& OutputNo(std::ostream& s)//编号格式如:0000001{s<<std::setw(7)<<std::setfill('0')<<std::setiosflags(std::ios::right);return s;}std::istream& InputHex (std::istream& s)//要求输入的数为十六进制数{s>>std::hex;return s;}int main()
{std::cout<<OutputNo<<8<<std::endl;int a;std::cout<<"请输入十六进制的数:";std::cin>> InputHex >>a;std::cout<<"转化为十进制数:"<<a<<std::endl;return 0;
}

这里写图片描述

程序中OutputNo和InputHex都是用户自定义的格式操纵符,操作符的函数原型必须满足cout对象的成员函数operator<<()的重载形式

ostream& ostream::operator<<(ostream& (*op)(ostream&));

ostream& ostream::operator<<(ostream& (*op)(ostream&));

二、C++中endl“\n”和‘\n’的区别

“\n” 表示搜索一个字符串,只有一个数据是回车符

‘\n’表示一个字符,两者在输出上是一样的!

endl

  • 在c++中,终端输出换行时,用cout<<......<<endl 与 “\n”都可以,这是初级的认识。但二者有小小的区别,用endl时会刷新缓冲区,使得栈中的东西刷新一次,但用“\n”不会刷新,它只会换行,盏内数据没有变化。但一般情况,二者的这点区别是很小的,在大的程序中可能会用到。建议用endl来换行.
  • endl除了写’\n’进外,还调用flush函数,刷新缓冲区,把缓冲区里的数据写入文件或屏幕.考虑效率就用’\n’.
  • cout<<endl;除了往输出流中插入一个\n还有刷新输出流的作用.
    cout<<endl; 等价于: cout<<\n<<flush;
    在没有必要刷新输出流的时候应尽量使用cout<<'\n';, 过多的endl是影响程序执行效率低下的因素之一.

这篇关于C++学习记录20--endl,'\n',\n的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/902332

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]