
C & C++ BASICS — 计算机世界的「内功心法」
几乎所有计算机专业课——数据结构、操作系统、计算机组成原理、编译原理——都以 C/C++ 为语言基础。学好 C/C++ 意味着你真正理解:程序是怎么在内存里跑起来的、数据是怎么存储的、指针到底指向哪里。这些底层认知,是后面学任何语言、任何方向(包括网安的逆向与 Pwn)都不会过时的「内功」。
同时,C/C++ 是算法竞赛(ACM、蓝桥杯)的主流语言,STL 标准库能大幅提升刷题效率。实验室的学长学姐建议:大一上学期认真过一遍 C,大一下再进入 C++ 与数据结构。
写 C/C++ 需要两样东西:编译器(把代码翻译成机器语言)和编辑器/IDE(写代码的地方)。三种常见选择:
| 方案 | 适合人群 | 说明 |
|---|---|---|
| VS Code + MinGW | 推荐(轻量) | 安装 VS Code → 装 C/C++ 插件 → 安装 MinGW-w64 编译器 → 配置 tasks.json 即可编译运行 |
| Visual Studio | Windows 开发 | 微软官方 IDE,安装「使用 C++ 的桌面开发」工作负载,开箱即用 |
| Dev-C++ | 上课/考试 | 国内教学常用,极小极简单,单文件即可编译运行 |
验证安装:写一个 hello.cpp,编译运行输出 Hello, World!,环境就 OK 了。
#include <iostream> // 引入输入输出头文件
using namespace std; // 使用标准命名空间(简化写法)
int main() { // 主函数:程序从这里开始执行
cout << "Hello, World!" << endl; // 输出一行文字并换行
return 0; // 返回 0 表示程序正常结束
}
变量是「装数据的盒子」。C++ 常用数据类型:
| 类型 | 说明 | 示例 | 占用 |
|---|---|---|---|
int | 整数 | int age = 18; | 4 字节 |
long long | 大整数 | long long x = 1e18; | 8 字节 |
float / double | 小数 | double pi = 3.14159; | 4 / 8 字节 |
char | 单个字符 | char c = 'A'; | 1 字节 |
bool | 真假 | bool ok = true; | 1 字节 |
string | 字符串(C++) | string s = "hello"; | 动态 |
C++ 用 cin 读入、cout 输出;C 语言风格是 printf / scanf(%d 整数、%c 字符、%s 字符串、%f 小数)。
#include <iostream>
using namespace std;
int main() {
int a; string name;
cin >> a >> name; // 连续读入
cout << "age=" << a << ", name=" << name << endl;
return 0;
}
+ - * / %(% 是取余,如 7 % 3 = 1;整数除法会截断,如 7 / 2 = 3)=、+=、-=、*=、/=> < >= <= == !=(结果为 bool)&&(与)、||(或)、!(非)i++、++i、i--int score = 85;
if (score >= 90) cout << "优秀";
else if (score >= 60) cout << "及格";
else cout << "不及格";
// switch 适合多值判断
int day = 3;
switch (day) {
case 1: cout << "周一"; break;
case 2: cout << "周二"; break;
default: cout << "其他";
}
// 输出 1~10 的和
int sum = 0;
for (int i = 1; i <= 10; i++) sum += i;
// while 适合不确定次数的循环
int n; while (cin >> n) { /* 读到文件尾为止 */ }
// do-while:至少执行一次
int x = 0;
do { x++; } while (x < 5);
int a[5] = {1, 2, 3, 4, 5}; // 一维数组,下标从 0 开始
cout << a[0] << a[4]; // 输出 1 和 5
int m[3][4]; // 二维数组(3 行 4 列)
// 注意:数组越界不会报错但会破坏内存,一定要小心!
char s[20] = "hello"; // C 风格字符串(字符数组)
string str = "hello"; // C++ 风格字符串(推荐,可拼接 str + "!")
// 返回两数较大值
int max2(int a, int b) { return a > b ? a : b; }
// 递归:自己调用自己(必须有终止条件!)
int fact(int n) { return n <= 1 ? 1 : n * fact(n - 1); }
int main() {
cout << max2(3, 7) << endl; // 7
cout << fact(5) << endl; // 120
}
指针是存储地址的变量。变量在内存中有自己的地址,指针就「指着」那个地址。理解指针 = 理解程序如何访问内存,这也是未来学逆向工程、理解栈溢出漏洞的根本。
int x = 42;
int* p = &x; // p 保存了 x 的地址(& 取地址)
cout << *p; // *p 解引用:取出 p 指向位置的值 = 42
*p = 100; // 通过指针修改 x,现在 x == 100
int a[5] = {10,20,30,40,50};
int* q = a; // 数组名本身就是首元素地址
cout << *(q + 2); // 30 —— 指针 + 2 跳过 2 个 int
指针常见易错点:
nullptrp + n 实际移动 n × sizeof(类型) 字节int* arr = new int[100]; ... delete[] arr; 手动的内存管理,是 C/C++ 强大与危险并存的原因;C++ 里推荐用 vector 代替裸指针数组。struct Student { // 结构体:把数据打包
string name;
int score;
};
Student s = {"张三", 95};
cout << s.name << s.score;
class Dog { // 类:数据 + 行为
public:
void bark() { cout << "汪!"; }
private:
int age = 2;
};
Dog d; d.bark();
| 容器 | 作用 | 示例 |
|---|---|---|
vector<T> | 动态数组 | vector<int> v; v.push_back(1); v.size(); |
string | 字符串 | s.length(); s.substr(0,3); s.find('a'); |
map<K,V> | 键值对(哈希) | map<string,int> m; m["a"]=1; |
stack<T> | 栈(后进先出) | push / pop / top / empty |
queue<T> | 队列(先进先出) | push / pop / front / empty |
set<T> | 集合(去重排序) | insert / count / erase |
sort() | 排序(算法) | sort(v.begin(), v.end()); |
刷题时 90% 的数据结构需求,用 STL 几行就能搞定。之后学习数据结构(链表、树、图)时再手写实现,理解底层。
题目:输入两个整数 a, b,输出它们的和。这是洛谷的「入门第一题」,用来熟悉提交流程。
#include <iostream>
using namespace std;
int main() {
int a, b;
cin >> a >> b;
cout << a + b << endl;
return 0;
}
💡 教训:注意题目数据范围 —— 如果 a、b 可能超过 int(约 21 亿),就要用 long long。
题目:给定整数数组 nums 和目标值 target,返回和为 target 的两个数的下标。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
for (int i = 0; i < nums.size(); i++)
for (int j = i + 1; j < nums.size(); j++)
if (nums[i] + nums[j] == target)
return {i, j};
return {};
}
};
unordered_map,对每个数查 target - 当前值 是否已出现。class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> mp;
for (int i = 0; i < nums.size(); i++) {
int need = target - nums[i];
if (mp.count(need)) return {mp[need], i};
mp[nums[i]] = i;
}
return {};
}
};
i 和 mp[need] 顺序无所谓。💡 这是面试高频题,务必背熟哈希写法。