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

ops/2024/9/24 7:14:53/

文章目录

    • 一、从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.oU __cxa_atexitU __dso_handleU _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 _ZN10NameSpace23funEvU _ZNSt8ios_base4InitC1EvU _ZNSt8ios_base4InitD1Ev
0000000000000000 r _ZStL19piecewise_construct
0000000000000004 b _ZStL8__ioinitliujie@liujie-vm:~/Documents/demo/HelloWorld/Debug$ nm main.cpp.o | c++filt -tU __cxa_atexitU __dso_handleU _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);         // 调用成员函数设置新值

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


http://www.ppmy.cn/ops/40272.html

相关文章

web后端——netbeans ide +jsp+servlet开发学习总结

目录 jsp基础 netbeans开发工具问题访问网页失败,404,not found 等?HTTP Status 405 - HTTP method POST is not supported......netbeans 提示无法启动GlassFish Server 4.1.1:服务器未运行时, HTTP 或 HTTPS 监听程序端口已被占用404 问题netbeans中项目中有多个html文件,如…

kafka安装及收发消息

kafka需要与zookeeper配合使用&#xff0c;但是从2.8版本kafka引入kraft&#xff0c;也就是说在2.8后&#xff0c;zookeeper和kraft都可以管理kafka集群&#xff0c;这里我们依然采用zookeeper来配合kafka。 1、首先我们下载zookeeper 下载地址为 https://zookeeper.apache.org…

Python numpy np.clip() 将数组中的元素限制在指定的最小值和最大值之间

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ numpy.clip&#xff1a;https://numpy.org/doc/stable/reference/generated/numpy.clip.html numpy.clip(a, a_min, a_max, outNone, **kwargs)下面这段示例代码使用了 Python 的 NumPy 库来实现一个简…

Linux 之 tail 命令

一、基本语法 tail [option] [file] 其中 option 是可选参数&#xff0c;用于定制命令的行为&#xff0c;file 则是要处理的目标文件名。 二、常用参数 几个常用的 option 选项&#xff1a; -n&#xff1a;显示文件的最后 n 行&#xff0c;默认为 10 行。-f&#xff1a;实…

SQLZOO:Using Null

数据表&#xff1a;teacher-dept teacher iddeptnamephonemobile1011Shrivell275307986 555 12341021Throd275407122 555 19201031Splint2293104Spiregrain32871052Cutflower321207996 555 6574106Deadyawn3345... dept idname1Computing2Design3Engineering... Q1 List the t…

经典的设计模式和Python示例(一)

目录 一、工厂模式&#xff08;Factory Pattern&#xff09; 二、单例模式&#xff08;Singleton Pattern&#xff09; 三、观察者模式&#xff08;Observer Pattern&#xff09; 一、工厂模式&#xff08;Factory Pattern&#xff09; 工厂模式&#xff08;Factory Pattern…

uniapp引用第三方组件样式无法穿透

在通过uniapp编写小程序过程中发现&#xff0c;引用第三方组件库的样式无法穿透修改。微信小程序文档也给出对应的解决思路自定义组件样式穿透 组件样式隔离 默认情况下&#xff0c;自定义组件的样式只受到自定义组件 wxss 的影响。除非以下两种情况&#xff1a; 指定特殊的…

云计算的优势与未来发展

随着数字化转型的蓬勃发展&#xff0c;云计算作为信息技术应用的基础设施&#xff0c;逐渐成为企业的首选。云计算以其诸多优势和未来发展趋势&#xff0c;为企业带来了更高效、灵活和创新的IT解决方案&#xff0c;助力企业实现数字化转型和业务发展。 云计算的优势 首先&…