【C++】C++入门知识(上)

 好久不见,本篇介绍一些C++的基础,没有特别的主题,话不多说,直接开始。

1.C++的第一个程序

C++中需要把定义文件代码后缀改为 .cpp 

我们在 test.cpp 中来看下面程序

#include <stdio.h>
int main()
{printf("hello world\n");return 0;
}

相信大家再熟悉不过了,这是一个C语言的简单代码,我们运行代码发现也没问题

这是因为C++兼容C语言绝大多数的语法,所以C语言实现的hello world依旧可以运行,当然,C++也有自己的一套输入输出,严格来说C++版本的hello world应该像下面这样写

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

啊?namespace  std是什么啊?cout啥意思啊?<< 这又是啥?......

相信大家初次看到C++的代码一定会有这些疑惑,不着急,我们一个一个来简单看看。

2.命名空间namespace

2.1 namespace的价值

namespace是我们接触的C++的第一个关键字

我们先看下面的程序,从程序现象分析namespace的价值

#include <stdio.h>
int rand = 10;
int main()
{printf("%d\n", rand);return 0;
}

此时,上面的程序可以正常运行,不会报错

但是我们如果加上#include <stdlib.h>呢?

#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main()
{printf("%d\n", rand);return 0;
}

程序就会报下面的错误,说rand重定义了

多加了个头文件程序为什么会重定义呢? 

C语言中有个东西叫命名冲突,在同一域内,不能定义同名的东西。没有包含 <stdlib.h> 时,全局只有一个rand变量,此时没有冲突,程序正常运行,但是,包含 <stdlib.h> 这个头文件后就有问题了,是因为rand是C语言库里的函数,头文件stdlib.h包含这个库函数,所以变量rand和库函数rand两个名字就冲突了

为了解决C语言中命名冲突的问题,C++设计了namespace,命名空间

2.2 namespace的定义

定义命名空间,需要使用namespace关键字,后面跟命名空间的名字,然后接一对{},{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等

2.2.1 namespace定义变量 

以上面的rand为例,定义一个命名空间,命名空间的名字随便起嗷

namespace lyj
{int rand = 10;
}
#include <stdio.h>
#include <stdlib.h>
namespace lyj
{int rand = 10;
}
int main()
{printf("%d\n", rand);return 0;
}

namespace本质是定义出一个域,这个域跟全局域各自独立,不同的域可以定义同名变量

此时再看我们的程序,运行没有报错,变量rand和函数rand已经不在同一个域内了,就不会冲突

虽然程序没有报错,但是报了如下警告

报警告是因为此时这里的rand访问的是全局的函数,并不是命名空间里的变量rand,解除警告可以把%d改成%p,就是打印函数rand的地址。

那我们要访问namespace里的rand怎么访问?

2.2.2 域作用限定符::

我们要知道一个运算符 :: 两个冒号,叫做域作用限定符,先看下面的代码

#include <stdio.h>
int a = 20;
int main()
{int a = 10;printf("%d\n", a);return 0;
}

根据局部优先的规则,我们打印出来的应该是10,而不是20

 

我们用了::这个运算符后,并且::的左边什么也不给(左边留空格只是为了格式好看),就默认去全局查找,如下

	printf("%d\n", ::a);

 那么打印出来的就是20

理解了之后我们回过头来看上面的rand,想要在命名空间查找,::左边就是命名空间的名字,如下

#include <stdio.h>
#include <stdlib.h>
namespace lyj
{int rand = 10;
}
int main()
{printf("%d\n", lyj::rand);return 0;
}

此时就能解决名字冲突的问题,想访问哪个域就访问哪个域

 

C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找一个变量/函数/类型出处(声明或定义)的逻辑,所以有了隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找的逻辑,还会影响变量的生命周期,命名空间域和类域不影响变量的生命周期

2.2.3 namespace定义函数和类型

这里简单举几个例子,比如下面的命名空间,定义了一个简单的函数和结构体

namespace lyj
{int add(int a, int b){return a + b;}struct node{struct node* next;int val;};
}

函数直接指定就行了

int main()
{printf("%d\n", lyj::add(1, 1));return 0;
}

 

定义结构体的话就稍微不同一些 ,命名空间的名字放在struct的后面,结构体名字的前面

int main()
{struct lyj::node p1;return 0;
}

2.2.4 namespace的嵌套定义和合并

namespace只能定义在全局,当然它还可以嵌套定义

namespace group
{namespace zhangsan{int num = 1;int add(int a, int b){return a + b;}}namespace lisi{int num = 2;struct node{struct node* next;int val;};}
}

 比如上面这个例子,就是namespace的嵌套定义。如果我们要分别打印group下面张三的num和李四的num,像下面这样就行了

    printf("%d\n", group::zhangsan::num);printf("%d\n", group::lisi::num);

如果代码复杂一点,有几个头文件和源文件,那此时怎么运用命名空间呢?

其实,不同文件的命名空间,名字相同会自动合并 。当然,这个合并并不是真的合并在一起,只是逻辑上的合并,名字相同的namespace会认为是一个namespace。举个简单例子

Func.h文件中有下面的函数声明

namespace func1
{int Add(int a, int b);int Sub(int a, int b);
}namespace func2
{int Mul(int a, int b);float Div(int a, int b);
}

Func.cpp文件中有下面的函数

#include "Func.h"
namespace func1
{int Add(int a, int b){return a + b;}int Sub(int a, int b){return a - b;}
}
namespace func2
{int Mul(int a, int b){return a * b;}float Div(int a, int b){return (float)a / b;}
}

虽然他们不在同一个文件,但是namespace func1中的内容和namespace func2中的内容都会被分别合并

2.3 C++中 std命名空间

2.3.1 关键字using

我们看下面的例子

namespace lyj
{int a = 1;int b = 2;
}

想要打印namespace里的a和b,就要像下面这样用::去一个个指定

    printf("%d\n", lyj::a);printf("%d\ ", lyj::b);

如果namespace里我们需要用的东西很多,像这样一个个指定真的太麻烦了,那么直接把整个namespace展开可以吗?可以。展开namespace就要用到关键字using。

    using namespace lyj;

加上这句话之后,就可以直接使用namespace里的东西

namespace lyj
{int a = 1;int b = 2;
}
using namespace lyj;
int main()
{printf("%d\n", a);printf("%d\n", b);return 0;
}

 

但是,展开命名空间中所有成员,在实战项目中不推荐,冲突风险很大

假设我在程序中用a用的非常多,不推荐展开全部,一次次展开又太麻烦了,怎么办?

using还可以局部展开。比如说我就展开a。

    using lyj::a;

 使用时,a就不需要用::去指定,可以直接使用,b没展开就要用::指定

2.3.2 std命名空间

C++标准库都放在一个叫std(standard)的命名空间中。

using namespace std;

这句话就是把C++标准库都展开。在日常练习中可以展开,不会有什么风险。

3.C++的输入和输出

<iostream>是 Input Output Stream 的缩写,是标准输入、输出流的,定义了标准的输入、输出对象。

C++的输入输出需要包含这个头文件,就相当于C语言中使用printf我们需要包含<stdio.h>这个头文件。那为什么iostream没有加.h呢?C++标准库版本问题,新版本是不需要加.h的,如果加了.h,证明那个编译器应该是特别老的编译器(比如vc6.0)。

std::cin 是istream类的对象,它主要面向窄字符(narrow characters (of type char))的标准输入流 。

std::cout 是ostream类的对象,它主要面向窄字符的标准输出流。

std::endl 是一个函数(endl是endline的缩写),流插入输出时,相当于插入一个换行字符加刷新缓冲区(目前简单理解为换行符,其实这个函数很复杂)。

这里cin、cout中的c就是窄字符的意思,后面会学宽字符,目前我们遇到的都是窄字符。 

当我们在程序中展开了std,也就是using namespace std; 使用cin, cout, endl时就不需要加std::了,不过展开了std又加上了std:: 程序也不会报错,但有点多此一举了。

<<是流插入运算符,>>是流提取运算符。 

 C语言中用 << 和 >> 作为位运算符,<<是左移运算符,>>是右移运算符。

<<和>>是二元操作符,只能有两个操作数!

到现在,我们可以简单抽象地理解下面这句话了,就是把hello world 和endl 流向cout,而cout就是插入到终端或者控制台,其中endl简单来说就是换行符。

	cout << "hello world" << endl;

 C++输入、输出可以自动识别变量的类型

C语言中的printf和scanf需要手动指定格式,比如输入一个int a ,输出一个float b = 3.14

	int a;float b = 3.14;scanf("%d", &a);printf("%f", b);

而C++中就不需要指定格式,比如下面的cout输出

    int a = 1;float b = 3.14;char c = 'x';cout << a << " " << b << " " << c << endl;

 

再来看看cin输入,也是不需要指定类型的

	int y, z;cin >> y;cin >> z;cout << y << endl << z << '\n';

也可以cin >> y >> z;

 

类型不同也可以。 

还有一点,

在C语言中想要确定小数点的精度,像下面这样就行,

	double d = 2.22222222;printf("%.2lf\n", d);

在C++中小数精度是默认小数点后5位

在C++中可以控制小数点精度吗?可以但是比较复杂。所以我们需要在C++中确定精度的话直接用C语言的printf就行了,反正C++兼容C语言。

由于兼容和缓冲区等复杂原因,C++的cin和cout的IO效率有时候比较低,可以与scanf和printf混着用,在io需求比较高的地方,比如大量输入输出竞赛中,也可以加上下面的三句代码,提高C++IO效率。

	ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);

 

本小篇就到这里,拜拜~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/876726.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL Server 设置端口号:详细步骤与注意事项

目录 一、了解SQL Server端口号的基础知识 1.1 默认端口号 1.2 静态端口与动态端口 二、使用SQL Server配置管理器设置端口号 2.1 打开SQL Server配置管理器 2.2 定位到SQL Server网络配置 2.3 修改TCP/IP属性 2.4 重启SQL Server服务 三、注意事项 3.1 防火墙设置 3…

Java小抄|Java中的List与Map转换

文章目录 1 List<User> 转Map<User.id,User>2 基础类型的转换&#xff1a;List < Long> 转 Map<Long,Long> 1 List 转Map<User.id,User> Map<Long, User> userMap userList.stream().collect(Collectors.toMap(User::getId, v -> v, …

p28 vs环境-C语言实用调试技巧

int main() { int i0; for(i0;i<100;i) { printf("%d",i); } } 1.Debug 和Release的介绍 Debug通常称为调试版本&#xff0c;它包含调试信息&#xff0c;并且不做任何优化&#xff0c;便于程序员调试程序。 Release称为发布版本&#x…

PTPD 在 QNX 系统上的授时精度验证与误差排查

文章目录 0. 引言1.关键函数实现2. 验证策略与结果3. 授时误差的排查与解决3. 授时误差的排查与解决4. 结论 0. 引言 PTPD是一种时间同步的开源实现&#xff0c;在不同操作系统上的表现可能存在显著差异。 本文通过在QNX系统上运行PTPD&#xff0c;针对其授时精度进行详细验证…

探索算法系列 - 双指针

目录 移动零&#xff08;原题链接&#xff09; 复写零&#xff08;原题链接&#xff09; 快乐数&#xff08;原题链接&#xff09; 盛最多水的容器&#xff08;原题链接&#xff09; 有效三角形的个数&#xff08;原题链接&#xff09; 查找总价格为目标值的两个商品&…

优化算法:2.粒子群算法(PSO)及Python实现

一、定义 粒子群算法&#xff08;Particle Swarm Optimization&#xff0c;PSO&#xff09;是一种模拟鸟群觅食行为的优化算法。想象一群鸟在寻找食物&#xff0c;每只鸟都在尝试找到食物最多的位置。它们通过互相交流信息&#xff0c;逐渐向食物最多的地方聚集。PSO就是基于这…

【python_将一个列表中的几个字典改成二维列表,并删除不需要的列】

def 将一个列表中的几个字典改成二维列表(original_list,headersToRemove_list):# 初始化一个列表用于存储遇到的键&#xff0c;保持顺序ordered_keys []# 遍历data中的每个字典&#xff0c;添加其键到ordered_keys&#xff0c;如果该键还未被添加for d in original_list:for …

P4009 汽车加油行驶问题题解

P4009 汽车加油行驶问题 紫题&#xff0c;但是DFS。 思路 记忆化搜索&#xff0c;分多钟情况去搜索。 注意该题不用标记&#xff0c;有可能会往回走。 有可能这样走。 代码 #include<bits/stdc.h> #include<cstring> #include<queue> #include<set&g…

redis:清除缓存的最简单命令示例

清除redis缓存命令(执行命令列表见截图) 1.打开cmd窗口&#xff0c;并cd进入redis所在目录 2.登录redis redis-cli 3.查询指定队列当前的记录数 llen 队列名称 4.清除指定队列所有记录 ltrim 队列名称 1 0 5.再次查询&#xff0c;确认队列的记录数是否已清除

配置和连接另一台电脑上的 MySQL 数据库

要配置和连接另一台电脑上的 MySQL 数据库&#xff0c;可以按照以下步骤进行设置&#xff1a; 1. 配置 MySQL 服务器 在目标计算机上&#xff08;192.168.10.103&#xff09;进行以下操作&#xff1a; 修改 MySQL 配置文件&#xff1a; 打开 MySQL 配置文件&#xff08;通常位…

【系统架构设计师】十八、信息系统架构设计理论与实践①

目录 一、信息系统架构概述 二、信息系统架构风格与分类 2.1 信息系统架构风格 2.2 信息系统架构分类 三、信息系统架构模型 3.1 单体应用 3.2 客户机/服务器 3.2.1 二层 C/S 3.2.2 三层 C/S 和 B/S 3.2.3 多层 C/S 和 B/S 3.2.4 MVC 3.3 面向服务架构(SOA)模式 …

Activiti 本地画流程 http://localhost:8080/activiti-app/#/

http://localhost:8080/activiti-app/#/ 1、本地安装了Tomcat 2、本地安装了Activiti 3、拷贝Activiti中这两个文件到Tomcat中的webapps目录下 4、启动startu.bat 5、http://localhost:8080/activiti-app/#/ 账号&#xff1a;admin 密码&#xff1a;test

乐鑫 Matter 技术体验日回顾|全面 Matter 解决方案驱动智能家居新未来

日前&#xff0c;乐鑫信息科技 (688018.SH) 在深圳成功举办了 Matter 方案技术体验日活动&#xff0c;吸引了众多照明电工、窗帘电机、智能门锁、温控等智能家居领域的客户与合作伙伴。活动现场&#xff0c;乐鑫产研团队的小伙伴们与来宾围绕 Matter 产品研发、测试认证、生产工…

Python学习笔记46:游戏篇之外星人入侵(七)

前言 到目前为止&#xff0c;我们已经完成了游戏窗口的创建&#xff0c;飞船的加载&#xff0c;飞船的移动&#xff0c;发射子弹等功能。很高兴的说一声&#xff0c;基础的游戏功能已经完成一半了&#xff0c;再过几天我们就可以尝试驾驶 飞船击毁外星人了。当然&#xff0c;计…

解析西门子PLC的String和WString

西门子PLC有两种字符串类型&#xff0c;String与WString String 用于存放英文数字标点符号等ASCII字符&#xff0c;每个字符占用一个字节 WString宽字符串用于存放中文、英文、数字等Unicode字符&#xff0c;每个字符占用两个字节 之前我搞过一篇解析String的 关于使用TCP-…

Vue3 Pinia的创建与使用代替Vuex 全局数据共享 同步异步

介绍 提供跨组件和页面的共享状态能力&#xff0c;作为Vuex的替代品&#xff0c;专为Vue3设计的状态管理库。 Vuex&#xff1a;在Vuex中&#xff0c;更改状态必须通过Mutation或Action完成&#xff0c;手动触发更新。Pinia&#xff1a;Pinia的状态是响应式的&#xff0c;当状…

Linux内核 mmap内存映射的实现原理

在Linux内核以及Linux系统编程的时候&#xff0c;经常会碰到mmap内存映射&#xff0c;mmap函数是实现高性能编程的一个关键点。本文详细介绍一下mmap实现原理。 虚拟地址映射物理地址 虚拟地址映射物理地址采用的是页表机制&#xff0c;64位CPU采用的是4级页表。 64位CPU虚拟…

鸿蒙 HarmonyOS NEXT端云一体化开发-认证服务篇

一、开通认证服务 地址&#xff1a;AppGallery Connect (huawei.com) 步骤&#xff1a; 1 进入到项目设置页面中&#xff0c;并点击左侧菜单中的认证服务 2 选择需要开通的服务并开通二、端侧项目环境配置 添加依赖 entry目录下的oh-package.json5 // 添加&#xff1a;主要前…

《python程序语言设计》第6章14题 估算派值 类似莱布尼茨函数。但是我看不明白

这个题提供的公式我没看明白&#xff0c;后来在网上找到了莱布尼茨函数 c 0 for i in range(1, 902, 100):a (-1) ** (i 1)b 2 * i - 1c a / bprint(i, round(4 / c, 3))结果 #按题里的信息&#xff0c;但是结果不对&#xff0c;莱布尼茨函数到底怎么算呀。

PyTorch深度学习快速入门(上)

PyTorch深度学习快速入门&#xff08;上&#xff09; 一、前言&#xff08;一&#xff09;PyTorch环境配置&#xff08;二&#xff09;Python编译器的选择&#xff08;三&#xff09;Python学习中的两大法宝函数 二、如何加载数据&#xff08;一&#xff09;Dataset与Dataloade…