C++(不含类部分和STL部分)
文章平均质量分 92
本专栏是专门介绍C++基础语法的,这个专栏没有关于C++的面向对象部分以及标准库STL的知识,这两块的知识点我另外开了两个专栏专门讲解
掘根
须知少时凌云志,曾许人间第一流
展开
-
整数在内存中的存储形式,大小端
对于⼤端模式,就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在⾼地址中,即 0x0011 中。这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为8 bit 位,但是在C语⾔中除了8 bit 的 char 之外,还有16 bit 的 short 型,32 bit 的 long 型(要看 具体的编译器)三种表⽰⽅法均有符号位和数值位两部分,符号位都是⽤0表⽰“正”,⽤1表⽰“负”,⽽数值位最 ⾼位的⼀位是被当做符号位,剩余的都是数值位。原创 2024-05-07 22:43:09 · 1057 阅读 · 31 评论 -
C++tuple类型
当我们定义一个tuple时,需要指出每个成员的类型;int main()//三个成员都设置为0当我们创建一个tuple对象时,可以使用 tuple的默认构造函数,它会对每个成员进行提供一个初始值。也可以像本例中初始化nomeval一样,为每个成员提供一个初始值// 错误// 正确类似 make_pair,make_tuple 函数使用初始值的类型来推断 tuple的类型。在本例中,item是一个tuple,类型为 tuple。原创 2024-04-02 18:00:39 · 1000 阅读 · 0 评论 -
C++bitset类型
bitset类是一个类模板,它类似array类,具有固定的大小。// 32位;低位为 1,其他位为 0大小必须是一个常量表达式。这条语句定义bitvec为一个包含32位的bitset。就像 vector 包含未命名的元素一样,bitset中的二进制位也是未命名的,我们通过位置来访问它们。二进制位的位置是从0开始编号的。因此,bitvec包含编号从0到31的32个二进制位。编号从0开始的二进制位被称为低位,编号到31结束的二进制位被称为高位。初始化bitset的方法bitsetb;b有n位;原创 2024-04-02 20:26:07 · 1125 阅读 · 1 评论 -
C++IO类,输入输出缓冲区,流状态
例如,头文件fstream定义了ifstream和wifstream类型。原创 2024-04-06 01:06:25 · 976 阅读 · 2 评论 -
C++智能指针2——unique_ptr和weak_ptr
一个unique_ptr“拥有”它所指向的对象。swap(p,q)p.swap(q)reset成员接受一个可选的指针参数,令unique_ptr重新指向给定的指针。如果unique_ptr不为空,它原来指向的对象被释放。因此,对 p2 调用 reset 释放了用"Stegosaurus”初始化的string所使用的内存,将p3对指针的所有权转移给p2,并将p3置为空。在本例中,管理内存的责任简单地从一个智能指针转移给另一个。原创 2024-04-05 20:42:24 · 819 阅读 · 1 评论 -
C++智能指针1——shared_ptr类
在C++中,动态内存的管理是通过一对运算符来完成的:动态内存的使用很容易出问题,因为确保在正确的时间释放内存是极其困难的。有时我们会忘记释放内存,在这种情况下就会产生内存泄漏;有时在尚有指针引用内存的情况下我们就释放了它,在这种情况下就会产生引用非法内存的指针。为了更容易(同时也更安全)地使用动态内存,新的标准库提供了两种智能指针类型来管理动态对象。智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象。新标准库提供的这两种智能指针的区别在于管理底层指针的方式这三种类型都定义在memory头文件原创 2024-04-05 18:03:34 · 813 阅读 · 3 评论 -
C++allocator类
new有一些灵活性上的局限,其中一方面表现在它将内存分配和对象构造组合在了一起。因为在这种情况下,我们几乎肯定知道对象应有什么值。更重要的是,那些没有默认构造函数的类就不能动态分配数组了。原创 2024-04-05 14:54:07 · 1000 阅读 · 0 评论 -
C++动态内存分配(new和delete)
相对于智能指针,使用这两个运算符管理内存非常容易出错,随着我们逐步详细介绍这两个运算符,这一点会更为清楚。原创 2024-04-05 14:12:57 · 823 阅读 · 0 评论 -
C++模板基础3——模板参数,成员模板,控制实例化
在类内部直接定义成员函数模板是非常方便和直观的。这种方式通常用于较短的函数实现,以便将函数的声明和实现紧密地结合在一起。public:// 成员函数模板的类内定义在类内定义时,模板参数和函数体都直接写在类定义中。这种方式适用于函数体较短、逻辑简单的情况。如果成员函数模板的实现比较复杂,或者为了保持类定义的简洁性,你可能希望在类外部定义成员函数模板。在类外定义时,你需要使用作用域解析运算符(::)来指明这个函数属于哪个类。public:// 成员函数模板的声明// 成员函数模板的类外定义。原创 2024-04-05 12:08:51 · 936 阅读 · 0 评论 -
C++模板基础2——定义类模板
/ 类成员和函数声明与定义其中,表示该类是一个模板类,T是一个占位符类型,可以在类内部使用。ClassName是模板类的名称。我们举个例子// 类模板定义public:private:T value_;// 使用int类型的类模板实例化对象// 输出: Value: 42// 修改整数值并打印// 输出: Value: 100// 使用std::string类型的类模板实例化对象");// 输出: Value: Hello, Templates!原创 2024-04-04 22:07:10 · 686 阅读 · 0 评论 -
C++模板基础1——定义函数模板
非类型模板参数的模板实参必须是常量表达式。原创 2024-04-04 19:20:04 · 676 阅读 · 0 评论 -
c++函数模板,显式具体化,隐式实例化,显式实例化,关键字decltype
读书的时候我们肯定背过很多作文模板吧,英语也好,语文也罢,背模板都是为了下次能直接套用,节约思考时间。函数模板就和这个作文模板类似,先把模板记录下来,后面在应对不同类型的变量时能做类似的处理函数模板是通用的函数描述,也就是说它们使用泛型来定义函数,其中的泛型可以用具体的类型来替换。通过将类型作为参数传递给模板,可使编译器生成该类型的函数。为了声明函数模板,我们引入了template,typename这些关键字,不过typename可以替换为class(这两个关键字是等价的)写法有两种先看一个例子原创 2024-02-06 14:05:16 · 1052 阅读 · 1 评论 -
C++理解std::move和转发(std::forward)
/在返回类型和类型转换中也要用到typename这段代码很短,但其中有些微妙之处。首先,move的函数参数T&&是一个指向模板类型参数的右值引用。通过引用折叠,此参数可以与任何类型的实参匹配。特别是,我们既可以传递给move一个左值,也可以传递给它一个右值,"),s2;"));// 正确:从一个右值移动数据// 正确:但在赋值之后,s1的值是不确定的//没有打印任何东西为了通过翻转函数传递一个引用,我们需要重写函数,使其参数能保持给定实参的“左造性”。原创 2024-04-04 14:39:32 · 1188 阅读 · 0 评论 -
C++模板实参推断
作为一个例子,考虑对函数fobj和fref的调用。原创 2024-04-04 13:35:56 · 1286 阅读 · 0 评论 -
C++函数匹配机制
实参类型与形参类型越接近,它们匹配得越好。在我们的例子中,调用只提供了一个(显式的)实参,它的类型是double。如果调用f(int),实参将不得不从double转换成int。另一个可行函数f(double,double)则与实参精确匹配。原创 2024-04-03 22:06:55 · 1037 阅读 · 1 评论 -
C++重载和模板
函数模板可以被另一个模板或一个普通非模板函数重载。与往常一样,名字相同的函数必须具有不同数量或类型的参数。如果涉及函数模板,则函数匹配规则会在以下几方面受到影响: ——如果同样好的函数中只有一个是非模板函数,则选择此函数, ——如果同样好的函数中没有非模板函数,而有多个函数模板,且其中一个模板比其他 模板更特例化,则选择此模板。 ——否则,此调用有歧义。作为一个例子,我们将构造原创 2024-04-03 21:11:20 · 1300 阅读 · 5 评论 -
C++可变参数模板
作为一个例子,我们将定义一个函数,它名为error_msg 函数,函数实参的类型是可变的。我们首先定义一个名为print的函数,它在一个给定流上打印给定实参列表的内容。可变参数函数通常是递归的。第一步调用处理包中的第一个实参,然后用剩余实参调用自身。我们的print函数也是这样的模式, 每次递归调用将第二个实参打印到第一个实参表示的流中。原创 2024-04-02 16:20:14 · 1208 阅读 · 0 评论 -
C++未格式化的输入/输出操作,流随机访问
一般情况下,在读取下一个值之前,标准库保证我们可以退回最多一个值。原创 2024-03-31 18:19:53 · 719 阅读 · 0 评论 -
C++格式化输入和输出
除了条件状态外,每个iostream对象还维护一个格式状态来控制IO如何格式化的细节。格式状态控制格式化的某些方面,如整型值是几进制、浮点值的精度、一个输出元素的宽度等。标准库定义了一组操纵符来修改流的格式状态。一个操纵符是一个函数或是一个对象,会影响流的状态,并能用作输入或输出运算符的运算对象。类似输入和输出运算符,操纵符也返回它所处理的流对象,因此我们可以在一条语句中组合操纵符和数据。我们已经在程序中使用过一个操纵符——endl,我们将它“写”到输出流,就像它是一个值一样。但endl不是一个普通值,而是原创 2024-03-31 14:03:56 · 1267 阅读 · 1 评论 -
C++RTTI(运行时类型识别)
然而,并非任何时候都能定义一个虚函数。假设我们无法使用虚函数,则可以使用一个RTTI运算符。另一方面。原创 2024-03-29 16:37:15 · 1005 阅读 · 0 评论 -
C++随机数
程序通常需要一个随机数源。在新标准出现之前,C和C++都依赖于一个简单的C库函数rand来生成随机数。此函数生成均匀分布的伪随机整数,每个随机数的范围在0和一个系统相关的最大值(至少为32767)之间。rand 函数有一些问题:即使不是大多数,也有很多程序需要不同范围的随机数。一些应用需要随机浮点数。一些程序需要非均匀分布的数。而程序员为了解决这些问题而试图转换rand生成的随机数的范围、类型或分布时,常常会引入非随机性。定义在头文件random中的随机数库通过一组协作的类来解决这些问题:随机数引擎类和随机原创 2024-03-28 13:31:08 · 926 阅读 · 0 评论 -
C++命名空间详解
一个命名空间的定义包含两部分;首先是关键字 namespace,随后是命名空间的名字。在命名空间名字后面是一系列由花括号括起来的声明和定义。注意末尾不需要分号namespace 命名空间名//声明,定义}//命名空间结束没有分号,这和块类似只要能出现在全局作用域中的声明就能置于命名空间内,主要包括:类、变量(及其初始化操作)、函数(及其定义)、模板和其他命名空间:和其他名字一样,命名空间的名字也必须在定义它的作用域内保持唯一。int a;int a;//错误,重复定义。原创 2024-03-26 18:08:04 · 1487 阅读 · 1 评论 -
C++noexcept 异常说明
对于用户及编译器来说,预先知道某个函数不会抛出异常是大有好处的。在C++11新标准中,我们可以通过提供noexcept说明指定某个函数不会抛出异常。其形式是关键字 noexcept 紧跟在函数的参数列表后面,用以标识该函数不会抛出异常:这两条声明语句指出 recoup 将不会抛出任何异常,而alloc可能抛出异常。我们说recoup做了不抛出说明(nonthrowingspecification)。对于一个函数来说,noexcept说明要么出现在该函数的所有声明语句和定义语句中,要么一次也不出现。原创 2024-03-25 21:54:31 · 753 阅读 · 0 评论 -
C++函数重载
函数重载的主要目的是提供一种方便的方式来定义和调用。原创 2024-03-24 22:22:46 · 875 阅读 · 0 评论 -
C++运算符优先级表
:::::全局作用域类作用域命名空间作用域::name->[]()()成员选择成员选择下标函数调用类型构造a.ba->ba[b]函数名(参数)类型(参数)++--typeidtypeidexplicit cast后置递增后置递减类型ID运行时类型ID类型转换a++a--++--!()sizeofsizeofSizeof...newnew[]deletedelete[]noexcept前置递增前置递减位求反逻辑非。原创 2024-03-23 14:40:09 · 353 阅读 · 0 评论 -
掘根宝典之C++变量初始化的几种方法
如果我们想定义一个名为a的int的变量,并把它初始化为6,则以下四条语句都是可以的。原创 2024-03-14 20:35:38 · 158 阅读 · 0 评论 -
掘根宝典之C++基于范围的for循环
C++的基于范围的for循环(Range-based for loop)是C++11引入的一种方便的循环语法,用于遍历容器中的元素或者其他可迭代的对象。基本语法为:其中,是容器中的元素,是一个容器或者其他可迭代的对象。范围for循环会自动遍历中的每个元素,并将每个元素赋值给,然后执行循环体内的操作。最初编译器会自动从容器中拷贝第一个元素到变量中。在循环执行期间,container的下一个元素会被自动拷贝到element中,直到拷贝完container的最后一个元素。需要注意的是,不使用引用的范围for原创 2024-03-12 12:49:28 · 668 阅读 · 0 评论 -
C++异常详解
在C++中,abort()函数用于终止程序的执行。abort()调用abort()函数会导致程序立即终止,并生成一个异常终止信号并将其发送到标准错误流。程序的终止是非正常的,它不会执行任何的析构函数、清理操作等。通常情况下,abort()函数被用于处理严重错误或异常情况,强制终止程序以避免进一步的损害。示例使用abort()int a = 0;abort();// 如果 a 等于 0,强制终止程序return 0;在上面的示例中,如果a的值等于0,则调用abort()函数终止程序的执行。原创 2024-03-08 21:01:52 · 888 阅读 · 0 评论 -
掘根宝典之C++智能指针模板类(auto_ptr,unique_ptr,shared_ptr,weak_ptr)
说白了,智能指针就是类似于指针的类对象,但是功能比指针多。智能指针是一种在程序中管理动态分配的内存的工具。智能指针提供了一种机制来自动分配和释放内存,从而减少内存泄漏和悬挂指针的风险。智能指针通过将内存的所有权转移到指针对象本身,可以在对象不再需要时自动释放内存。智能指针通常会在构造函数中分配内存,并在析构函数中释放内存。此外,智能指针还提供了一些额外的功能,如拷贝构造函数和移动构造函数,以便能够正确地管理指针的所有权。原创 2024-02-18 10:51:22 · 1249 阅读 · 0 评论 -
C++类型转换运算符(dynamic_cast,const_cast,static_cast,reinterpret_cast)
RTTI是运行阶段类型识别的简称。原创 2024-02-17 16:54:25 · 773 阅读 · 0 评论 -
掘根宝典之C++存储持续性,作用域和链接性(自动存储连续性,静态持续变量,关键字static,const的链接性,函数链接性,动态分配链接性)
代码块:由花括号括起的一系列语句如果在代码块里定义了变量,则该变量的存在时间和作用域将被限制在该代码块。话不多说,上例子int main()int a = 9;//结果是9//代码块int b = 8;//结果是8//结果是9//这不可以从上面这个例子得出,b的作用域被限制在它所在的代码块里,同时我们也发现在代码块外定义的变量a在内部代码块和外部代码块都是可见的那如果将内部的变量命名为a,使得代码块内部和外部有两个同名的变量,这时情况会如何呢?话不多说,上例子。原创 2024-02-08 17:34:14 · 1388 阅读 · 1 评论 -
掘根宝典之c++单独编译,头文件,#include
如果将类的声明、函数的声明等放在多个源文件中,容易出现重复定义的问题。而将这些声明放在头文件中,其他源文件可以通过包含头文件来避免重复定义。5.原创 2024-02-07 21:44:53 · 771 阅读 · 1 评论 -
掘根大全之C++默认参数
1.如果函数的声明和定义是分开的话,那么只能在函数声明处设置默认参数,不能在函数定义处设置默认参数上例子//函数声明int main()int A(int a, int b)//函数定义,b不用再设置默认值下面这种情况是不被允许的int main()默认参数只能被设置一次,不能重复设置 ,就算是两处设置的值一样也不行//函数声明int main()int A(int a, int b=9)//函数定义2.如果函数的声明和定义在一起的话,那么直接设置就好了。原创 2024-02-06 21:06:19 · 208 阅读 · 0 评论 -
掘根宝典之c++内联函数(看这篇就够了)
我们引入inline这个关键字以 inline 修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。下面举个例子inline void A(int a)//前面加了个inlineint main()int w=99;A(w);//A(w)直接展开为{a=99;函数A()就是一个内联函数。原创 2024-02-04 16:28:16 · 598 阅读 · 1 评论 -
掘根宝典之c++引用变量详解-------看这一篇就够了
引用实际上是已定义变量的别名,使一个变量拥有多个名字c++给符号赋予了另一个意义,将其用来声明引用int a=9;int&b=a;此时b成为a的一个别名,a就是b,b就是a.它们均指向同一片内存int a=99;int&b=a;//b成为a的别名//a,b的地址相同//a,b的值相同a,b的各种属性相同,说明了a,b是同一个变量,该变量有a,b两个名字再如a++和b++操作均将一个有两个名字的变量的值+1。原创 2024-02-05 10:59:26 · 785 阅读 · 2 评论 -
掘根宝典之C语言和C++中的const
如果const位于星号*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号*的右侧,const就是修饰指针本身,即指针本身是常量。原创 2024-03-06 17:26:39 · 968 阅读 · 0 评论 -
C++类型别名,关键字typedef,auto,decltype
我们看个例子。原创 2024-03-11 18:18:29 · 722 阅读 · 0 评论 -
C++之constexpr和常量表达式
常量表达式(const expression)是指值不会改变并且在编译过程就能得到计算结果的表达式。显然,字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。后面将会提到,C++语言中有几种情况下是要用到常量表达式的。一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同决定,例如:尽管staff_size的初始值是个字面值常量,但由于它的数据类型只是一个普通int而非const int,所以它不属于常量表达式。另一方面,尽管sz本身是一个常量,但它的具体值直到运行时才能原创 2024-03-22 17:45:48 · 903 阅读 · 0 评论 -
掘根宝典之c++标识符,命名
在探讨命名方案之前,我们来了解一下C++中的标识符啊什么是标识符呢?在C++中,标识符是用于命名变量、函数、类、对象等实体的名称。标识符的命名必须遵循C++标识符的规则:也就是说标识符第一个字符不能是数字。也就是说下面这些都不是标识符标识符不能包含空格和特殊字符(如@、#、$等)。标识符是大小写敏感的。例如,"myVariable"和"MyVariable"是两个不同的标识符。这一点和c语言是有不同之处的。c语言里的标识符只保证前63个字符有意义。也就是说,假如你用了两个有64原创 2024-03-19 17:05:52 · 263 阅读 · 0 评论 -
C++枚举类型
只要enum有名字,我们就能定义并初始化该类型的成员。要想初始化enum对象或者为enum对象赋值,必须使用该类型的一个枚举成员或者该类型的另一个对象,//正确一个不限定作用城的枚举类型的对象或枚举成员自动地转换成整型,限定作用域的枚举类型不会进行隐式转换int a1 = a;//可以//不可以,限定作用域的枚举类型不会进行隐式转换。原创 2024-03-27 23:27:26 · 1638 阅读 · 1 评论