Skip to content

💡 Code_Tricks


一、0x3f


  • 0x3f 在算法题/竞赛代码里早已不是 “63” 这么简单,

    它被当成一种 “ 安全、易写、不易溢出 ” 的 伪无穷大 使用。


  • 1). 单字节 0x3f -- memset 的 “填充无穷大”

    • memset 按字节赋值。

    • 0x3f 二进制 0011 1111,最高位是 0 → 看成有符号数也是正数。

    • 把整型数组每个字节都灌成 0x3f,效果:

类型内存示意(四字节)十进制值特点
int0x3F3F3F3F1061109567够大,但不到 INT_MAX , 加法不溢出
  • 使用示例:
c++
int g[N][N];
memset(g, 0x3f, sizeof g);   // 整型“无穷大”矩阵初始化 (如存图的邻接矩阵)

  • 2). 四字节 0x3f3f3f3f -- 真正 “INF” 常数
    • 值 ≈ 1.06 × 10^9,远小于 INT_MAX (≈ 2.14 × 10^9)。
    • 两个 INF 相加:1.06 G + 1.06 G = 2.12 G < INT_MAX,不会溢出。
    • 位运算友好:低 6 位全 1,取模、掩码时常能直接用。
  • 使用示例:
c++
const int INF = 0x3f3f3f3f;
int dist[N];
fill(dist, dist + N, INF);
c++
if (dist[u] == INF)  // u 还没被松弛
c++
if (dist[u] > INF / 2)  // 有负权边松弛,但起点不可达

二、getline


  • 注 :有两个重载版本:std::getlineistream::getline , 下面讲的是 std::getline

  • 函数原型:
c++
istream& getline(istream& is, string& str, char delim = '\n');
  • 读到 delim 为止(默认换行符),不把 delim 放进 str
  • 返回流引用,可直接当 bool 用
  • 会丢弃行尾的分隔符(与 C 的 fgets 不同)

  • 1). 基本用法:
c++
string line;
getline(cin, line);          // 读一整行,含空格

  • 2). 去除行末换行:

  • 如输入数据:

txt
2
5 6 8 11 9
10 12 9
c++
int cnt; 
cin >> cnt;		// 读到第一行的 2 
string line;
getline(cin, line); // 忽略掉第一行的回车
while( cnt -- ){
    // 读取正确数据
    getline(cin, line);
    // .....
}

  • 3). 循环读文件直到 EOF
c++
ifstream fin("data.txt");
string line;
while (getline(fin, line)) { /* 处理 line */ }

三、sstream


  • 头文件:
c++
#include <sstream>

  • 核心类就三个:
    • istringstream —— 把字符串当成输入流(解析用)
    • ostringstream —— 把字符串当成输出流(拼接用)
    • stringstream —— 既可读又可写(功能最全)

  • 1). 字符串 → 多字段解析(istringstream
c++
string line = "Tom 18 3.7";
istringstream iss(line);
string name; int age; double gpa;
iss >> name >> age >> gpa;          // 按 空格/TAB/换行 分割
if (iss) { /* 解析成功 */ }
  • 整行读取到末尾时最爽:
c++
while (getline(cin, line)) {
    istringstream iss(line);
    /* 逐行解析 */
}

  • 2). 任意类型 → 字符串(ostringstream
c++
int id = 7;
double score = 95.5;
ostringstream oss;
oss << "id=" << id << ",score=" << score;
string s = oss.str();         // "id=7,score=95.5"

  • 3). 字符串 ↔ 任意类型双向(stringstream
c++
stringstream ssin;
ssin << 123 << ' ' << 3.14;
int a; double b;
ssin >> a >> b;                       // 123 3.14

四、常用取数


  • 1). 某一个十进制数,每次取出最低位:
c++
while(x){
    // 把 x 的每一个数取出来
    int t = x % 10;	// 最低位那个数
    x /= 10;	// 删掉最低位
    
    // ...其它操作
}

  • 2). 某一个十进制数对应的二进制表示的每一位:
c++
int x = 11; //  二进制: 1011
while(x){
    int t = x & 1;  // 取最低位
    x >>= 1;        // 删掉最低位
    cout << t << ' ';   // 1 1 0 1 
}

  • 3). 某一个十进制的二进制表示中的第 k 位:
c++
n >> k & 1

  • 4). 某个十进制数的二进制表示的最后一位 1 及其后面的 0 对应是十进制数:
c++
int lowbit(int x){
    return x & -x;    
}

  • 5). 一个大长度的十进制数取某个区间技巧:(日期问题中常用)
    • / 1000 : 取前三位 (这个几位其实就是对应 1 后面 0 的个数)
    • % 1000 : 取后三位 (这个几位其实就是对应 1 后面 0 的个数)
c++
int date = 20251024;
// 取出年月日
int year = date / 10000;			// 取前四位 
int month = date % 10000 / 100;		// 先后四位再取前两位
int day = date % 100;				// 取后两位

  • 对于得到了由秒数来表示的时间,常用转换如下(虽然没上面那样可以数 0 的个数那么好记):
c++
int time = get_time();	// time 是获取到了一个由秒数来表示的时间
int hour = time / 3600;
int minute = time % 3600 / 60;
int second = time % 60;

五、sscanf


  • sscanf 是 C 语言中的一个标准库函数,用于从字符串中读取格式化输入。

    它的功能与 scanf 类似,但 scanf 是从标准输入读取,而 sscanf 是从字符串中读取。


  • 函数原型:
c++
int sscanf(const char *str, const char *format, ...);
参数说明
str要解析的字符串
format格式控制字符串(与 printf/scanf 的格式类似)
...指向变量的指针,用于存储解析出来的数据

  • 返回值:
    • 成功时:返回成功赋值的变量个数。
    • 失败时:返回 0 或负数(通常是 -1)。

  • 解析字符串中指定格式下不同位置,不同类型的数据:
c++
char *input = "name:Tom age:25 height:1.75";
char name[20];
int age;
float height;

sscanf(input, "name:%s age:%d height:%f", name, &age, &height);
printf("姓名:%s,年龄:%d,身高:%.2f\n", name, age, height);

  • 1231. 航班时间 :对于一个如下类型的航班时间格式各个部分的读取:
txt
17:21:07 00:31:46 (+1)
c++
int h1, m1, s1, h2, m2, s2, d;
sscanf(line.c_str(), "%d:%d:%d %d:%d:%d (+%d)", &h1, &m1, &s1, &h2, &m2, &s2, &d);

六、字符串&数字转换


6.1 字符串 -> 数字


  • 头文件:
c++
#include <string>

  • 示例:
c++
#include <string>
using namespace std;

int num = stoi("123");
long num_l = stol("123456");
double num_d = stod("123.45");

函数名缩写全称含义说明
stoistring to integer字符串转 int
stolstring to long字符串转 long
stollstring to long long字符串转 long long
stofstring to float字符串转 float
stodstring to double字符串转 double
stoldstring to long double字符串转 long double

6.2 数字 -> 字符串


  • 头文件:
c++
#include <string>

  • 示例:
c++
#include <string>
using namespace std;

// 整数 -> 字符串
int num = 123;
string str = to_string(num);  // "123"

// 浮点数 -> 字符串
double d = 3.14;
string str_d = to_string(d);  // "3.140000"

七、初始化&备份神器


  • “内存级” 工具 memset / memcpy 可以极快的效率完成 初始化 / 备份

    它比手写 for - loop 可以快 3 ~ 10


7.1 memset


  • 头文件:
c++
#include <cstring>   // 或者万能头 <bits/stdc++.h>

  • 1). 清零(最常用)
c++
int a[N];
memset(a, 0, sizeof(a));      // 每个字节置 0,整个数组变成 0

  • 2). 置 -1(利用补码特性,-1 每个字节都是 0xFF

常用邻接表的初始化,把静态链表的头节点都指向 -1 (NULL)

c++
// 使用邻接表来存储图
int h[N], w[N], e[N], ne[N], idx;
// ....
// 初始化邻接表表头
memset(h, -1, sizeof h);

  • 3). 置无穷大(只推荐 0x3f,原因见下)

求最短路时距离数组初始化为无穷大表示不可达

c++
int INF = 0x3f3f3f3f;         // 10^9 级别,两倍相加不爆 int
memset(dist, 0x3F, sizeof(dist));   // 每个字节 0x3F,整体 0x3F3F3F3F

  • 4). 结构体清零
c++
struct Node { int x, y; bool vis; };
Node pool[M];
memset(pool, 0, sizeof(pool));   // 全部字段变 0 / false

7.2 memcpy


  • 头文件:
c++
#include <cstring>   // 或者万能头 <bits/stdc++.h>

  • 1). 整型数组复制(比 for-loop 快 3~5 倍)

比如说在 bellman_ford 算法中 dist 需要先备份,后面使用备份来更新,防止 ”串联“ 操作

c++
int A[N], B[N];
//...                       // 计算完 A
memcpy(B, A, sizeof(A));  // B 变成 A 这一阶段的备份
// A 再去做其他计算 ...

  • 2). 结构体数组复制
c++
struct Pt { ll x, y; } p[N], bak[N];
memcpy(bak, p, sizeof(p));   // 备份整个点集

  • 3). 二维数组复制
c++
ll g[502][502], tmp[502][502];
memcpy(tmp, g, sizeof(g));   // 行主序连续,可直接拷

7.3 总结


  • 常用操作:
c++
memset(arr, 0, sizeof(arr));      // 清 0
memset(arr, -1, sizeof(arr));     // 置 -1
memset(arr, 0x3F, sizeof(arr));   // 置 INF
memcpy(dst, src, sizeof(src));    // 整块复制