添加随机数种子:
//通过利用当前时间生成随机数,防止每次随机数一样
srand((unsigned int)time(0));
int num=rand()%100+1;//生成1-100的值
//例如:如果需要生成30-200的值 那么% 171之后是0-170 之后再+1 为1-171范围 再+29 为30-200
//以此往前推即可
cout << num <<endl;
水仙花数:
简述:一个三位数,将其个位数、十位数、百位数拆解后各自立方之和等于这个三位数。
例如:2x2x2+7x7x7+0x0x0=270
程序逻辑:
1、输入三位数
int data;
cout<<"输入三位数: "<<endl;
cin>data;//输入的三位数值
2、使用do{}while()循环
循环解释:先执行一遍程序段之后进入循环判断
程序段:
do {
//拆解出个位数、十位数、百位数
unit = num % 10; //个位数
decade = num / 10 % 10; //十位数
hundreds = num / 100; // 百位数
cout << "hundreds: " << hundreds << "\tdecade: " << decade << "\tunit: " << unit << endl;
//各自立方和
data = unit * unit * unit + decade * decade * decade + hundreds * hundreds * hundreds;
//判断是否等于本身,如果是本身则输入该值时水仙花数。
if (data == num) {
cout << "水仙花数为:" << num << endl;
}
num++;
} while (num < 1000);
冒泡排序:
**注释:**第一个遍历,按顺序指定数据,将第一个遍历的数据和后面的数据依次比较,从小到大(前一个数据如果大于后面的数据进行替换),从大到小反之。
int arr[9] = { 4,2,8,0,5,7,1,3,9 };
int temp;
for (int i = 0; i < 9 - 1; i++) {
for (int j = i + 1; j < 9; j++) {
if (arr[i] > arr[j]) {
temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
else {
continue;
}
}
}
for (int i = 0; i < 9; i++) {
cout << arr[i] << endl;
}
分文件写法:
主文件:
导入
#include "子文件.h"
swap(1,2);
子文件.cpp:
cpp文件内部写函数的内容
#include "子文件.h"
void swap(int a,int b){
return a + b;
}
子文件.h:
定义函数
#pragma once
#include <iostream>
using namespace std;
void swap(int a,int b);
注意:.h文件头部的#pragm once必须要写,用来区分
扩展:
引用的区别
<文件>:内部的库使用
“文件”:自己写的库
空指针和野指针:
**空指针:**对指针一开始赋值为NULL
**野指针:**并未对指针赋初始值
这两指针最好不要出现在程序内部
const修饰对象区别:
指针常量:
修饰常量
指针的指向不可以修改,指针指向的值可以修改
int * const p = &a;
常量指针:
修饰指针
指针的指向可以修改,指针指向的值不可以修改
const int * p = &a;
第三种:
既修饰指针又修饰常量
const int * const p = &a;
浮点精度设置
std::setprecision(n) //n:打印长度
布尔类型0/1->true/false
std::cout << std::boolalpha; // 以 true , false 格式打印bool
std::cin >> std::boolalpha;// 允许用户输入 'true' or 'false' 作为bool变量的值
转义字符
名称 | 符号 | 含义 |
---|---|---|
告警(Alert) | \a | 发出告警,例如响铃 |
退格(Backspace) | \b | 将光标往后移一格 |
换页(Formfeed) | \f | 将光标移动到下一页 |
换行(Newline) | \n | 将光标移动到下一行 |
回车(Carriage return) | \r | 将光标移动到行的开头 |
水平制表(Horizontal tab) | \t | 水平制表符 |
垂直制表(Vertical tab) | \v | 垂直制表符 |
单引号(Single quote) | \’ | 单引号 |
双引号(Double quote) | " | 双引号 |
反斜杠(Backslash) | \ | 反斜杠 |
问号(Question mark) | ? | 问号 |
八进制数字(Octal number) | (number) | 按八进制解释为数字 |
十六进制数字(Hex number) | \x(number) | 按十六进制解释为数字 |
static_cast操作符
static_cast<新类型>(表达式)
例子:
#include <iostream>
void print(int x)
{
std::cout << x << '\n';
}
int main()
{
print( static_cast<int>(5.5) ); // 显示的将 double 值 5.5 转换为 int
return 0;
}
常量-优化程序
const修饰常量之后数据不可修改。
如何区分时编译时常量还是运行时常量?
用constexpr关键词进行修饰,且是能修饰编译时常量,如果修饰的是运行时常量则会报错。但constexpr修饰的函数可以传入 1、没被constexpr修饰的常量。不过会成为运行时求值。2、数值(例如1、2、3…),则有可能是编译时求值,也可能是运行时求值。
关键字consteval,用于指示函数必须在编译时求值,否则将导致编译错误。这种函数称为即时函数(immediate functions)
#include <iostream>
consteval int greater(int x, int y) // function 现在是 consteval
{
return (x > y ? x : y);
}
int main()
{
constexpr int g { greater(5, 6) }; // ok: 在编译时求值
std::cout << g << '\n';
std::cout << greater(5, 6) << " is greater!\n"; // ok: 在编译时求值
int x{ 5 }; // not constexpr
std::cout << greater(x, 6) << " is greater!\n"; // error: consteval 函数必须在编译时求值
return 0;
}
字面值常量
类别 | 后缀 | 类型 |
---|---|---|
integral | u or U | unsigned int |
integral | l or L | long |
integral | ul, uL, Ul, UL, lu, lU, Lu, LU | unsigned long |
integral | ll or LL | long long |
integral | ull, uLL, Ull, ULL, llu, llU, LLu, LLU | unsigned long long |
integral | z or Z | The signed version of std::size_t (C++23) |
integral | uz, uZ, Uz, UZ, zu, zU, Zu, ZU | std::size_t (C++23) |
floating point | f or F | float |
floating point | l or L | long double |
string | s | std::string |
string | sv | std::string_view |
float f { 4.1 }; // warning: 4.1 is a double literal, not a float literal
//默认带小数的数值是double类型,需要后缀4.1f
以十进制、八进制或十六进制输出值
#include <iostream>
int main()
{
int x { 12 };
std::cout << x << '\n'; // 十进制 (默认)
std::cout << std::hex << x << '\n'; // 16进制
std::cout << x << '\n'; // 现在是16进制
std::cout << std::oct << x << '\n'; // 八进制
std::cout << std::dec << x << '\n'; // 重新设置回十进制
std::cout << x << '\n'; // 十进制
return 0;
}
//输出
12
c
c
14
12
12
输出二进制值
#include <bitset> // 引入 std::bitset
#include <iostream>
int main()
{
// std::bitset<8> 意味着要存储 8 个 bit
std::bitset<8> bin1{ 0b1100'0101 }; // 二进制的 1100 0101
std::bitset<8> bin2{ 0xC5 }; // 十六进制的 1100 0101
std::cout << bin1 << '\n' << bin2 << '\n';
std::cout << std::bitset<4>{ 0b1010 } << '\n'; // 创建一个临时的bitset并打印
return 0;
}
//输出
11000101
11000101
1010
在C++20和C++23中,通过新的格式库(C++20)和打印库(C++23),我们有更好的选项:
#include <format> // C++20
#include <iostream>
#include <print> // C++23
int main()
{
std::cout << std::format("{:b}\n", 0b1010); // C++20
std::cout << std::format("{:#b}\n", 0b1010); // C++20
std::print("{:b} {:#b}\n", 0b1010, 0b1010); // C++23
return 0;
}
//输出
1010
0b1010
1010 0b1010
string库简介
序号 | 函数名称 |
---|---|
1 | std::string |
2 | std::getline() |
std::string
#include <iostream>
#include <string>
int main()
{
std::cout << "Enter your full name: ";
std::string name{};
std::cin >> name; // 可能不一定按预期工作,因为std::cin读取到 空白字符,就会停止
std::cout << "Enter your favorite color: ";
std::string color{};
std::cin >> color;
std::cout << "Your name is " << name << " and your favorite color is " << color << '\n';
return 0;
}
std::getline() 另一种方式输入字符串
#include <iostream>
#include <string> // 引入 std::string 和 std::getline
int main()
{
std::cout << "Enter your full name: ";
std::string name{};
std::getline(std::cin >> std::ws, name); // 将一整行输入读取到 name
std::cout << "Enter your favorite color: ";
std::string color{};
std::getline(std::cin >> std::ws, color); // 将一整行输入读取到 color
std::cout << "Your name is " << name << " and your favorite color is " << color << '\n';
return 0;
}
那么为什么会使用std::ws呢?
如果我们先cin然后再getline,那么会导致cin之后直接跳出,从而不会接受到getline的字符串。因此使用std::ws输入操纵器,告诉std::getline()忽略任何前导空格字符。
针对如何得到有多少个字符串
#include <iostream>
#include <string>
int main()
{
std::string name{ "Alex" };
std::cout << name << " has " << name.length() << " characters\n";
return 0;
}
#include <iostream>
#include <string>
int main()
{
std::string name{ "Alex" };
std::cout << name << " has " << std::ssize(name) << " characters\n";
return 0;
}
如果说你要将得到的字符串数量值传给int值,最好使用static_cast转化为int类型数值
int length { static_cast<int>(name.length()) };
为了节省运行时的资源,当把string初始化的值传到函数内部,会导致大量的资源消耗,因此可以利用std::string_view进行初始化数据,这样可以让数据变成只读数据,无法更改,因此只能用于不需要更改数据的场合。
#include <iostream>
#include <string_view>
// str 提供了传入参数的只读访问能力
void printSV(std::string_view str) // str现在是 std::string_view
{
std::cout << str << '\n';
}
int main()
{
std::string_view s{ "Hello, world!" }; // s现在是 std::string_view
printSV(s);
return 0;
}
注意:
1、string可以转换为string_view,但string_view不可以隐式转换为string
2、使用static_cast做显式转换
std::string_view更像是一个视图,我们可以通过限制查看的范围去左侧、右侧进行遮挡,从而删除字符
- remove_prefix() 成员函数从视图的左侧删除字符。
- remove_suffix() 成员函数从视图的右侧删除字符。
#include <iostream>
#include <string_view>
int main()
{
std::string_view str{ "Peach" };
std::cout << str << '\n';
// 从视图左侧移除一个字符
str.remove_prefix(1);
std::cout << str << '\n';
// 从视图右侧移除一个字符
str.remove_suffix(2);
std::cout << str << '\n';
str = "Peach"; // 重置视图
std::cout << str << '\n';
return 0;
}
//输出
Peach
each
ea
Peach
运算符优先级和结合性表
优先级/结合性 | 运算符 | 描述 | 模式 |
---|---|---|---|
1 L->R | :: | 全局命名空间(一元) | ::name |
:: | 命名空间(二元) | class_name::member_name | |
2 L->R | () | 括号 | (expression) |
() | 函数调用 | function_name(parameters) | |
() | 初始化 | type name(expression) | |
{} | 列表初始化 | type name{expression} | |
type() | 类型转换 | new_type(expression) | |
type{} | 类型转换 | new_type{expression} | |
[] | 数组下标取值 | pointer[expression] | |
. | 取对象成员 | object.member_name | |
-> | 取对象指针的成员 | object_pointer->member_name | |
++ | 后自增 | lvalue++ | |
–– | 后自减 | lvalue–– | |
typeid | 运行时类型信息 | typeid(type) or typeid(expression) | |
const_cast | 去掉类型的const限定 | const_cast(expression) | |
dynamic_cast | 运行时类型转换 | dynamic_cast(expression) | |
reinterpret_cast | 强制类型转换 | reinterpret_cast(expression) | |
static_cast | 编译时类型转换 | static_cast(expression) | |
sizeof… | 获取模板打包的参数个数 | sizeof…(expression) | |
noexcept | 编译时异常检查 | noexcept(expression) | |
alignof | 获取类型对齐方式 | alignof(type) | |
3 R->L | + | 一元加 | +expression |
- | 一元减 | -expression | |
++ | 前自增 | ++lvalue | |
– | 前自减 | ––lvalue | |
! | 逻辑非 | !expression | |
not | 逻辑非 | not expression | |
~ | 按位取反 | ~expression | |
(type) | c样式类型转换 | (new_type)expression | |
sizeof | 求字节大小 | sizeof(type) or sizeof(expression) | |
co_await | 异步Await调用 | co_await expression (C++20) | |
& | 取对象地址 | &lvalue | |
* | 解引用 | *expression | |
new | 动态内存分配 | new type | |
new[] | 动态数组内存分配 | new type[expression] | |
delete | 动态内存回收 | delete pointer | |
delete[] | 动态数组内存回收 | delete[] pointer | |
4 L->R | ->* | 成员指针访问 | object_pointer->*pointer_to_member |
.* | 成员对象访问 | object.*pointer_to_member | |
5 L->R | * | 乘 | expression * expression |
/ | 除 | expression / expression | |
% | 余数 | expression % expression | |
6 L->R | + | 加 | expression + expression |
- | 减 | expression - expression | |
7 L->R | « | 按位左移/插入 | expression « expression |
» | 按位右移/提取 | expression » expression | |
8 L->R | <=> | 三向比较 | expression <=> expression |
9 L->R | < | 小于比较 | expression < expression |
<= | 小于等于比较 | expression <= expression | |
> | 大于比较 | expression > expression | |
>= | 大于等于比较 | expression >= expression | |
10 L->R | == | 相等比较 | expression == expression |
!= | 不相等比较 | expression != expression | |
11 L->R | & | 按位 And | expression & expression |
12 L->R | ^ | 按位 XOR | expression ^ expression |
13 L->R | | | 按位 OR | expression | expression |
14 L->R | && | 逻辑 AND | expression && expression |
and | 逻辑 AND | expression and expression | |
15 L->R | || | 逻辑 OR | expression || expression |
or | 逻辑 OR | expression or expression | |
16 R->L | throw | 抛出异常 | throw expression |
co_yield | Yield 表达式 (C++20) | co_yield expression | |
?: | 条件表达式 | expression ? expression : expression | |
= | 赋值 | lvalue = expression | |
*= | 乘赋值 | lvalue *= expression | |
/= | 除赋值 | lvalue /= expression | |
%= | 余数赋值 | lvalue %= expression | |
+= | 加赋值 | lvalue += expression | |
-= | 减赋值 | lvalue -= expression | |
«= | 按位左移赋值 | lvalue «= expression | |
»= | 按位右移赋值 | lvalue »= expression | |
&= | 按位And赋值 | lvalue &= expression | |
|= | 按位Or赋值 | lvalue |= expression | |
^= | 按位Xor赋值 | lvalue ^= expression | |
17 L->R | , | 逗号运算符 | expression, expression |