C++这个C语言运行错误是怎么回事什么意思?

本文是C++主要内容的知识图谱,主要记载了学习过程中容易忽略或者混淆的基础知识适合新手或者长时间不用C++而重新使用的各位查漏补缺,不适合各位大神翻阅!由于涉及内容较多,后续会持续更新内容,如有错误,请批评指针。

内容主要来源以下链接,具体细节可以去翻阅参考书籍:

c++是面向对象的编程,特点可以概括为4个字:封装、抽象、继承、多态,把对象的属性和方法集合成一个独立的系统单位,尽可能隐藏对象的内部细节,对具体的问题进行概括的过程,子类对象拥有与基类相同的全部属性和方法,子类继承基类的属性和行为后,可以具有不同的数据类型和表现行为等。C++ 在以下应用中有多种用途:

  • 操作系统和系统编程。例如基于 Linux 的操作系统(Ubuntu 等)

  • 通过初始化元素声明数组
  • 通过指定大小和初始化元素来声明数组

  • 按值传参:函数接收到了传递过来的参数后,将其拷贝一份,其函数内部执行的代码操作的都是传递参数的拷贝。也就是说,按值传参最大的特点就是不会影响到传递过来的参数的值,但因为拷贝了一份副本,会更浪费资源一些。
  • 按(左值)引用传参:按值传参不会影响到原来的参数的值,那么问题来了,如果我们就是想要对参数进行一些修改,怎么办呢?这时候按(左值)引用传参就应运而生了。注意区分穿数组引用以及其他引用的区别。
  • 按常量引用传参:那么我们不想要对传入参数进行修改,是不是就只能使用按值传参了呢?我们能不能既拥有引用的节省拷贝开支的优点,又拥有按值传参的不影响原值的优点呢?于是乎,按常量引用传参也就应运而生了。如果我们只是想要看一看参数的值,而并不需要去修改它,我们就可以使用按常量引用传值,从而减少拷贝方面的开销。
  • 右值引用传参:对于右值来说,其存储的是临时的将要被摧毁的资源,移动一个对象的状态总会比赋值这个对象的状态要来的简单(开销小)。

  • const T:定义一个常量,声明的同时必须进行初始化,一旦声明,这个值将不能被改变。
  • const T*:指向常量的指针,不能用指针改变指向的对象的值,但指针本身的值(指向)可以改变。
  • T *const:常量指针,指针本身的值(指向)不可以改变,指向的对象的值可以改变
  • const T&:对常量(const)的引用,又称为常量引用,常量引用不能修改其邦定的对象。引用并非对象;引用必须初始;引用只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起;类型要严格匹配
  • const T*&:指向常量对象的指针的引用,这可以分两步来理解:1.const T*是指向常量的指针;2.const T*&指向常量的指针的引用。

希望传入一个对象,又不想让函数体修改这个对象方法:

  • void func(const T& data):这种方式还有一个好处是只有在调用函数的时候会邦定对象,传递的是对象的引用,而不是对象,减少函数调用时对象赋值的花销。

在类中的使用,返回一个类的成员,但不希望调用方修改这个成员方法:

typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。

下面重点说明一下tyedef与结构体混合的使用

C++中的return语句是函数中一个重要的语句,return语句用于结束当前正在执行的函数,并将控制权返回给调用此函数的函数。

return语句有两种形式:

不带返回值的return语句只能用于返回类型为void的函数,return语句是为了引起函数的强制结束,这种用法类似于循环结构中的break语句的作用。

任何返回类型不是void的函数都必须返回一个值,而且这个返回值的类型必须和函数的返回类型相同,或者能隐式转化为函数的返回类型。

输入/输出操作的头文件有:

  • iomanip:iomanip 代表输入输出操纵器。这些文件中声明的方法用于操作流。该文件包含 setw、setprecision 等的定义
  • fstream:这个头文件主要描述文件流。此头文件用于处理从文件中读取的数据作为输入或写入文件作为输出的数据。

注意区分以下四个输入输出函数:

  • 标准输出流(cout):通常标准输出设备是显示屏。C++cout语句是 ostream 类的实例。它用于在标准输出设备(通常是显示屏)上产生输出。需要在屏幕上显示的数据使用插入运算符 (<<) 插入到标准输出流 (cout) 中。
  • 标准输入流(cin):通常计算机中的输入设备是键盘。C++ cin 语句是istream类的实例,用于从标准输入设备(通常是键盘)读取输入。 提取运算符 ( >> ) 与对象cin一起用于读取输入。提取运算符从使用键盘输入的对象cin中提取数据。
  • 无缓冲标准错误流 (cerr):C++ cerr 是用于输出错误的标准错误流。这也是 iostream 类的一个实例。由于 C++ 中的 cerr 是无缓冲的,因此当需要立即显示错误消息时使用它。它没有任何缓冲区来存储错误消息并稍后显示。cerr 和 cout 之间的主要区别在于,当您想使用“cout”重定向输出时,如果使用“cerr”,则该错误不会存储在文件中。(这就是无缓冲的意思..它无法存储消息)
  • 缓冲标准错误流 (clog):这也是 ostream 类的一个实例,用于显示错误,但与 cerr 不同的是,错误首先插入缓冲区并存储在缓冲区中,直到它没有被完全填满。或者缓冲区没有显式刷新(使用flush())。错误信息也会显示在屏幕上。

变量声明是指变量在首次使用之前首先声明或引入的部分。变量定义是为变量分配内存位置和值的部分。大多数时候,变量声明和定义是一起完成的。

局部变量:在块或方法或构造函数中定义的变量称为局部变量。

  • 这些变量在进入块或函数被调用时创建,并在退出块或调用从函数返回时销毁。
  • 这些变量的作用域只存在于声明变量的块中。即我们只能在该块内访问这些变量。
  • 局部变量的初始化是强制性的。

实例变量:实例变量是非静态变量,在任何方法、构造函数或块之外的类中声明。

  • 由于实例变量是在类中声明的,因此这些变量在创建类的对象时创建,并在对象被销毁时销毁。
  • 与局部变量不同,我们可以对实例变量使用访问说明符。如果我们不指定任何访问说明符,则将使用默认访问说明符。
  • 实例变量的初始化不是强制性的。
  • 实例变量只能通过创建对象来访问。

静态变量:静态变量也称为类变量。

  • 这些变量的声明方式与实例变量类似,不同之处在于静态变量是在任何方法构造函数或块之外的类中使用
  • 与实例变量不同,无论我们创建了多少对象,每个类只能拥有一个静态变量的副本。
  • 静态变量在程序执行开始时创建,并在执行结束时自动销毁。
  • 静态变量的初始化不是强制性的。它的默认值为 0
  • 如果我们访问像实例变量这样的静态变量(通过对象),编译器将显示警告消息并且它不会停止程序。编译器会自动将对象名替换为类名。
  • 如果我们在没有类名的情况下访问静态变量,编译器会自动附加类名。

C++为什么不使用默认值初始化变量?

“让 C++ 可行的一件事是零开销规则:你不使用什么,你就不用付费。”-斯特劳斯特鲁普。 初始化堆栈变量的开销很大,因为它阻碍了执行速度,因此这些变量可以包含不确定的值或垃圾值,因为在我们定义数据类型时提供了内存空间。在代码中使用原始数据类型变量之前,它被认为是一种最佳实

  • 通常,当定义了两个具有相同名称的变量时,编译器会产生编译时错误。但是如果变量是在不同的范围内定义的,那么编译器就会允许它。
  • 只要定义了与全局变量同名的局部变量,编译器就会优先考虑局部变量

当有同名的局部变量时如何访问全局变量?

如果我们想做与上述任务相反的事情怎么办。如果存在同名的局部变量时要访问全局变量怎么办? 为了解决这个问题,我们需要使用::

在 C/C++ 程序中,我们可以通过两种方式定义常量,如下所示:

  • 使用#define预处理器指令

在 C/C++ 编程中,未定义的行为意味着当程序编译失败或执行不正确、崩溃或生成不正确的结果时,或者它可能偶然地完全按照程序员的意图执行。每当执行程序的结果不可预测时,就说它具有未定义的行为。

  • auto:auto 关键字提供类型推断能力,使用它可以自动推断编程语言中表达式的数据类型。这样可以减少编写编译器已经知道的东西的时间。
  • register:该存储类声明了与 auto 变量具有相同功能的寄存器变量。唯一的区别是,如果有可用的空闲寄存器,编译器会尝试将这些变量存储在微处理器的寄存器中。这使得寄存器变量的使用比程序运行时存储在内存中的变量快得多。如果没有可用的寄存器,则这些寄存器只存储在内存中。通常,一些在程序中被频繁访问的变量用 register 关键字声明,这样可以提高程序的运行时间。这里要注意的一个重要且有趣的点是,我们无法使用指针获取寄存器变量的地址。
  • extern:外部存储类只是告诉我们该变量是在别处定义的,而不是在使用它的同一块内。基本上,该值在不同的块中分配给它,并且也可以在不同的块中覆盖/更改。因此,外部变量只不过是一个用合法值初始化的全局变量,在该变量中声明它以便在其他地方使用。它可以在任何功能/块中访问。此外,通过在任何函数/块中的声明/定义之前放置“extern”关键字,也可以使普通全局变量成为外部变量。这基本上意味着我们没有初始化一个新变量,而是我们只使用/访问全局变量。使用外部变量的主要目的是可以在作为大型程序一部分的两个不同文件之间访问它们。
  • 语言中编写程序时常用的静态变量。静态变量具有保留其值的属性,即使它们超出了它们的范围!因此,静态变量在其作用域内保留了它们最后一次使用的值。所以我们可以说它们只被初始化一次并且一直存在到程序终止。因此,没有新的内存被分配,因为它们没有被重新声明。它们的作用域是定义它们的函数的本地范围。全局静态变量可以在程序的任何地方访问。默认情况下,编译器为它们分配值 0。
  • mutable:有时需要通过 const 函数修改类/结构的一个或多个数据成员,即使您不希望该函数更新类/结构的其他成员。使用 mutable 关键字可以轻松执行此任务。关键字 mutable 主要用于允许修改 const 对象的特定数据成员。当我们将函数声明为 const 时,传递给函数的指针变为 const。向变量添加 mutable 允许 const

  • 文本段(即指令):文本段,也称为代码段或简称为文本,是目标文件或内存中的程序段之一,其中包含可执行指令。作为内存区域,可以将文本段放置在堆或堆栈下方,以防止堆和堆栈溢出覆盖它。 通常,文本段是可共享的,因此对于频繁执行的程序(例如文本编辑器、C 编译器、shell 等),只需要在内存中保存一个副本。此外,文本段通常是只读的,以防止程序意外修改其指令。
  • 初始化的数据段 :初始化数据段,通常简称为数据段。数据段是程序虚拟地址空间的一部分,其中包含由程序员初始化的全局变量和静态变量。请注意,数据段不是只读的,因为变量的值可以在运行时更改。该段可以进一步分为初始化只读区和初始化读写区。
  • 未初始化的数据段(bss):未初始化的数据段通常称为“bss”段,以一个古老的汇编运算符命名,代表“由符号开始的块”。该段中的数据在程序开始执行之前由内核初始化为算术 0,未初始化的数据从数据段的末尾开始,包含所有初始化为零或源代码中没有显式初始化的全局变量和静态变量。
  • 堆 :堆是通常发生动态内存分配的段。堆区域从 BSS 段的末尾开始,并从那里增长到更大的地址。Heap area 由 malloc、realloc 和 free 管理,可以使用 brk 和 sbrk 系统调用来调整其大小(注意使用 brk/sbrk 和单个“heap area”不是必须履行的契约malloc/realloc/free;它们也可以使用 mmap 来实现,以将虚拟内存的潜在不连续区域保留到进程的虚拟地址空间中)。堆区域由进程中的所有共享库和动态加载的模块共享。
  • 栈:栈区域传统上与堆区域相邻,并以相反的方向增长;当栈指针遇到堆指针时,可用内存已耗尽。(使用现代大地址空间和虚拟内存技术,它们几乎可以放置在任何地方,但它们通常仍以相反的方向增长。)栈区域包含程序栈,这是一种 LIFO 结构,通常位于内存的较高部分。在标准 PC x86 计算机体系结构上,它向零地址增长;在其他一些架构上,它的增长方向相反。“栈指针”寄存器跟踪栈的顶部;每次将值“推入”栈时都会对其进行调整。为一个函数调用推送的一组值称为“栈帧”;栈帧至少包含一个返回地址。栈,其中存储自动变量,以及每次调用函数时保存的信息。每次调用函数时,返回的地址和调用者环境的某些信息,例如一些机器寄存器,都保存在栈中。然后,新调用的函数在栈上为其自动和临时变量分配空间。这就是 C 中递归函数的工作方式。每次递归函数调用自身时,都会使用一个新的栈帧,因此一组变量不会干扰来自另一个函数实例的变量。

引用和指针都可用于在另一个函数中更改一个函数的局部变量。当作为参数传递给函数或从函数返回时,它们也可用于保存大对象的复制,以提高效率。

尽管有上述相似之处,但引用和指针之间存在以下差异。

  • 指针可以声明为 void,但引用永远不能为 void
  • 指针变量有n 级/多级间接,即单指针、双指针、三指针。然而,参考变量只有一个/单一的间接级别
  • 引用变量是一个内部指针。
  • 引用变量的声明以'&'符号开头(但不要读作“地址”)。
  • 引用一旦创建,以后就不能再引用另一个对象;它无法重置。这通常使用指针来完成。
  • 引用不能为 NULL。指针通常设为 NULL 以表明它们没有指向任何有效的东西。
  • 引用必须在声明时进行初始化。指针没有这样的限制。

由于上述限制,C++中的引用不能用于实现链表、树等数据结构。在Java中,引用没有上述限制,可以用于实现所有数据结构。Java 中更强大的引用是 Java 不需要指针的主要原因。

引用更安全,更易于使用:

  • 更安全由于必须初始化引用,因此不太可能存在像仍然可能有不引用有效位置的引用。
  • 更易于使用:引用不需要取消引用运算符来访问值。它们可以像普通变量一样使用。'&' 运算符仅在声明时才需要。此外,可以使用点运算符 ('.') 访问对象引用的成员,这与需要箭头运算符 (->) 来访问成员的指针不同。

加上上面的原因,像拷贝构造函数参数这样的地方很少有不能使用指针的。必须使用引用在复制构造函数中传递参数。同样,引用必须用于重载一些运算符,如 ++。

理解类的函数和数据成员非常重要,每个对象都有自己的数据成员副本,并且所有对象共享成员函数的单个副本。那么现在的问题是,如果每个成员函数只存在一个副本并被多个对象使用,那么如何访问和更新正确的数据成员?

答案:编译器提供一个隐式指针以及函数名称作为“this”。“this”指针作为隐藏参数传递给所有非静态成员函数调用,并可作为所有非静态函数体内的局部变量使用。'this' 指针在静态成员函数中不可用,因为可以在没有任何对象(带有类名)的情况下调用静态成员函数。对于 X 类,此指针的类型是“X*”。此外,如果 X 的成员函数声明为 const,则此指针的类型为 'const X *'

以下是使用“this”指针的情况:

  • 当局部变量名与成员名相同时
  • 返回对调用对象的引用:当返回对本地对象的引用时,返回的引用可用于链接单个对象的函数调用。

C++ 中的智能指针以及如何使用它们?

指针用于访问程序外部的资源——比如堆内存。因此,为了访问堆内存(如果在堆内存中创建了任何东西),需要使用指针。当访问任何外部资源时,我们只使用资源的副本。如果我们对其进行任何更改,我们只需在复制的版本中进行更改。但是,如果我们使用指向资源的指针,我们将能够更改原始资源。

当函数fun结束时, p 将被销毁,因为它是一个局部变量。但是,它消耗的内存不会被释放,因为我们忘记使用delete p;在函数的最后。这意味着内存不会被其他资源免费使用。但是,我们不再需要变量,但我们需要内存。C++11 提出了解决这个问题的方法,Smart Pointer。

无意识地不释放指针会导致内存泄漏,从而可能导致程序崩溃。语言 Java、C# 具有垃圾收集机制,可以巧妙地释放未使用的内存以再次使用。程序员不必担心任何内存泄漏。C++11 提出了自己的机制,即Smart Pointer。当对象被销毁时,它也会释放内存。所以,我们不需要删除它,因为 Smart Pointer 会处理它。

智能指针是指针上的包装类,其中重载了 * 和 -> 等运算符。智能指针类的对象看起来像普通指针。但是,与普通指针不同,它可以解除分配和释放被破坏的对象内存。

这个想法是采用一个带有指针、和(如 * 和 ->)的类。由于当对象超出范围时会自动调用析构函数,因此动态分配的内存将被自动删除(或者引用计数可以减少)。

  • unique_ptr:unique_ptr只存储一个指针。我们可以通过从指针中删除当前对象来分配不同的对象。注意下面的代码。首先,unique_pointer指向P1。但是,然后我们删除P1并分配P2,因此指针现在指向P2
  • shared_ptr:通过使用shared_ptr多个指针一次可以指向这个对象,并且它将使用use_count()方法维护一个引用计数器。
  • weak_ptr:它与 shared_ptr 更相似,只是它不会维护Reference Counter。在这种情况下,指针在对象上不会有据点。原因是如果假设指针持有对象并请求其他对象,那么它们可能会形成死锁。

string与字符数组两者区别:

  • 字符数组只是一个可以由空字符终止的字符数组。字符串是定义表示为字符流的对象的类。
  • 字符数组的大小必须静态分配,如果需要,不能在运行时分配更多内存。在字符数组的情况下,未使用的分配内存被浪费了。在字符串的情况下,内存是动态分配的。可以在运行时按需分配更多内存。由于没有预先分配内存,因此不会浪费任何内存
  • 在字符数组的情况下存在的威胁。由于字符串表示为对象,因此不会发生数组衰减
  • 字符数组的实现比std::string 快。与实现相比,字符串比字符数组慢。
  • 字符数组不提供许多操作字符串的内置函数。String 类定义了许多允许对字符串进行多种操作的功能。
  • getline():此函数用于将用户输入的字符流存储在对象内存中。
  • push_back():该函数用于在字符串的末尾输入一个字符。
  • pop_back():从 C++11 引入(用于字符串),该函数用于从字符串中删除最后一个字符。
  • capacity():该函数返回分配给字符串的容量,可以等于或大于字符串的大小。分配了额外的空间,以便在将新字符添加到字符串时,可以有效地完成操作。
  • resize():这个函数改变字符串的大小,大小可以增加或减少。
  • length():此函数查找字符串的长度。
  • shrink_to_fit():此函数减小字符串的容量,使其等于字符串的最小容量。如果我们确定不需要进一步添加字符,此操作对于节省额外内存很有用。
  • begin():此函数将迭代器返回到字符串的开头。
  • end():此函数将迭代器返回到字符串的末尾。
  • rbegin():此函数返回一个指向字符串末尾的反向迭代器。
  • rend():此函数返回一个指向字符串开头的反向迭代器。
  • copy:此函数复制其参数中提到的目标字符数组中的子字符串。它需要 3 个参数,目标 char 数组,要复制的长度以及开始复制的字符串中的起始位置。
  • swap:此函数将一个字符串与另一个字符串交换。

原始字符串文字是其中 不处理 C++ 的\n\t\"等转义字符的字符串。因此,这是在 C++11 中引入的,这是一个以R“( 并以 )” 结尾的原始字符串文字。

C++ 中的字符串数组(5 种不同的创建方式)

C++分隔符拆分字符串方法

面向对象编程——顾名思义,在编程中使用。面向对象编程旨在在编程中实现继承、隐藏、多态等现实世界的实体。OOP 的主要目的是将数据和对它们进行操作的函数绑定在一起,这样代码的其他部分就不能访问该数据,除了该函数。

C++ 中的类是导致面向对象编程的基石。它是一种用户定义的数据类型,它拥有自己的数据成员和成员函数,可以通过创建该类的实例来访问和使用。C++ 类就像一个对象的蓝图。对象是类的实例。当一个类被定义时,没有分配内存,但是当它被实例化(即创建一个对象)时,内存被分配。

构造函数是特殊的类成员,每次实例化该类的对象时编译器都会调用它们。构造函数与类同名,可以在类定义内部或外部定义。

  • 然而,默认构造函数没有输入参数,复制和参数化构造函数有输入参数
  • 创建对象时会自动调用构造函数。
  • 它必须放在课堂的公共部分。
  • 如果我们不指定构造函数,C++ 编译器会为对象生成一个默认构造函数(不期望参数并且有一个空的主体)。

构造函数有 3 种类型:

  • 默认构造函数:默认构造函数是不带任何参数的构造函数。即使我们没有显式定义任何构造函数,编译器也会自动隐式提供默认构造函数。
  • 参数化构造函数:可以将参数传递给构造函数。通常,这些参数有助于在创建对象时对其进行初始化。要创建参数化构造函数,只需像添加任何其他函数一样向其添加参数。当您定义构造函数的主体时,使用参数来初始化对象。 参数化构造函数的用途:它用于在创建不同对象时用不同的值初始化不同对象的各种数据元素;它用于重载构造函数。
  • 复制构造函数:复制构造函数是一个成员函数,它使用同一类的另一个对象来初始化一个对象

析构函数是编译器在对象作用域结束时调用的另一个特殊成员函数。、

为私有的析构函数称为私有析构函数。每当我们想防止对象被破坏时,我们可以将析构函数设为私有。

一个类从另一个类派生属性和特征的能力称为继承。可以简单地避免数据重复并增加可重用性。派生类不会继承对私有数据成员的访问权限。但是,它确实继承了一个完整的父对象,其中包含该类声明的任何私有成员。基类中的私有成员不能在派生类中直接访问,而受保护的成员可以直接访问。

多态性定义为消息以多种形式显示的能力。C++中的多态主要分为两种:编译时多态和运行时多态。

这种类型的多态性是通过函数重载或运算符重载来实现的。

:当有多个同名但参数不同的函数时,这些函数称为重载。函数可以通过更改参数数量或/和更改参数类型来重载。

:C++ 还提供重载运算符的选项。例如,我们可以使字符串类的运算符 ('+') 连接两个字符串。我们知道这是加法运算符,其任务是将两个操作数相加。因此,单个运算符 '+' 当放置在整数操作数之间时,将它们相加,当放置在字符串操作数之间时,将它们连接起来。

  • 运行时多态(virtual虚函数)

这种类型的多态性是通过函数覆盖实现的。当派生类具有基类的一个成员函数的定义时,就会发生据说该基本功能已被覆盖

当多态性派生类的函数是使用基类指针调用的,出发虚函数的性质。虚函数在运行时被延迟解析。

函数是在类中使用关键字 virtual 声明并由派生类重新定义(覆盖)的成员函数。多态性意味着采取多种形式的能力。如果存在通过继承相互关联的类的层次结构,则会发生这种情况。在 C++ 中,这意味着如果我们调用成员函数,那么它可能会导致执行不同的函数,这取决于调用它的对象类型。

有什么用:虚函数允许我们创建一个基类指针列表并调用任何派生类的方法,甚至无需知道派生类对象的种类。

每个包含了虚函数的类都包含一个虚表。一个类继承了包含虚函数的基类,那么这个类也拥有自己的虚表。虚表是属于类的,而不是属于某个具体的对象,一个类只需要一个虚表即可。同一个类的所有对象都使用同一个虚表。

对象的虚表指针用来指向自己所属类的虚表,虚表中的指针会指向其继承的最近的一个类的虚函数

  • 函数指针表,按类维护。
  • 的指针,为每个对象实例维护

封装被定义为将数据和信息封装在一个单元中。在面向对象编程中,封装被定义为将数据和操作它们的函数绑定在一起。实现封装的过程可以细分为两个步骤:

  • 应使用私有访问说明符将数据成员标记为私有
  • 操作数据成员的成员函数应使用公共访问说明符标记为公共

抽象意味着只显示基本信息并隐藏细节。数据抽象是指只向外界提供数据的基本信息,隐藏背景细节或实现。

  • 使用类进行抽象:我们可以使用类在 C++ 中实现抽象。类帮助我们使用可用的访问说明符对数据成员和成员函数进行分组。一个类可以决定哪些数据成员对外界可见,哪些不可见。
  • 头文件中的抽象:C++ 中的另一种抽象类型可以是头文件。例如,考虑 math.h 头文件中的 pow() 方法。每当我们需要计算一个数字的幂时,我们只需调用 math.h 头文件中的函数 pow() 并将数字作为参数传递,而无需知道该函数实际计算数字幂的底层算法。

函数重载:其中两个或多个函数可以具有相同的名称但不同的参数。

运算符重载:让运算符为用户定义的类工作。这意味着 C++ 能够为运算符提供对数据类型的特殊含义,这种能力称为运算符重载。

运算符函数和普通函数有什么区别?

运算符功能与普通功能相同。唯一的区别是,运算符函数的名称始终是运算符关键字,后跟运算符符号,并且在使用相应运算符时调用运算符函数。

标准模板库 (STL) 是一组 C++ 模板类,用于提供常见的编程数据结构和函数,例如列表、堆栈、数组等。它是容器类、算法和迭代器的库。它是一个通用库,因此它的组件是参数化的。的工作知识是使用 STL 的先决条件。STL 有四个组件:算法,容器、职能、迭代器。

容器是存储其他对象(其元素)的集合的持有者对象。它们被实现为类模板,这使得作为元素支持的类型具有很大的灵活性。 容器管理其元素的存储空间,并提供成员函数来访问它们,直接或通过迭代器(具有与指针类似属性的引用对象)。

实现可以按顺序访问的数据结构。

  • 静态连续数组(类模板)
  • 动态连续数组(类模板)

关联容器实现了可以快速搜索的排序数据结构(O(log n) 复杂度)。

  • 唯一键的集合,按键排序 (类模板)
  • 键值对的集合,按键排序,键是唯一的(类模板)。
  • 键的集合,按键排序(类模板)
  • 键值对的集合,按键排序 (类模板)

无序关联容器实现了可以快速搜索的未排序(散列)数据结构(O(1) 摊销,O(n) 最坏情况复杂度)。

  • 唯一键的集合,由键散列。(类模板)
  • 键值对的集合,由键散列,键是唯一的。(类模板)
  • 键的集合,由键(类模板)散列
  • 键值对的集合,由键散列(类模板)

容器适配器为顺序容器提供了不同的接口。

  • 适配一个容器来提供栈(LIFO数据结构)(类模板)。
  • 适配一个容器来提供队列(FIFO数据结构)(类模板)。
  • 适配一个容器来提供优先队列(类模板)。

在 C++ 中从/向文件读取/写入类对象:

用于创建文件的 C++ 程序

CSV是一种简单的文件格式,用于存储表格数据,例如电子表格或数据库。CSV 代表逗号分隔值。CSV 文件中的数据字段由逗号(', ')分隔/分隔,各个行由换行符('\n')分隔。C++ 中的 CSV 文件管理类似于文本类型的文件管理,只是做了一些修改。

创建操作类似于创建一个文本文件,即从用户输入数据并使用文件指针和不同列之间的适当分隔符(',')和每行结束后的'\n'将其写入csv文件.

  1. 使用 getline()、文件指针和 '\n' 作为分隔符,读取整行并将其存储在字符串变量中。
  2. 现在使用 getline()、字符串流指针和 ', ' 作为分隔符,读取行中的每个单词,将其存储在字符串变量中并将该变量推送到字符串向量。
  3. 通过 row[index] 检索所需的列数据。此处,row[0] 始终存储学生的卷号,因此将 row[0] 与用户输入的卷号进行比较,如果匹配,则显示该学生的详细信息并退出循环。

  1. 从文件中读取数据并将其与用户输入进行比较,如读取操作中所述。
  2. 要求用户为要更新的记录输入新值。
  3. 用新数据更新 row[index]。这里,索引是指需要更新的列字段。
  4. 将更新的记录和所有其他记录写入新文件('reportcardnew.csv')。

  1. 从文件中读取数据并将其与用户输入进行比较,如读取和更新操作中所述。
  2. 将所有更新的记录(要删除的数据除外)写入一个新文件(reportcardnew.csv)。
  3. 删除旧文件,并用旧文件的名称重命名新文件。

  1. 文件大小 – 使用 C/C++ 获取文件大小
  2. 检查存在 - 在 C/C++ 中检查文件是否存在

为什么要处理异常? 以下是异常处理相对于传统错误处理的主要优势。

  • 错误处理代码与普通代码分离:在传统的错误处理代码中,总是有if else条件来处理错误。这些条件和处理错误的代码与正常流程混为一谈。这会降低代码的可读性和可维护性。使用 try catch 块,错误处理代码与正常流程分离。
  • 函数/方法可以处理他们选择的任何异常:一个函数可以抛出许多异常,但可以选择处理其中的一些。其他被抛出但未被捕获的异常可以由调用者处理。如果调用者选择不捕获它们,则异常由调用者的调用者处理。 在 C++ 中,函数可以使用 throw 关键字指定它抛出的异常。此函数的调用者必须以某种方式处理异常(通过再次指定或捕获它)
  • 错误类型的分组:在C++中,基本类型和对象都可以作为异常抛出。我们可以创建异常对象的层次结构,在命名空间或类中对异常进行分组,根据类型对它们进行分类。
  • try 语句允许您定义一个代码块,以便在执行时对其进行错误测试。
  • throw 关键字在检测到问题时抛出异常,这让我们可以创建自定义错误。
  • try 块中发生错误,catch 语句允许您定义要执行的代码块。
  • 当抛出异常时,在封闭的 try 块内创建的所有对象都在控制转移到 catch 块之前被破坏。

异常处理 - 将基类和派生类作为异常捕获:

如果基类和派生类都被作为异常捕获,则派生类的 catch 块必须出现在基类之前。如果我们把基类放在首位,那么派生类的 catch 块将永远无法到达。

}

回复 :哦哦,知道啦,谢谢啊!

编程按指定格式输出N阶数字方阵。

输出包括N行,为对应的数字方阵。每个整数固定占3位,左对齐。

}

以下文字资料是由(历史新知网)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

(函数)参数列表存在语法错误;
可能导致的原因是你函数的参数未匹配,参数类型写错了

movewindow这个函数的参数不正确,可能是你调用该函数时,参数个数和函数声明不一样,或者参数类型没匹配。你检查你这个函数的参数。

分析与处理:函数调用的参数间必须以逗号隔开,并以一个右括号结束。若源文件中含有一个其后不是逗号也不是右括号的参数,则出错。

函数的参数列表写错了,要看具体的代码

也有可能是 关于什么的论点,或 关于什么的意见
根据上下文可以判断其代表的具体内容.

}

我要回帖

更多关于 C语言运行错误是怎么回事 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信