C++基础与深度解析 | C++初探 | Hello World | 系统I/O | 控制流 | 结构体与自定义数据类型

文章目录

    • 一、从Hello World谈起
    • 二、系统I/O
    • 三、控制流
    • 四、结构体与自定义数据类型

一、从Hello World谈起

#include <iostream>

void fun(const char *pInfo)
{
    std::cout << pInfo << std::endl;
}

int main()
{
    fun("Hello World!");
    fun("Hello China!");
    fun("Hello TianJin!");
}

  函数:一段能被反复调用的代码,可以接收输入,进行处理并(或)产生输出。

  • 返回类型:表示了函数返回结果的类型,可以为 void

  • 函数名:用于函数调用

  • 形参列表:表示函数接收的参数类型,可以为空,可以为 void ,可以无形参。多个形参之间用逗号分隔

  • 函数体:具体的执行逻辑

  main 函数:特殊的函数,作为整个程序的入口,系统会调用main函数

  • 返回类型:一定为 int ,表示程序的返回值,通常使用 0 来表示正常返回。0返回给操作系统

    C++标准规定:在main函数中如果没有返回语句,系统会默认返回0。

  • 函数名:C++是大小写敏感的语言,只有main函数才是系统入口函数

  • 形参列表:可以为空,可以为两个参数

    int main()
    {
        //
    }
    
    int main(int argc, char* argv[])
    {
        //
    }
    

Linux系统中获取上一个命令的退出状态,使用的命令行参数为:echo #?

  (内建)类型:为一段存储空间赋予实际的意义。

image-20240502165002825

类型并不是计算机(硬件)引入的概念,而是C++这门语言引入的概念,用于描述参数的信息。

  语句:表明了需要执行的操作。

  • 表达式+分号的语句
  • 语句块
  • if/while等语句

  注释:会被编译器忽略的内容。

  • 用于编写说明或去除不使用的语句

  • 两种注释形式:

    • /**/ :块注释

      块注释还有一个特殊的用处:

      void fun(const char* pInfo, int /*pValue*/)  //方便其他开发人员阅读
      {
          
      }
      
    • //:行注释

二、系统I/O

  系统IO指的是系统提供的输入输出接口,用于与用户进行交互。

#include <iostream>

int main()
{
    int x;
    std::cout << "How old are you: ";
    std::cin >> x;
    std::cout << "You are " << x << std::endl;
}

iostream:标准库所提供的IO接口,用于与用户交互。

  • 输入流:cin;输出流:cout / cerr / clog

  • 几个输出流之间的区别:

    • 输出目标不同

      可以将cout / cerr 这些输出流重定向到不同的文件中

    • 是否立即刷新缓冲区

      及时刷新缓冲区,可以看到一些错误信息。 cerr 会立即刷新缓冲区。 clog不立即刷新缓冲区。std::cout 不会默认立即刷新缓冲区,但你可以手动使用 std::flushstd::endl 来实现这一目的。

  • 缓冲区与缓冲区刷新:std::endlstd::flush

    • std::endl:这个操纵符不仅插入一个换行符,而且还会刷新输出流。因此,当你使用 std::endl 时,输出会立即显示,并且缓冲区会被清空。

      std::cout << "Hello, World!" << std::endl;
      
    • std::flush:这个函数可以用来强制刷新输出流,无论输出的是什么内容。如果你只是想刷新缓冲区而不插入任何额外的字符,可以使用 std::flush

      std::cout << "Hello, World!" << std::flush;
      
#include <iostream>
#include "xx.h"

#include 指令有两种形式,使用尖括号<>和双引号""

  • 使用尖括号 <>

    使用尖括号时,编译器首先会在系统的默认头文件搜索路径中查找头文件。这些默认路径由编译器的实现和操作系统决定。如果找不到,编译器可能会在用户定义的额外路径中查找。使用尖括号通常是为了包含标准库的头文件,因为这些头文件通常安装在系统的标准位置。

  • 使用双引号""

    使用双引号时,编译器首先会在包含当前文件的同一目录中查找头文件。如果当前目录中找不到,编译器会退回到系统默认的头文件搜索路径中继续查找。使用双引号通常是为了包含用户自定义的头文件或第三方库的头文件,这些文件可能位于项目的源代码目录中。

如何决定选择使用哪种形式

  • 标准库:对于标准库的头文件,推荐使用尖括号,因为它们通常不位于源代码目录中,而是安装在系统的标准位置。
  • 用户自定义头文件:对于项目特定的头文件,使用双引号可以确保编译器首先在当前目录中查找,这有助于避免潜在的冲突,并提高可移植性。

  名字空间提供了一种将程序中的实体(如变量、类型、函数等)组织在一起的方法,同时避免了命名冲突。std名字空间是C++标准库所定义的名字空间。名字空间的使用示例如下:

namespace MyNamespace {
    void foo() {
        // 函数定义
    }

    class MyClass {
        // 类定义
    };
}

int main() {
    // 使用 MyNamespace::foo() 或 MyNamespace::MyClass 来访问命名空间中的实体
    MyNamespace::foo();
    MyNamespace::MyClass myObject;
    return 0;
}

访问名字空间中元素的3种方式:

  • 域解析符::

    namespace MyNamespace {
        void foo() {
            // 函数定义
        }
    
        class MyClass {
            // 类定义
        };
    }
    
    int main() {
        // 使用 MyNamespace::foo() 或 MyNamespace::MyClass 来访问命名空间中的实体
        MyNamespace::foo();
        MyNamespace::MyClass myObject;
        return 0;
    }
    
  • using声明语句;

    为了避免在每次使用命名空间中的实体时都写完整的命名空间名称,可以使用 using 声明:

    namespace MyNamespace {
        void foo() {
            // 函数定义
        }
    
        class MyClass {
            // 类定义
        };
    }
    
    int main() {
        using namespace MyNamespace;
        // 现在可以直接使用 foo() 和 MyClass 而不需要 MyNamespace:: 前缀
        foo();
        MyClass myObject;
        return 0;
    }
    

    使用 using 声明的注意事项:

    • 使用 using 声明时要谨慎,因为它可能导致命名冲突,尤其是当多个命名空间中存在同名实体时。
    • 头文件中通常不推荐使用 using namespace,因为这会影响包含该头文件的所有源文件。
  • 名字空间别名

    C++11引入了别名声明,允许为名字空间或类型定义一个别名,使代码更简洁:

    namespace MyNamespace {
        void foo() {
            // 函数定义
        }
    
        class MyClass {
            // 类定义
        };
    }
    
    int main() {
        namespace MyNS = MyNamespace;
        MyNS::foo(); // 使用别名访问函数
        return 0;
    }
    

  名字空间与名称改编(name mangling),这是每一个编译器都会有的行为。

liujie@liujie-vm:~/Documents/demo/HelloWorld/Debug$ nm main.cpp.o
                 U __cxa_atexit
                 U __dso_handle
                 U _GLOBAL_OFFSET_TABLE_
0000000000000062 t _GLOBAL__sub_I__ZN10NameSpace13funEv
000000000000000e T main
0000000000000019 t _Z41__static_initialization_and_destruction_0ii
0000000000000000 B _ZN10NameSpace11xE
0000000000000000 T _ZN10NameSpace13funEv
0000000000000007 T _ZN10NameSpace23funEv
                 U _ZNSt8ios_base4InitC1Ev
                 U _ZNSt8ios_base4InitD1Ev
0000000000000000 r _ZStL19piecewise_construct
0000000000000004 b _ZStL8__ioinit
 
liujie@liujie-vm:~/Documents/demo/HelloWorld/Debug$ nm main.cpp.o | c++filt -t
                 U __cxa_atexit
                 U __dso_handle
                 U _GLOBAL_OFFSET_TABLE_
0000000000000062 unsigned short _GLOBAL__sub_I__ZN10NameSpace13funEv
000000000000000e T main
0000000000000019 unsigned short __static_initialization_and_destruction_0(int, int)
0000000000000000 B NameSpace1::x
0000000000000000 T NameSpace1::fun()
0000000000000007 T NameSpace2::fun()
                 U std::ios_base::Init::Init()
                 U std::ios_base::Init::~Init()
0000000000000000 r std::piecewise_construct
0000000000000004 bool std::__ioinit

注意

  • 在Linux系统中,nm 是一个命令行工具,用于列出目标文件(通常是 .o 文件)中的符号(symbol)。这些符号可以是函数、变量、常量等。nm 命令对于调试和分析程序的符号表非常有用。

    基本的 nm 命令用法示例:

    nm yourfile.o
    

    nm 的输出通常包含三列:

    1. 符号类型:可以是 T(文本)、D(数据)、B(bss)、R(只读数据)、C(常量)等,这些表示符号所在的内存段。
    2. 符号地址:符号在内存中的地址。
    3. 符号名称:符号的名称
  • c++filt 是一个用于解码 C++ 符号的命令行工具。它主要用于将 C++ 符号(通常是经过 mangling(名称修饰)后的)转换为可读的源代码形式。在 C++ 中,为了支持函数重载和复杂的类型系统,编译器会对函数和变量的名称进行 mangling,以生成唯一的标识符。

    c++filt 的使用非常简单,你只需要将 mangled 名称作为参数传递给该工具,它就会输出对应的 demangled(解码后)名称。

    • 基本用法:

      c++filt [options] [mangled_name]
      
    • -t 选项:

      c++filt-t 选项用于输出解码后的类型信息。当你使用 -t 选项时,c++filt 不仅会解码函数名,还会尝试解码参数和返回值的类型。

  C / C++ 系统IO比较:

  • printf: 使用直观,但容易出错
  • cout: 不容易出错,但书写冗长

在C++20格式化库中,提供了新的解决方案: std::format,它提供了一种类似于 Python 的字符串格式化机制,但编译器对C++20格式化库的支持还不够,需要 C++20 兼容的编译器。

三、控制流

  以猜数字为例,

#include <iostream>

int main()
{
    std::cout << "Please Input a number: \n";
    
    int y = 0;
    std::cin >> y;
    if(y == 42)
    {
        std::cout << "You are right!\n";
    }
    else
    {
        std::cout << "You are wrong!\n";
    }
}

  if语句用于分支选择,条件部分用于判断是否执行,返回bool值。语句部分是要执行的操作。

image-20240502195006090
#include <iostream>

int main()
{
    int x = 42, y = 0;
    
    while (x != y)
    {
        std::cout << "Please Input a number: ";
        std::cin >> y;
        if(y == 42)
        {
            std::cout << "You are right!\n";
        }
        else
        {
            std::cout << "You are wrong!\n";
        }
    }    
}

  while语句用于循环执行,条件部分用于判断是否执行。语句部分是要执行的操作。

image-20240502195609717

== 与= 操作

  • =操作:用于赋值,将数值保存在变量所对应的内存中,赋值表达式的返回值为左侧的常量。

    int x;
    x = y = 42;
    
  • ==操作:用于判断两个值是否相等

可以将常量放在==左边以防止误用。

四、结构体与自定义数据类型

  在C++中,结构体(struct)是一种复合数据类型,它允许将不同的数据项组合成一个单一的实体。结构体在C++中有着广泛的应用,包括表示数据集合、实现数据封装以及作为函数参数传递等。

  • 定义结构体

    结构体可以通过以下方式定义:

    struct MyStruct {
        int a;
        double b;
        std::string c;
        // 默认构造函数
        MyStruct() : a(0), b(0.0), c("") {}
    
        // 带有两个参数的构造函数
        MyStruct(int ia, double ib) : a(ia), b(ib), c("Initialized") {}
    
        // 全参构造函数
        MyStruct(int ia, double ib, const std::string& ic) : a(ia), b(ib), c(ic) {}
    };
    
  • 初始化结构体

    结构体可以通过直接初始化或使用构造函数进行初始化,结构体的构造函数与结构体的名称相同,并且没有返回类型。

    // 直接初始化
    MyStruct ms = {10, 20.5, "Hello"};
    
    // 使用构造函数(如果定义了)
    MyStruct ms(10, 20.5, "Hello");
    
  • 使用结构体

    结构体定义了一组数据,可以通过点(.)操作符访问这些数据:

    ms.a = 42;
    std::cout << ms.b << std::endl;
    
  • 结构体与类的区别

    尽管结构体和类在C++中非常相似,但它们之间存在一些差异:

    • 默认访问权限:在C++中,结构体成员的默认访问权限是public,而类的默认访问权限也是public,但在C++11及以后的版本中,结构体和类都可以通过访问说明符明确指定成员的访问权限。
    • 数据封装:类通常用于数据封装,而结构体更倾向于表示数据的简单集合。
    • 继承:类可以用于实现继承,而结构体通常不用于继承。
  • 结构体与函数

    结构体可以作为函数的参数传递,也可以作为函数的返回值:

    void printStruct(const MyStruct& ms) {
        std::cout << "a: " << ms.a << ", b: " << ms.b << ", c: " << ms.c << std::endl;
    }
    
    MyStruct createStruct() {
        return {1, 2.5, "Example"};
    }
    
  • 匿名结构体:

    C++允许在定义结构体的同时实例化,而不需要先声明类型:

    auto myStructInstance = struct {
        int a;
        double b;
        std::string c;
    } {10, 20.5, "Hello"};
    
  • 嵌套结构体

    结构体可以嵌套在其他结构体中:

    struct OuterStruct {
        struct InnerStruct {
            int x;
            double y;
        };
        InnerStruct inner;
    };
    
  • 结构体字面量

    C++11引入了结构体字面量,允许直接创建结构体的实例:

    auto ms = MyStruct{10, 20.5, "Hello"};
    

  结构体(struct)在C++中不仅可以包含数据成员,还可以引入成员函数,从而更好地表示函数与数据的相关性。

在结构体中定义成员函数

struct MyStruct {
    int value;

    // 构造函数
    MyStruct(int v) : value(v) {}

    // 成员函数,用于获取当前值
    int getValue() const {
        return value;
    }

    // 成员函数,用于设置新值
    void setValue(int v) {
        value = v;
    }
};

使用成员函数

  创建结构体对象后,可以通过点(.)操作符调用其成员函数:

MyStruct obj(10);
int val = obj.getValue(); // 调用成员函数获取值
obj.setValue(20);         // 调用成员函数设置新值

通过引入成员函数,结构体可以隐藏内部实现细节,只通过成员函数暴露操作数据的方式。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【补充】图神经网络前传——DeepWalk

论文阅读 论文&#xff1a;https://arxiv.org/pdf/1403.6652 参考&#xff1a;【论文逐句精读】DeepWalk&#xff0c;随机游走实现图向量嵌入&#xff0c;自然语言处理与图的首次融合_随机游走图嵌入-CSDN博客 abstract DeepWalk是干什么的&#xff1a;在一个网络中学习顶点…

求最大梯形的面积

【入门】求最大梯形的面积 今天做4星题单发现一个好玩的&#xff08;太简单了&#xff09;。 说明 从键盘读入n(3<n<100)个梯形的上底、下底和高&#xff0c;请问这n个梯形中&#xff0c;最大面积的梯形的面积是多少&#xff1f;&#xff08;梯形面积的求解公式为 S …

ExcelVBA在选择区域(有合并)中删除清除空行

【问题】 关于删除空行&#xff0c;以前是用函数来完成工作的&#xff0c; 今天有人提出问题&#xff0c;传来这个文件&#xff0c; 现有数据&#xff0c;1w多行&#xff0c;其中有部分列有不同合并单元格&#xff0c;跨行也不一样。如果要进行筛选删除空行&#xff0c;有一定的…

Rerank进一步提升RAG效果

RAG & Rerank 目前大模型应用中&#xff0c;RAG&#xff08;Retrieval Augmented Generation&#xff0c;检索增强生成&#xff09;是一种在对话&#xff08;QA&#xff09;场景下最主要的应用形式&#xff0c;它主要解决大模型的知识存储和更新问题。 简述RAG without R…

买卖股票的最佳时机 II(LeetCode 122)

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容&#xff0c;和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣&#xff01; 推荐&#xff1a;数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航&#xff1a; LeetCode解锁100…

整体安全设计

人员和资产的安全是当今许多组织的最高优先事项之一。随着暴力事件在美国各地盛行——枪击事件、袭击、内乱等——建筑物业主必须为其建筑物及其居住者的安全做好计划。 为了创造一个安全的环境&#xff0c;新设施或园区的安全设计必须超越基本的摄像头和访问控制设备&#xf…

HarmonyOS开发案例:【UIAbility内和UIAbility间页面的跳转】

UIAbility内和UIAbility间页面的跳转&#xff08;ArkTS&#xff09; 介绍 基于Stage模型下的UIAbility开发&#xff0c;实现UIAbility内和UIAbility间页面的跳转。包含如下功能&#xff1a; UIAbility内页面的跳转。跳转到指定UIAbility的首页。跳转到指定UIAbility的指定页…

centos7安装MySQL(rpm安装)

centos7安装MySQL&#xff08;rpm安装&#xff09; 准备工作1、卸载不要的环境2、获取MySQL官方yum源3、下载官方的yum源 安装可能遇到问题:描述解决方法&#xff1a; 配置添加远程访问用户设置MySql不区分大小写 准备工作 1、卸载不要的环境 grep mariadb # 先检查是否有mar…

【Java】/*方法的使用-快速总结*/

目录 一、什么是方法 二、方法的定义 三、实参和形参的关系 四、方法重载 五、方法签名 一、什么是方法 Java中的方法可以理解为C语言中的函数&#xff0c;只是换了个名称而已。 二、方法的定义 1. 语法格式&#xff1a; public static 返回类型 方法名 (形参列表) { //方…

【GD32】02-ADC模拟数字转换器

ADC 在电子和通信技术中&#xff0c;ADC&#xff08;模拟数字转换器&#xff09;是一种将模拟信号转换为数字信号的电子设备。这种转换是电子系统中非常关键的一个环节&#xff0c;因为数字信号更易于处理、存储和传输。ADC的工作原理通常包括采样、保持、量化和编码等步骤。采…

数据结构与算法===回溯法

文章目录 原理使用场景括号生成代码 小结 原理 回溯法是采用试错的思想&#xff0c;它尝试分步骤的去解决一个问题。在分步骤解决问题的过程中&#xff0c;当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候&#xff0c;它将取消上一步甚至是上几步的计算&#x…

wsl安装Xfce桌面并设置系统语言和输入法

一、安装xfce &#xff08;有相关的依赖都会安装&#xff09; sudo apt -y install xfce4 二、 安装远程连接组件 sudo apt install xrdp -y 并重新启动 Xrdp 服务&#xff1a; sudo systemctl restart xrdp 本地windows系统中请按 winR 键 呼出运行 在运行中输入 mstsc…

最简单的Winapi编程窗口程序

以下是一个简单的使用 WinAPI 创建窗口的程序示例&#xff0c;大致了解下win32的一个窗口编程大致流程&#xff1a; #include <Windows.h>// 窗口过程函数 LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {switch (uMsg){case WM_DES…

Ubuntu24 文件目录结构——用户——权限 详解

目录 权限 用户 文件目录结构 一个目录可以有程序&#xff0c;目录&#xff0c;文件&#xff0c;以及这三者的链接。可以看到还分别有使用者和权限信息。 每个文件和目录都有与之关联的三个主要属性&#xff1a;所有者&#xff08;owner&#xff09;、组&#xff08;group&a…

【Qt 学习笔记】Qt常用控件 | 布局管理器 | 垂直布局Vertical Layout

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 布局管理器 | 垂直布局Vertical Layout 文章编号&#x…

【JavaEE】Spring Boot 入门:快速构建你的第一个 Spring Boot 应用

目录 第一个SpringBoot程序介绍项目创建创建项目目录介绍输出Hello World 第一个SpringBoot程序 介绍 在学习SpringBoot之前, 我们先来认识⼀下Spring 我们看下Spring官⽅(https://spring.io/)的介绍 可以看到, Spring让Java程序更加快速, 简单和安全. Spring对于速度、简单…

【MySQL数据库】详解数据库审核工具SQLE的部署及接口调用

SQLE部署及使用 1. 部署SQLE SQLE相信大家都不陌生吧&#xff0c;它是一款开源&#xff0c;支持多场景审核&#xff0c;支持标准化上线流程&#xff0c;原生支持 MySQL 审核且数据库类型可扩展的 SQL审核工具。我们可以基于此工具进行数据库SQL审核&#xff0c;提升SQL脚本质量…

LangChain:模型 I/O 封装使用解析和感触

目录 模型 API&#xff1a;LLM vs. ChatModel OpenAI 模型封装 多轮对话 Session 封装 换个国产模型 模型的输入与输出 Prompt 模板封装 PromptTemplate ChatPromptTemplate MessagesPlaceholder 从文件加载 Prompt 模板 TXT模板 Yaml模板 Json模板 输出封装 Out…

使用模拟SPI接口驱动串行接口的LCD( STM32F4)

目录 概述 1. 硬件介绍 1.1 ST7796-LCD 1.2 MCU IO与LCD PIN对应关系 2 代码实现 2.1 STM32CubeMX 6.11生成工程 2.2 IO模拟SPI接口 2.3 实现LCD的驱动 3 测试 测试代码下载地址&#xff1a; stm32-f407-lcd-ft6336-proj资源-CSDN文库 gitee下载地址&#xff1a; h…

48. 旋转图像/240. 搜索二维矩阵 II

48. 旋转图像 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 &#xff1a; 输入&#xff1a;matrix [[5,1,9,11],[2,4,…