C 与 C++学习基础

C & C++ BASICS — 计算机世界的「内功心法」

为什么大一新生要先学 C/C++?

几乎所有计算机专业课——数据结构、操作系统、计算机组成原理、编译原理——都以 C/C++ 为语言基础。学好 C/C++ 意味着你真正理解:程序是怎么在内存里跑起来的、数据是怎么存储的、指针到底指向哪里。这些底层认知,是后面学任何语言、任何方向(包括网安的逆向与 Pwn)都不会过时的「内功」。

同时,C/C++ 是算法竞赛(ACM、蓝桥杯)的主流语言,STL 标准库能大幅提升刷题效率。实验室的学长学姐建议:大一上学期认真过一遍 C,大一下再进入 C++ 与数据结构。

📌 推荐教材:《C Primer Plus》(C 语言)、《C++ Primer》(C++);在线刷题:洛谷、力扣;入门视频:B 站搜「C 语言程序设计」任一高播放量课程即可。

第一步:环境搭建(10 分钟搞定)

写 C/C++ 需要两样东西:编译器(把代码翻译成机器语言)和编辑器/IDE(写代码的地方)。三种常见选择:

方案适合人群说明
VS Code + MinGW推荐(轻量)安装 VS Code → 装 C/C++ 插件 → 安装 MinGW-w64 编译器 → 配置 tasks.json 即可编译运行
Visual StudioWindows 开发微软官方 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--

④ 分支:if / switch

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 << "其他";
}

⑤ 循环:for / while

// 输出 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
}

第三步:指针与内存 —— C/C++ 的灵魂

指针是存储地址的变量。变量在内存中有自己的地址,指针就「指着」那个地址。理解指针 = 理解程序如何访问内存,这也是未来学逆向工程、理解栈溢出漏洞的根本。

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

指针常见易错点:

  • 野指针:声明了却没初始化,指向未知内存 —— 声明时赋 nullptr
  • 悬空指针:指向的内存已被释放(delete 之后要置空)
  • 指针运算:p + n 实际移动 n × sizeof(类型) 字节
📌 动态内存:int* arr = new int[100]; ... delete[] arr; 手动的内存管理,是 C/C++ 强大与危险并存的原因;C++ 里推荐用 vector 代替裸指针数组。

第四步:C++ 面向对象与 STL 标准库

结构体与类

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();

STL 常用容器(竞赛刷题神器)

容器作用示例
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 几行就能搞定。之后学习数据结构(链表、树、图)时再手写实现,理解底层。

入门挑战 · 练习题(附 WP 与直达链接)

洛谷P1001 A+B Problem输入输出★☆☆ 去题目
📖 查看 WP 题解

题目:输入两个整数 a, b,输出它们的和。这是洛谷的「入门第一题」,用来熟悉提交流程。

1读题:从标准输入读两个整数,求和输出。
2代码(洛谷提交时语言选 C++17):
#include <iostream>
using namespace std;
int main() {
    int a, b;
    cin >> a >> b;
    cout << a + b << endl;
    return 0;
}
3提交:洛谷会自动评测多组数据,全部通过即显示 AC。

💡 教训:注意题目数据范围 —— 如果 a、b 可能超过 int(约 21 亿),就要用 long long。

力扣1. 两数之和数组 · 哈希★☆☆ 去题目
📖 查看 WP 题解

题目:给定整数数组 nums 和目标值 target,返回和为 target 的两个数的下标。

1暴力法(O(n²)):两层循环枚举所有数对,面试中先说这个再优化。
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 {};
    }
};
2哈希优化(O(n)):边遍历边把「值→下标」存进 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 {};
    }
};
3提交:注意返回的是下标而不是值,i 和 mp[need] 顺序无所谓。

💡 这是面试高频题,务必背熟哈希写法。

🚀 进阶刷题建议:洛谷「入门」→「普及-」难度逐题刷(推荐题单:洛谷官方题单);力扣按「数组 → 链表 → 哈希 → 栈队列 → 递归」专题刷。 每天 1~2 题,坚持一个月,进步会非常明显!