2025.10.14 闲话
好久没写过博客了,今天写一篇
没写博客主要是因为前段时间很忙,现在集训了,时间多了,自然就有空写博客了
笑点解析:懒得弄虚拟机的中文输入法,因此写这篇博客时专门从虚拟机切回windows
省流:
- 要用
ulimit -s unlimited - 对于占用内存较大的类型可在传入函数参数时将引用传入
注:本文代码均在 NOILinux 下的 VSCode 中编译与运行,编译选项为 -std=c++14 -O2 -Wall
Part.1 起因
在做矩阵求逆的时候写了这样一段代码:
完整代码
#include < bits/stdc++.h >
#define int long long
using namespace std;
const int M = 810 , mod = 1e9 + 7;
int n;
int qpow(int x , int y){
int res = 1;
while(y){
if(y & 1) res = res * x % mod;
x = x * x % mod , y >>= 1;
}
return res;
}
int inv(int x){ return qpow(x , mod - 2); }
struct mat{
int num[M][M];
int* operator [](int x){ return num[x]; }
mat(){ memset(num , 0 , sizeof(num)); }
}a;
istream& operator >>(istream& is , mat& A){
for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) is >> A[i][j];
return is;
}
ostream& operator <<(ostream& os , mat A){
for(int i = 0; i < n; ++i){
for(int j = 0; j < n; ++j) os << A[i][j] << ' ';
os << '\n';
}
return os;
}
void inv(mat A){
for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) A[i][j + n] = i == j;
for(int i = 0; i < n; ++i){
for(int j = i; j < n; ++j) if(A[j][i]){ swap(A.num[j] , A.num[i]); break; }
if(!A[i][i]){ cout<<"No Solution"; return; }
for(int j = n * 2 - 1; j >= i; --j) A[i][j] = A[i][j] * inv(A[i][i]) % mod;
for(int j = i + 1; j < n; ++j)
for(int k = n * 2 - 1; k >= i; --k)
(A[j][k] += mod - A[j][i] * A[i][k] % mod) %= mod;
}
for(int i = n - 1; i >= 0; --i)
for(int j = 0; j < i; ++j)
for(int k = n * 2 - 1; k >= i; --k)
(A[j][k] += mod - A[j][i] * A[i][k] % mod) %= mod;
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
A[i][j] = A[i][j + n] , A[i][j + n] = 0;
cout<<A;
}
signed main(){
freopen("data.in" , "r" , stdin) , freopen("data.out" , "w" , stdout);
ios::sync_with_stdio(0) , cin.tie(0) , cout.tie(0);
cin>>n>>a;
inv(a);
return 0;
}
省流:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int M = 810 , n = 5;
struct mat{
int num[M][M];
}a;
ostream& operator <<(ostream& os , mat A){
for(int i = 0; i < n; ++i){
for(int j = 0; j < n; ++j) os << A.num[i][j] << ' ';
os << '\n';
}
return os;
}
void f(mat A){
cout<<A;
}
signed main(){
f(a);
return 0;
}
喜报:正常过编了!
悲报:段错误 (核心已转储)
Part.2 调试
🤔🤔🤔
先是把无关代码删掉,得到以上省流版代码
还是段错误
把 operator <<(ostream& os , mat A) 中的 A 变成引用(即 operator <<(ostream& os , mat& A) )
我们惊奇地发现——居然能正常运行了!
但是为什么
仍然是先前的代码,注释掉 #define int long long,居然也不会发生段错误
于是我便naive地以为只是 #define 的问题
然而这时发生了三个状况:
- 若删去
#define int long long而只将num[M][M]设为long long,则仍然会发生段错误 - 在1.的基础上,将
num[M][M]设为int,则不会发生段错误 - 即使不删去
#define int long long,将M = 810改为M = 10同样不会发生段错误
从第三点入手,我找出了一个分界:
当 \(M\le723\) 时不会发生段错误,否则会发生段错误
然而这个 \(723\) 貌似并没有什么很直观的特点
那便输出一下 sizeof(a.num) 吧
结果:当 \(M=723\) 时输出 \(4181832\);当 \(M=724\) 时输出 \(4193408\)
🤔🤔🤔
我们发现 \(2^{22}=4194304\) 与这个值非常接近,而 \(4194304B=4096KB=4MB\)
答案呼之欲出——
Part.3 结论
起初,在 f(mat A) 与 operator<<(ostream& os , mat A) 中,传入的都是 mat 类型的对象,各占用 \(810\times810\times8=5248800B\),加在一起超出了 \(8192KB\),造成了段错误
而 f(mat& A) 与 operator<<(ostream& os , mat& A) 传入的是引用,不会额外占用空间,也不会超出 \(8192KB\) 的限制
那么这个 \(8192KB\) 是什么呢
是我偷懒没用ulimit -s unlimited导致栈空间上限是默认的\(8192KB\)
总结:对于占用内存较大的类型可在传入函数参数时将引用传入
随便写写
我怎么这就上高一了
一个半月集训可以集训出什么东西
快CSP了,加把劲!
快NOIP了,加把劲!

浙公网安备 33010602011771号