资源
只记录自认为不太熟悉的部分。
正文
工具概念
编译器
语法检查 :编译器会在编译阶段检查语法和类型错误。
代码优化 :
多平台支持 :不同编译器对目标操作系统和 CPU 架构支持不同。
链接库 :
静态库(.lib / .a)
动态库(.dll / .so / .dylib)
标准兼容性 :支持 C++11/14/17/20 等标准,或 C89/C99/C11 等。
编译器
特点
平台
GCC (GNU Compiler Collection)
免费开源、支持多种语言、优化能力强
Linux/Windows(MinGW)/macOS
Clang/LLVM
语法错误提示友好、快速、模块化
Linux/macOS/Windows
MSVC (Microsoft Visual C++)
与 Windows/Visual Studio 紧密结合
Windows
Intel C++ Compiler (ICC/oneAPI)
高性能优化,适合科学计算
Windows/Linux
TinyCC (TCC)
极小,编译速度快
Linux/Windows
gcc/g++
VSC 的终端(Powershell)使用 gcc 快速编译并执行(PowerShell 调用 cmd命令):
1 cmd /c "gcc main.c -o main.exe && main.exe"
Linux 下:
1 gcc main.c -o main && ./main
如果是 C++,则需要用 g++:
1 cmd /c "g++ main.cpp -o main.exe && main.exe"
C/C++互相调用编译
项目结构如下:
1 2 3 4 5 interop/ ├── main.c // C 文件,调用 C++ 函数 ├── helper.cpp // C++ 文件,调用 C 函数 ├── helper.h // C 函数头文件 └── cppfunc.h // C++ 函数声明给 C 调用
helper.h (C 头文件,给 C++ 调用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #ifndef HELPER_H #define HELPER_H #ifdef __cplusplus extern "C" { #endif int c_add (int a, int b) ;int c_subtract (int a, int b) ;#ifdef __cplusplus }#endif #endif
helper.cpp (C++ 文件,实现 C 函数,并定义 C++ 函数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include "helper.h" #include <iostream> int c_add (int a, int b) { return a + b; }int c_subtract (int a, int b) { return a - b; }extern "C" int cpp_multiply (int a, int b) { return a * b; }extern "C" void cpp_hello () { std::cout << "Hello from C++!" << std::endl; }
cppfunc.h (给 C 调用 C++ 函数的头文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #ifndef CPPFUNC_H #define CPPFUNC_H #ifdef __cplusplus extern "C" {#endif int cpp_multiply (int a, int b) ;void cpp_hello () ;#ifdef __cplusplus }#endif #endif
main.c (C 文件,调用 C++ 函数,同时测试 C++ 调用 C 函数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <stdio.h> #include "cppfunc.h" #include "helper.h" int main () { int a = 10 , b = 5 ; int prod = cpp_multiply(a, b); printf ("C calling C++ multiply: %d\n" , prod); cpp_hello(); int sum = c_add(a, b); int diff = c_subtract(a, b); printf ("C++ calling C add: %d\n" , sum); printf ("C++ calling C subtract: %d\n" , diff); return 0 ; }
编译并运行:
1 2 3 4 g++ -c helper.cpp # 编译 C++ 文件 gcc -c main.c # 编译 C 文件 g++ main.o helper.o -o interop_example # 链接生成可执行文件 ./interop_example
1 2 3 4 C calling C++ multiply: 50 Hello from C++! C++ calling C add: 15 C++ calling C subtract: 5
C++ 调用 C
C 头文件使用 extern "C" 包装,避免名字修饰。
C 调用 C++
C++ 函数也用 extern "C" 对外暴露,否则 C 编译器找不到符号。
编译顺序
先单独编译 C++ 和 C 文件,再用 g++ 链接。
使用 g++ 链接可以自动处理 C++ 标准库。
CMake
角色
功能
CMake
生成构建系统文件(Makefile / VS 工程)
编译器
将源码编译成目标文件和可执行文件
链接器
将目标文件与库链接成最终可执行程序
CMake 是 “指挥官”,编译器是 “工人”,链接器是 “装配工”。
快速开始
工程结构如下:
1 2 3 4 5 6 7 MyProject/ ├── CMakeLists.txt ├── src/ │ ├── foo.cpp │ └── main.cpp └── include/ └── foo.h
main.cpp:
1 2 3 4 5 6 7 8 9 #include <iostream> #include "foo.h" int main () { print_message ("Hello from foo.cpp!" ); int result = add (3 , 5 ); std::cout << "3 + 5 = " << result << std::endl; return 0 ; }
foo.cpp:
1 2 3 4 5 6 7 8 9 10 #include "foo.h" #include <iostream> void print_message (const std::string& msg) { std::cout << "[Message] " << msg << std::endl; }int add (int a, int b) { return a + b; }
foo.h:
1 2 3 4 5 #pragma once #include <string> void print_message (const std::string& msg) ;int add (int a, int b) ;
CMakeLists.txt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 cmake_minimum_required (VERSION 3.10 )project (MyProject VERSION 1.0 LANGUAGES CXX)set (CMAKE_CXX_STANDARD 17 )set (CMAKE_CXX_STANDARD_REQUIRED True )file (GLOB SOURCES "src/*.cpp" )add_executable (${PROJECT_NAME} ${SOURCES} )target_include_directories (${PROJECT_NAME} PRIVATE include )if (MSVC) target_compile_options (${PROJECT_NAME} PRIVATE /W4) target_compile_options (${PROJECT_NAME} PRIVATE $<$<CONFIG:Release>:/O2> ) target_compile_options (${PROJECT_NAME} PRIVATE $<$<CONFIG:Debug>:/RTC1> )elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) target_compile_options (${PROJECT_NAME} PRIVATE -Wall -Wextra) target_compile_options (${PROJECT_NAME} PRIVATE $<$<CONFIG:Release>:-O2> )endif ()
编译并运行(VS2022):
1 2 3 mkdir build cd build cmake -G "Visual Studio 17 2022" ..
1 2 3 4 5 6 7 8 9 -- The CXX compiler identification is MSVC 19.44.35213.0 -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: D:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.44.35207/bin/Hostx64/x64/cl.exe - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done (5.4s) -- Generating done (0.1s) -- Build files have been written to: D:/Users/Documents/Study/C/build
1 cmake --build . --config Release
1 2 3 4 5 6 7 8 9 适用于 .NET Framework MSBuild 版本 17.14.14+a129329f1 1>Checking Build System Building Custom Rule D:/Users/Documents/Study/C/CMakeLists.txt foo.cpp main.cpp 正在生成代码... MyProject.vcxproj -> D:\Users\Documents\Study\C\build\Release\MyProject.exe Building Custom Rule D:/Users/Documents/Study/C/CMakeLists.txt
1 2 cd Release MyProject.exe
1 2 [Message] Hello from foo.cpp! 3 + 5 = 8
Makefile
特性
Makefile
CMake
定位
编译脚本
构建系统生成器
复杂项目支持
较弱
非常强大
跨平台
不太行
出色
难度
写起来复杂
语法简单,且模块化
工程可维护性
较差
优秀
小项目可用 Makefile,大项目用 CMake。
功能
Bazel
CMake
Make
Maven/Gradle
定位
完整构建系统
构建文件生成器
编译脚本
Java 构建/依赖管理
增量构建速度
⭐⭐⭐⭐⭐
⭐⭐
⭐
⭐⭐⭐
多语言支持
优秀
中等
弱
弱(Java 周边)
适合项目规模
超大型
中/大型
小型
中型
学习成本
高
中
低
中
快速开始
在上一个文件项目结构中,创建 Makefile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 CC = gcc CXX = g++ CFLAGS = -Wall -Iinclude CXXFLAGS = -Wall -Iinclude SRCDIR = src C_SOURCES = $(wildcard $(SRCDIR) /*.c) CPP_SOURCES = $(wildcard $(SRCDIR) /*.cpp) C_OBJS = $(C_SOURCES:.c=.o) CPP_OBJS = $(CPP_SOURCES:.cpp=.o) TARGET = main.exeall: $(TARGET) $(TARGET) : $(C_OBJS) $(CPP_OBJS) ifeq ($(CPP_OBJS) ,) $(CC) -o $@ $(C_OBJS) else $(CXX) -o $@ $(C_OBJS) $(CPP_OBJS) endif %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ %.o: %.cpp $(CXX) $(CXXFLAGS) -c $< -o $@ .PHONY : cleanclean: del /Q $(SRCDIR)\* .o $(TARGET)
编译:
1 2 3 g++ -Wall -Iinclude -c src/main.cpp -o src/main.o g++ -Wall -Iinclude -c src/foo.cpp -o src/foo.o g++ -o main.exe src/main.o src/foo.o
Keil
Keil = 针对嵌入式 MCU 的 C/C++ IDE + 编译器 + 调试工具。
在嵌入式开发中,有些团队会用 CMake + ARM GCC 替代 Keil 的 ARMCC,方便自动化和跨平台构建。
Keil uVision 工程主要由两个文件组成:
.uvprojx
XML 格式,包含工程全局配置、源文件、宏定义、头文件路径等。
.uvoptx
文件类型
后缀
描述
格式
支持的 Keil 版本
.uvproj
.uvproj
旧版 Keil 工程文件
文本格式,但结构较简单(类似 INI)
Keil uVision4 及以前
.uvprojx
.uvprojx
新版 Keil 工程文件
XML 格式 ,更规范、更可扩展
Keil uVision5 及以后
VSC IntelliSense
差别
VSCode
Keil
编辑器类型
轻量、插件化
全功能 IDE
引用错误提示来源
IntelliSense 静态分析
真正编译器解析
宏和头文件解析
依赖配置(includePath, defines, compilerPath)
工程配置 + 编译器内置宏
错误提示准确性
可能和真实编译器不一致
精准一致
文件管理
通过文件夹 + Makefile/CMake
工程文件管理,依赖关系明确
c_cpp_properties.json
VSCode 默认不会自动创建 这个文件。
只有当你在 C/C++ 项目中配置 IntelliSense 或者尝试 生成配置 时才会创建。
如果只是安装了 C/C++ 扩展,但没有明确配置 Include Path 或编译器,VSCode 会使用 默认 IntelliSense 模式 ,并不会生成文件。
若如此配置项目结构和 .vscode/c_cpp_properties.json:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 { "configurations" : [ { "name" : "Win32" , "includePath" : [ "${workspaceFolder}/include" , "C:/MinGW/include" , "C:/MinGW/lib/gcc/mingw32/6.3.0/include" , ] , "defines" : [ "UNICODE" , "_DEBUG" ] , "compilerPath" : "C:/MinGW/bin/gcc.exe" , "cStandard" : "c11" , "cppStandard" : "c++17" , "intelliSenseMode" : "gcc-x64" } ] , "version" : 4 }
其中的关键配置项:
配置项
作用
建议 / 说明
includePath
告诉 IntelliSense 去哪些路径查找头文件
将 Keil 工程中所有相关头文件路径加入,如 CMSIS、HAL、StdPeriph 和工程自定义头文件。这样 IntelliSense 才能正确解析类型、函数声明和宏。
defines
告诉 IntelliSense 工程中定义了哪些宏,类似 #define FOO 1
同步 Keil 工程里的宏定义,确保条件编译(#ifdef、#if)解析一致。
compilerPath
指向编译器的实际可执行文件,如 Keil 的 armcc.exe 或 armclang.exe
IntelliSense 可以根据真实编译器解析宏、内置类型和关键字。
cStandard / cppStandard
指定 C/C++ 标准版本,例如 C99、C11、C++14、C++17
确保 IntelliSense 解析代码时遵循与实际编译器一致的标准。
IntelliSense 将会找不到 foo.h 而出现报错提示:
添加 includePath 即可消除这个报错提示,但是如果不正确地配置编译器,编译还是出现错误。
VSCode 也可以配合 CMake Tools 或 Makefile 插件来设置 IntelliSense。
同步 Keil 与 VSC 的错误提示
思路如下:
配置 VSC 的 IntelliSense 与 Keil 一致
修改 .vscode/c_cpp_properties.json,配置:
"includePath":加入 Keil 工程里的所有头文件路径(CMSIS、HAL、StdPeriph、工程自定义头文件)。
"defines":加入 Keil 工程里的宏定义。
"compilerPath":指向 Keil 的编译器路径(如 armcc.exe 或 armclang.exe)。
"cStandard" / "cppStandard":和 Keil 工程设置一致(C99/C11, C++14/C++17)。
因此可以写一个 python 脚本分析项目工程中的 .uvprojx以生成对应的 .vscode/c_cpp_properties.json 来实现同步错误提示的效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 import xml.etree.ElementTree as ETimport jsonimport os uvprojx_file = "${workspaceFolder}/Project/XXX.uvprojx" workspace_folder = "${workspaceFolder}" output_vscode_file = ".vscode/c_cpp_properties.json" compiler_path = "arm-none-eabi-gcc" c_standard = "c11" cpp_standard = "c++17" ws_abs_path = os.getcwd() uvprojx_file_abs = uvprojx_file.replace("${workspaceFolder}" , ws_abs_path) tree = ET.parse(uvprojx_file_abs) root = tree.getroot() uvprojx_dir = os.path.dirname(uvprojx_file_abs) include_paths = set () defines = set ()for target in root.findall(".//Target" ): for path in target.findall(".//IncludePath" ): if path.text: for p in path.text.split(";" ): if p.strip(): abs_path = os.path.normpath(os.path.join(uvprojx_dir, p.strip())) rel_path = os.path.relpath(abs_path, start=ws_abs_path) include_paths.add(os.path.join(workspace_folder, rel_path).replace("\\" , "/" )) for define in target.findall(".//Define" ): if define.text: for d in define.text.split(";" ): if d.strip(): defines.add(d.strip()) final_defines = []for d in defines: for item in d.split("," ): item = item.strip() if item: item = item.replace("\\\"" , "\"" ) final_defines.append(item) vscode_config = { "configurations" : [ { "name" : "Keil" , "includePath" : sorted (list (include_paths)), "defines" : sorted (final_defines), "compilerPath" : compiler_path, "cStandard" : c_standard, "cppStandard" : cpp_standard } ], "version" : 4 } os.makedirs(os.path.dirname(output_vscode_file), exist_ok=True )with open (output_vscode_file, "w" , encoding="utf-8" ) as f: json.dump(vscode_config, f, indent=4 )print (f"已生成 VSCode 配置: {output_vscode_file} " )
C
头文件
头文件(Header File)是 C/C++ 中 .h 或者没有扩展名的文件,用于声明 程序中要使用的函数、类、宏、常量、数据类型等。它本身通常不包含具体的函数实现(C++ 中可以有模板实现或 inline 函数)。
主要作用:
函数声明 :告诉编译器函数的名称、参数类型和返回类型,以便在调用时进行类型检查。
宏定义 :定义常用的宏,例如 #define PI 3.14159。
结构体/类声明 :让源文件知道某个类型的存在。
代码复用 :将公共声明放在头文件中,多个源文件可以共享。
避免重复定义 :通过 #ifndef/#define/#endif 防止头文件被多次包含。
特性
C/C++
Java/C#
文件组织
函数/类声明和定义可以分开
类声明和定义通常在同一文件
编译模型
分文件编译,需要先声明再调用
编译器可直接读取类文件或中间表示
是否需要头文件
是,用于声明接口
否,类文件本身就是接口和实现
分析依赖
头文件 + 源文件
类引用 + import/using
C/C++ 的头文件是历史遗留和编译模型的产物 ,而 Java/C# 的编译器更智能,能直接处理完整类信息,不需要额外的“声明文件”。
数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <stdio.h> #include <limits.h> #include <float.h> int main () { printf ("char: %zu bytes, range: %d to %d\n" , sizeof (char ), CHAR_MIN, CHAR_MAX); printf ("unsigned char: %zu bytes, range: 0 to %u\n" , sizeof (unsigned char ), UCHAR_MAX); printf ("short: %zu bytes, range: %d to %d\n" , sizeof (short ), SHRT_MIN, SHRT_MAX); printf ("unsigned short: %zu bytes, range: 0 to %u\n" , sizeof (unsigned short ), USHRT_MAX); printf ("int: %zu bytes, range: %d to %d\n" , sizeof (int ), INT_MIN, INT_MAX); printf ("unsigned int: %zu bytes, range: 0 to %u\n" , sizeof (unsigned int ), UINT_MAX); printf ("long: %zu bytes, range: %ld to %ld\n" , sizeof (long ), LONG_MIN, LONG_MAX); printf ("unsigned long: %zu bytes, range: 0 to %lu\n" , sizeof (unsigned long ), ULONG_MAX); printf ("long long: %zu bytes, range: %lld to %lld\n" , sizeof (long long ), LLONG_MIN, LLONG_MAX); printf ("unsigned long long: %zu bytes, range: 0 to %llu\n" , sizeof (unsigned long long ), ULLONG_MAX); printf ("float: %zu bytes, range: %e to %e\n" , sizeof (float ), FLT_MIN, FLT_MAX); printf ("double: %zu bytes, range: %e to %e\n" , sizeof (double ), DBL_MIN, DBL_MAX); printf ("long double: %zu bytes, range: %Le to %Le\n" , sizeof (long double ), LDBL_MIN, LDBL_MAX); printf ("bool/_Bool: %zu bytes\n" , sizeof (_Bool )); printf ("int*: %zu bytes\n" , sizeof (int *)); return 0 ; }
当前的 C 环境 = Windows + MinGW (32-bit) + LLP64 + ILP32 类型模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 char: 1 bytes, range: -128 to 127 unsigned char: 1 bytes, range: 0 to 255 short: 2 bytes, range: -32768 to 32767 unsigned short: 2 bytes, range: 0 to 65535 int: 4 bytes, range: -2147483648 to 2147483647 unsigned int: 4 bytes, range: 0 to 4294967295 long: 4 bytes, range: -2147483648 to 2147483647 unsigned long: 4 bytes, range: 0 to 4294967295 long long: 8 bytes, range: -9223372036854775808 to 9223372036854775807 unsigned long long: 8 bytes, range: 0 to 18446744073709551615 float: 4 bytes, range: 1.175494e-038 to 3.402823e+038 double: 8 bytes, range: 2.225074e-308 to 1.797693e+308 long double: 12 bytes, range: -0.000000e+000 to -1.#QNAN0e+000 bool/_Bool: 1 bytes int*: 4 bytes
当前的 C 环境 = 64 位 Linux / macOS(或 MinGW-w64 64 位)且符合 LP64 模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 char: 1 bytes, range: -128 to 127 unsigned char: 1 bytes, range: 0 to 255 short: 2 bytes, range: -32768 to 32767 unsigned short: 2 bytes, range: 0 to 65535 int: 4 bytes, range: -2147483648 to 2147483647 unsigned int: 4 bytes, range: 0 to 4294967295 long: 8 bytes, range: -9223372036854775808 to 9223372036854775807 unsigned long: 8 bytes, range: 0 to 18446744073709551615 long long: 8 bytes, range: -9223372036854775808 to 9223372036854775807 unsigned long long: 8 bytes, range: 0 to 18446744073709551615 float: 4 bytes, range: 1.175494e-38 to 3.402823e+38 double: 8 bytes, range: 2.225074e-308 to 1.797693e+308 long double: 16 bytes, range: 3.362103e-4932 to 1.189731e+4932 bool/_Bool: 1 bytes int*: 8 bytes
变量定义与声明
定义会:
声明只告诉编译器:
“这个变量在别处存在,我这里只是提前告诉你它的类型。”
创建 addtwoumn.c:
1 2 3 4 5 extern int x;extern int y;int addtwonum () { return x + y; }
创建 test.c:
1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio.h> int x = 1 ;int y = 2 ;int addtwonum () ;int main (void ) { int result; result = addtwonum(); printf ("result is: %d\n" , result); return 0 ; }
编译并执行:
1 2 gcc addtwonum.c test.c -o main ./main
变量存放区域
数据类型/变量类型
存放区域
说明
局部变量(非 static)
栈 Stack
函数内部定义的普通变量
函数参数
栈 Stack
参数也在栈里
静态局部变量 static
Data/BSS
不在栈上,整个程序生命周期
全局变量(已初始化)
Data 段
程序加载时就存在
全局变量(未初始化)
BSS 段
程序加载时为 0
const 全局变量
Data / RO Data
只读区域或普通 data
字符串字面量 “abc”
只读段(text/rodata)
不可修改(修改会 crash)
malloc/new 分配
堆 Heap
运行时动态分配
函数代码本身
Text 段
存的是机器指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <stdio.h> #include <stdlib.h> int g_init = 10 ; int g_uninit; static int s_init = 20 ; static int s_uninit; const int g_const = 30 ; void test_function () { int local = 1 ; static int local_static = 2 ; int *heap = malloc (sizeof (int )); *heap = 3 ; const char *str = "hello" ; printf ("【函数内变量】\n" ); printf (" local (stack) = %p\n" , (void *)&local); printf (" local_static (data/bss) = %p\n" , (void *)&local_static); printf (" heap (heap) = %p\n" , (void *)heap); printf (" str literal (rodata) = %p\n" , (void *)str); free (heap); }int main () { printf ("【全局变量】\n" ); printf (" g_init (data) = %p\n" , (void *)&g_init); printf (" g_uninit (bss) = %p\n" , (void *)&g_uninit); printf (" s_init (data) = %p\n" , (void *)&s_init); printf (" s_uninit (bss) = %p\n" , (void *)&s_uninit); printf (" g_const (rodata/data) = %p\n" , (void *)&g_const); printf ("\n" ); test_function(); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 【全局变量】 g_init (data) = 00404004 g_uninit (bss) = 00407074 s_init (data) = 00404008 s_uninit (bss) = 00407020 g_const (rodata/data) = 00405064 【函数内变量】 local (stack ) = 0061F EF4 local_static (data/bss) = 0040400 C heap (heap) = 00B 91468 str literal (rodata) = 00405068
当局部变量被定义时,系统不会对其初始化,必须自行对其初始化。定义全局变量时,系统会自动对其初始化。
数组
1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio.h> #define LENGTH(array) (sizeof(array) / sizeof(array[0])) int main () { int array2[] = {1 , 2 , 3 , 4 , 5 }; int length = LENGTH(array2); printf ("Array length: %d\n" , length); return 0 ; }
指针
指针就是 存储变量地址的变量 。
用 * 表示指针类型
用 & 取变量地址
用 * 解引用(访问指针指向的值)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> int main () { int a = 10 ; int *p = &a; printf ("Value of variable a: %d\n" , a); printf ("Address of variable a: %p\n" , (void *)&a); printf ("Address stored in pointer p: %p\n" , (void *)p); printf ("Value accessed through pointer p: %d\n" , *p); *p = 20 ; printf ("Value of a after modification: %d\n" , a); printf ("Address of pointer p: %p\n" , (void *)&p); return 0 ; }
1 2 3 4 5 6 Value of variable a: 10 Address of variable a: 0061FF1C Address stored in pointer p: 0061FF1C Value accessed through pointer p: 10 Value of a after modification: 20 Address of pointer p: 0061FF18
复杂用法:
类型
用途
指针数组
保存多个变量地址
指向指针
多级访问,修改指针本身
函数指针
动态调用函数,回调
动态二维数组
矩阵、多维动态数据
指针 + 结构体
链表、树、图等动态数据结构
指针数组(Array of Pointers)
指针数组是一个数组,每个元素都是一个指针。
1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio.h> int main () { int a = 1 , b = 2 , c = 3 ; int *arr[3 ] = {&a, &b, &c}; for (int i = 0 ; i < 3 ; i++) { printf ("arr[%d] points to value = %d\n" , i, *arr[i]); } return 0 ; }
1 2 3 arr[0] points to value = 1 arr[1] points to value = 2 arr[2] points to value = 3
指向指针的指针(Pointer to Pointer)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <stdio.h> int main () { int a = 10 ; int *p = &a; int **pp = &p; printf ("a = %d\n" , a); printf ("*p = %d\n" , *p); printf ("**pp = %d\n" , **pp); **pp = 20 ; printf ("a after modification = %d\n" , a); return 0 ; }
1 2 3 4 a = 10 *p = 10 **pp = 10 a after modification = 20
指针和函数(函数指针)
函数指针可以存储函数地址,实现动态调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <stdio.h> int add (int a,int b) { return a+b; }int sub (int a,int b) { return a-b; }int main () { int (*func)(int ,int ); func = add; printf ("add: %d\n" , func(5 ,3 )); printf ("add address: %p\n" , (void *)func); func = sub; printf ("sub: %d\n" , func(5 ,3 )); printf ("sub address: %p\n" , (void *)func); return 0 ; }
1 2 3 4 add: 8 add address: 00401460 sub: 2 sub address: 0040146D
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <stdlib.h> #include <stdio.h> void populate_array (int *array , size_t arraySize, int (*getNextValue)(void )) { for (size_t i=0 ; i<arraySize; i++) array [i] = getNextValue(); } int getNextRandomValue (void ) { return rand(); } int main (void ) { int myarray[10 ]; populate_array(myarray, 10 , getNextRandomValue); for (int i = 0 ; i < 10 ; i++) { printf ("%d " , myarray[i]); } printf ("\n" ); return 0 ; }
1 41 18467 6334 26500 19169 15724 11478 29358 26962 24464
动态二维数组
用途:二维/多维动态数组、矩阵运算。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <stdio.h> #include <stdlib.h> int main () { int rows = 2 , cols = 3 ; int **matrix = malloc (rows * sizeof (int *)); for (int i = 0 ; i < rows; i++) matrix[i] = malloc (cols * sizeof (int )); matrix[0 ][0 ] = 1 ; matrix[1 ][2 ] = 9 ; printf ("%d %d\n" , matrix[0 ][0 ], matrix[1 ][2 ]); for (int i = 0 ; i < rows; i++) free (matrix[i]); free (matrix); return 0 ; }
指针和结构体(复杂数据结构)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <stdio.h> #include <stdlib.h> typedef struct Node { int val; struct Node *next ; } Node;int main () { Node *head = malloc (sizeof (Node)); head->val = 10 ; head->next = malloc (sizeof (Node)); head->next->val = 20 ; head->next->next = NULL ; Node *p = head; while (p) { printf ("%d -> " , p->val); p = p->next; } printf ("NULL\n" ); free (head->next); free (head); return 0 ; }
字符串
定义方式
内存位置
是否可修改
特点
char str[] = "Hello";
栈
可修改
自动加 \0
char str[10] = "Hi";
栈
可修改
数组大小固定,未用空间填 \0
char str[] = {'H','e','l','l','o','\0'};
栈
可修改
手动控制每个字符
char *str = "Hello";
只读数据段
不可修改
指针指向字面量,节省内存
char str[] = ""; 或 char *str = "";
栈 / 只读数据段
可修改/不可修改
空字符串初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <stdio.h> int main () { char str1[] = "Hello" ; str1[0 ] = 'h' ; printf ("str1 = %s\n" , str1); char str2[10 ] = "Hi" ; str2[2 ] = '!' ; str2[3 ] = '\0' ; printf ("str2 = %s\n" , str2); char str3[] = {'H' , 'e' , 'l' , 'l' , 'o' , '\0' }; str3[0 ] = 'h' ; printf ("str3 = %s\n" , str3); char *str4 = "Hello" ; printf ("str4 = %s\n" , str4); char str5[1 ] = "" ; char *str6 = "" ; printf ("str5 = '%s', str6 = '%s'\n" , str5, str6); return 0 ; }
1 2 3 4 5 str1 = hello str2 = Hi! str3 = hello str4 = Hello str5 = '', str6 = ''
string.h 提供了操作字符串和内存块的常用函数,包括:
函数
功能
示例
strlen(s)
返回字符串长度(不包含 ‘\0’)
int len = strlen(str1);
strcpy(dest, src)
字符串复制
strcpy(dest, src);
strncpy(dest, src, n)
指定长度复制
strncpy(dest, src, 3);
strcat(dest, src)
字符串拼接
strcat(dest, "World");
strcmp(s1, s2)
比较两个字符串
strcmp("a","b") < 0
strncmp(s1, s2, n)
比较前 n 个字符
strncmp("abc","abd",2)
strchr(s, c)
查找字符首次出现
strchr("abc",'b')
strrchr(s, c)
查找字符最后出现
strrchr("abcb",'b')
strstr(s1, s2)
查找子串
strstr("HelloWorld","World")
memset(ptr, val, n)
内存填充
memset(arr, 0, sizeof(arr))
memcpy(dest, src, n)
内存拷贝
memcpy(dest, src, 5)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <stdio.h> #include <string.h> int main () { char str1[20 ] = "Hello" ; char str2[] = "World" ; char str3[20 ]; printf ("Length of str1: %lu\n" , strlen (str1)); strcpy (str3, str1); printf ("str3 = %s\n" , str3); strcat (str3, str2); printf ("After concatenation, str3 = %s\n" , str3); if (strcmp (str1, str2) < 0 ) { printf ("str1 < str2\n" ); } char *p = strchr (str3, 'o' ); if (p) { printf ("'o' appears at position: %ld\n" , p - str3); } memset (str3, '*' , 5 ); str3[5 ] = '\0' ; printf ("After memset, str3 = %s\n" , str3); return 0 ; }
1 2 3 4 5 6 Length of str1: 5 str3 = Hello After concatenation, str3 = HelloWorld str1 < str2 'o' appears at position: 4 After memset, str3 = *****
结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <stdio.h> #include <string.h> typedef struct { char name[50 ]; int age; float score; } Student;int main () { Student s1 = {"Alice" , 20 , 95.5 }; printf ("Name: %s\n" , s1.name); printf ("Age: %d\n" , s1.age); printf ("Score: %.2f\n" , s1.score); s1.age = 21 ; strcpy (s1.name, "Alice Zhang" ); printf ("Updated Name: %s, Age: %d\n" , s1.name, s1.age); Student class [2] = {{"Bob" , 22 , 88.0 }, {"Charlie" , 19 , 92.5 }}; for (int i = 0 ; i < 2 ; i++) { printf ("%s - %d - %.2f\n" , class[i].name, class[i].age, class[i].score); } return 0 ; }
1 2 3 4 5 6 Name: Alice Age: 20 Score: 95.50 Updated Name: Alice Zhang, Age: 21 Bob - 22 - 88.00 Charlie - 19 - 92.50
结构体指针
特性
说明
定义
Student *p = &s1;
访问成员
(*p).age 或 p->age
函数传递
用指针避免结构体拷贝
动态分配
malloc(sizeof(Student)) 分配结构体内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct { char name[50 ]; int age; float score; } Student;void printStudent (Student *p) { printf ("%s - %d - %.2f\n" , p->name, p->age, p->score); }int main () { Student s1 = {"Alice" , 20 , 95.5 }; Student *p = &s1; printf ("Name: %s, Age: %d\n" , p->name, p->age); p->score = 100.0 ; printStudent(p); Student *p2 = (Student *)malloc (sizeof (Student)); strcpy (p2->name, "Bob" ); p2->age = 22 ; p2->score = 88.0 ; printStudent(p2); free (p2); return 0 ; }
1 2 3 Name: Alice, Age: 20 Alice - 20 - 100.00 Bob - 22 - 88.00
共用体
共用体 是一种特殊的数据类型,它允许多个成员 共享同一块内存 。
同一时刻,union 只能存储其中一个成员的值 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <stdio.h> #include <string.h> union Data { int i; float f; char str[20 ]; };int main () { union Data data ; data.i = 10 ; printf ("data.i = %d\n" , data.i); data.f = 3.14 ; printf ("data.f = %.2f\n" , data.f); printf ("data.i = %d\n" , data.i); strcpy (data.str, "Hello" ); printf ("data.str = %s\n" , data.str); printf ("data.f = %.2f\n" , data.f); printf ("Size of union: %zu\n" , sizeof (data)); return 0 ; }
1 2 3 4 5 6 data.i = 10 data.f = 3.14 data.i = 1078523331 data.str = Hello data.f = 1143139122437582500000000000.00 Size of union: 20
位域
位域允许你在结构体 中指定 成员占用的位数 ,而不是整个字节或类型的大小。
用途:
节省内存(尤其是多个标志位、状态位等)
与硬件寄存器对应(嵌入式编程常用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <stdio.h> struct Flags { unsigned int flag1 : 1 ; unsigned int flag2 : 3 ; unsigned int flag3 : 4 ; };int main () { struct Flags f ; f.flag1 = 1 ; f.flag2 = 5 ; f.flag3 = 10 ; printf ("flag1 = %u\n" , f.flag1); printf ("flag2 = %u\n" , f.flag2); printf ("flag3 = %u\n" , f.flag3); return 0 ; }
1 2 3 flag1 = 1 flag2 = 5 flag3 = 10
typedef
给已有类型 取一个新的名字(别名)
使代码更清晰,尤其是在使用复杂类型(如结构体、函数指针、数组类型)时
不会创建新类型,只是给现有类型起一个别名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include <stdio.h> #include <string.h> typedef struct { char name[50 ]; int age; } Student;typedef int IntArray[5 ];typedef int (*Operation) (int , int ) ;int add (int a, int b) { return a + b; }int multiply (int a, int b) { return a * b; }int main () { Student s1; strcpy (s1.name, "Alice" ); s1.age = 20 ; printf ("%s - %d\n" , s1.name, s1.age); IntArray arr = {1 , 2 , 3 , 4 , 5 }; for (int i = 0 ; i < 5 ; i++) printf ("%d " , arr[i]); printf ("\n" ); Operation op = add; printf ("2 + 3 = %d\n" , op(2 , 3 )); op = multiply; printf ("2 * 3 = %d\n" , op(2 , 3 )); return 0 ; }
1 2 3 4 Alice - 20 1 2 3 4 5 2 + 3 = 5 2 * 3 = 6
文件
模式
含义
"r"
只读,文件必须存在
"w"
只写,文件不存在则创建,存在则清空
"a"
追加写,文件不存在则创建
"r+"
读写,文件必须存在
"w+"
读写,文件不存在则创建,存在则清空
"a+"
读写,文件不存在则创建,写入追加到末尾
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 #include <stdio.h> #include <stdlib.h> #include <string.h> #define FILENAME "example.txt" #define MAX_LINE 256 void write_file () { FILE *fp = fopen(FILENAME, "w" ); if (!fp) { perror("Failed to open file" ); return ; } fprintf (fp, "Alice, 20, 95\n" ); fprintf (fp, "Bob, 22, 88\n" ); fprintf (fp, "Charlie, 21, 92\n" ); fclose(fp); printf ("File written successfully.\n" ); }void read_file () { FILE *fp = fopen(FILENAME, "r" ); if (!fp) { printf ("File not found.\n" ); return ; } char line[MAX_LINE]; printf ("File content:\n" ); while (fgets(line, sizeof (line), fp)) { printf ("%s" , line); } fclose(fp); }void append_file (const char *text) { FILE *fp = fopen(FILENAME, "a" ); if (!fp) { perror("Failed to open file" ); return ; } fprintf (fp, "%s\n" , text); fclose(fp); printf ("Appended: %s\n" , text); }void modify_file (const char *keyword, const char *new_text) { FILE *fp = fopen(FILENAME, "r" ); if (!fp) return ; FILE *tmp = fopen("tmp.txt" , "w" ); char line[MAX_LINE]; int found = 0 ; while (fgets(line, sizeof (line), fp)) { if (strstr (line, keyword)) { fputs (new_text, tmp); fputc('\n' , tmp); found = 1 ; } else { fputs (line, tmp); } } fclose(fp); fclose(tmp); if (found) { remove(FILENAME); rename("tmp.txt" , FILENAME); printf ("Modified lines containing: %s\n" , keyword); } else { remove("tmp.txt" ); printf ("No line found containing: %s\n" , keyword); } }void delete_file () { if (remove(FILENAME) == 0 ) { printf ("File deleted successfully.\n" ); } else { perror("Failed to delete file" ); } }void find_in_file (const char *keyword) { FILE *fp = fopen(FILENAME, "r" ); if (!fp) { printf ("File not found.\n" ); return ; } char line[MAX_LINE]; int found = 0 ; printf ("Search results for \"%s\":\n" , keyword); while (fgets(line, sizeof (line), fp)) { if (strstr (line, keyword)) { printf ("%s" , line); found = 1 ; } } if (!found) printf ("No match found.\n" ); fclose(fp); }int main () { write_file(); read_file(); printf ("\n" ); append_file("David, 23, 85" ); read_file(); printf ("\n" ); modify_file("Bob" , "Bob, 22, 90" ); read_file(); printf ("\n" ); find_in_file("Charlie" ); printf ("\n" ); delete_file(); read_file(); return 0 ; }
操作
对应函数
创建/写
write_file() → fopen("w"), fprintf
读取
read_file() → fopen("r"), fgets
追加
append_file() → fopen("a"), fprintf
修改
modify_file() → 读入内存 → 修改 → 覆盖写
删除
delete_file() → remove()
查找
find_in_file() → fopen("r"), strstr
可变参数
可变参数 指函数的参数个数 不固定 ,调用时可以传任意数量的参数。
C 语言通过 <stdarg.h> 提供支持。
宏
作用
va_list
定义一个变量,用于存放参数列表信息
va_start(ap, last_fixed)
初始化 ap,last_fixed 是最后一个固定参数
va_arg(ap, type)
获取参数列表中的下一个参数,指定类型 type
va_end(ap)
清理 ap,完成后必须调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <stdio.h> #include <stdarg.h> int sum (int count, ...) { int total = 0 ; va_list args; va_start(args, count); for (int i = 0 ; i < count; i++) { int value = va_arg(args, int ); total += value; } va_end(args); return total; }int main () { printf ("sum(1, 2, 3) = %d\n" , sum(3 , 1 , 2 , 3 )); printf ("sum(5, 1, 2, 3, 4, 5) = %d\n" , sum(5 , 1 , 2 , 3 , 4 , 5 )); return 0 ; }
1 2 sum(1, 2, 3) = 6 sum(5, 1, 2, 3, 4, 5) = 15
动态内存管理
函数
初始化
返回类型
是否可改变大小
说明
malloc
不初始化
void*
否
分配指定字节内存
calloc
初始化为 0
void*
否
分配 num*size 字节内存
realloc
保留原内容
void*
是
改变已分配内存大小
free
-
-
-
释放动态内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 #include <stdio.h> #include <stdlib.h> int main () { int *arr1 = (int *)malloc (5 * sizeof (int )); if (!arr1) { perror("malloc failed" ); return 1 ; } printf ("Contents of memory allocated by malloc (uninitialized, may contain garbage values):\n" ); for (int i = 0 ; i < 5 ; i++) printf ("%d " , arr1[i]); printf ("\n" ); int *arr2 = (int *)calloc (5 , sizeof (int )); if (!arr2) { perror("calloc failed" ); return 1 ; } printf ("Contents of memory allocated by calloc (initialized to 0):\n" ); for (int i = 0 ; i < 5 ; i++) printf ("%d " , arr2[i]); printf ("\n" ); for (int i = 0 ; i < 5 ; i++) arr2[i] = i + 1 ; arr2 = (int *)realloc (arr2, 8 * sizeof (int )); if (!arr2) { perror("realloc failed" ); return 1 ; } for (int i = 5 ; i < 8 ; i++) arr2[i] = i + 1 ; printf ("Contents of memory after realloc:\n" ); for (int i = 0 ; i < 8 ; i++) printf ("%d " , arr2[i]); printf ("\n" ); free (arr1); free (arr2); arr1 = NULL ; arr2 = NULL ; printf ("Memory has been freed.\n" ); return 0 ; }
1 2 3 4 5 6 7 Contents of memory allocated by malloc (uninitialized, may contain garbage values): 12398976 12393768 0 0 0 Contents of memory allocated by calloc (initialized to 0): 0 0 0 0 0 Contents of memory after realloc: 1 2 3 4 5 6 7 8 Memory has been freed.
命令行参数
argc (argument count) : 表示命令行参数的数量,包括程序名本身。因此,argc 至少为 1。
argv (argument vector) : 是一个指向字符串数组的指针,其中每个字符串是一个命令行参数。数组的第一个元素(即 argv[0])通常是程序的名称。接下来的元素是传递给程序的命令行参数。
1 2 3 4 5 6 7 8 9 #include <stdio.h> int main (int argc, char *argv[]) { printf ("Number of arguments: %d\n" , argc); for (int i = 0 ; i < argc; i++) { printf ("argv[%d] = %s\n" , i, argv[i]); } return 0 ; }
标准库
头文件
功能简介
<stdio.h>
标准输入输出库,包含 printf、scanf、fgets、fputs 等函数。
<stdlib.h>
标准库函数,包含内存分配、程序控制、转换函数等,如 malloc、free、exit、atoi、rand 等。
<string.h>
字符串操作函数,如 strlen、strcpy、strcat、strcmp 等。
<math.h>
数学函数库,包含各种数学运算函数,如 sin、cos、tan、exp、log、sqrt 等。
<time.h>
时间和日期函数,如 time、clock、difftime、strftime 等。
<ctype.h>
字符处理函数,如 isalpha、isdigit、isspace、toupper、tolower 等。
<limits.h>
定义各种类型的限制值,如 INT_MAX、CHAR_MIN、LONG_MAX 等。
<float.h>
定义浮点类型的限制值,如 FLT_MAX、DBL_MIN 等。
<assert.h>
包含宏 assert,用于在调试时进行断言检查。
<errno.h>
定义了错误码变量 errno 及相关宏,用于表示和处理错误。
<stddef.h>
定义了一些通用类型和宏,如 size_t、ptrdiff_t、NULL 等。
<signal.h>
定义了处理信号的函数和宏,如 signal、raise 等。
<setjmp.h>
提供非本地跳转功能的宏和函数,如 setjmp、longjmp 等。
<locale.h>
定义了与地域化相关的函数和宏,如 setlocale、localeconv 等。
<stdarg.h>
提供处理可变参数函数的宏,如 va_start、va_arg、va_end 等。
<stdbool.h>
定义布尔类型和值 true 和 false。
<stdint.h>
定义了精确宽度的整数类型,如 int8_t、uint16_t 等。
<inttypes.h>
提供与整数类型相关的格式化输出宏和函数。
<complex.h>
提供复数运算的函数和宏,如 cabs、carg 等。
<tgmath.h>
为泛型数学函数提供宏,以简化对不同类型数据的数学运算。
<fenv.h>
提供对浮点环境的控制,如舍入模式和异常状态。
C++
数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <iostream> #include <limits> int main () { std::cout << "bool: " << std::numeric_limits<bool >::min () << " to " << std::numeric_limits<bool >::max () << "\n" ; std::cout << "char: " << int (std::numeric_limits<char >::min ()) << " to " << int (std::numeric_limits<char >::max ()) << "\n" ; std::cout << "unsigned char: " << int (std::numeric_limits<unsigned char >::min ()) << " to " << int (std::numeric_limits<unsigned char >::max ()) << "\n" ; std::cout << "short: " << std::numeric_limits<short >::min () << " to " << std::numeric_limits<short >::max () << "\n" ; std::cout << "unsigned short: " << std::numeric_limits<unsigned short >::min () << " to " << std::numeric_limits<unsigned short >::max () << "\n" ; std::cout << "int: " << std::numeric_limits<int >::min () << " to " << std::numeric_limits<int >::max () << "\n" ; std::cout << "unsigned int: " << std::numeric_limits<unsigned int >::min () << " to " << std::numeric_limits<unsigned int >::max () << "\n" ; std::cout << "long long: " << std::numeric_limits<long long >::min () << " to " << std::numeric_limits<long long >::max () << "\n" ; std::cout << "unsigned long long: " << std::numeric_limits<unsigned long long >::min () << " to " << std::numeric_limits<unsigned long long >::max () << "\n" ; std::cout << "float: " << std::numeric_limits<float >::min () << " to " << std::numeric_limits<float >::max () << "\n" ; std::cout << "double: " << std::numeric_limits<double >::min () << " to " << std::numeric_limits<double >::max () << "\n" ; std::cout << "wchar_t: " << std::numeric_limits<wchar_t >::min () << " to " << std::numeric_limits<wchar_t >::max () << "\n" ; return 0 ; }
wchar_t 也是 C++ 的基本字符类型之一,用于表示宽字符 ,可以存储 Unicode 字符。常用于需要支持多语言字符的场景,比如中文、日文等。
1 2 3 4 5 6 7 8 9 10 11 12 bool: 0 to 1 char: -128 to 127 unsigned char: 0 to 255 short: -32768 to 32767 unsigned short: 0 to 65535 int: -2147483648 to 2147483647 unsigned int: 0 to 4294967295 long long: -9223372036854775808 to 9223372036854775807 unsigned long long: 0 to 18446744073709551615 float: 1.17549e-038 to 3.40282e+038 double: 2.22507e-308 to 1.79769e+308 wchar_t: 0 to 65535
字符串
C++ 标准库提供了 std::string ,是一个类 ,封装了字符数组和常用操作。
特性
C 字符串
C++ 字符串
类型
char[] 或 char*
std::string
结尾标志
\0
内部管理,不依赖 \0
内存管理
手动
自动
拼接
strcat()
+ 操作符
长度获取
strlen()
.length() 或 .size()
比较
strcmp()
==, != 等
安全性
易溢出
更安全,异常安全
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <iostream> #include <string> int main () { std::string str1 = "Hello" ; std::string str2 = "World" ; std::string str3 = str1 + " " + str2; std::cout << "Length: " << str3.l ength() << std::endl; for (size_t i = 0 ; i < str3.l ength(); i++) { std::cout << str3[i] << " " ; } std::cout << std::endl; if (str1 != str2) { std::cout << str1 << " and " << str2 << " are different" << std::endl; } return 0 ; }
1 2 3 Length: 11 H e l l o W o r l d Hello and World are different
引用
引用是一种 别名机制 ,即给已有变量取一个别名。
1 2 3 4 5 6 7 8 9 10 #include <iostream> void addOne (int &x) { x += 1 ; }int main () { int a = 5 ; addOne (a); std::cout << a << std::endl; }
Vector
vector 是 C++ 标准模板库(STL)提供的 动态数组容器 ,属于 顺序容器 。
它的特点是:
动态大小 :可以根据需要自动增长或缩小,不需要像普通数组一样预先指定长度。
连续内存存储 :和数组类似,支持通过下标访问元素,访问速度快。
提供丰富接口 :支持插入、删除、查找、排序等操作。
类型安全 :vector 是模板类,存储特定类型的元素。
功能
Python list
C++ vector
动态大小
可以随时增加或删除元素
push_back()、pop_back() 等操作
下标访问
lst[i]
v[i] 或 v.at(i)
遍历
for x in lst:
for (auto x : v)
末尾添加
append()
push_back()
删除元素
pop() / remove()
pop_back() / erase()
支持任意类型
可以存对象
模板类型,例如 vector<int>、vector<string>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <iostream> #include <vector> using namespace std;int main () { vector<int > v; v.push_back (10 ); v.push_back (20 ); v.push_back (30 ); for (auto x : v) cout << x << " " ; cout << endl; v.pop_back (); v.insert (v.begin () + 1 , 15 ); for (auto x : v) cout << x << " " ; cout << endl; return 0 ; }
面向对象
C++ 是多范式语言 ,支持 面向对象编程 ,OOP 的核心理念是将数据和操作封装在“对象”中。
特性
描述
示例
封装(Encapsulation)
将数据(成员变量)和操作(成员函数)封装在类里,并通过访问控制保护数据
private、public
继承(Inheritance)
新的类可以继承已有类的属性和方法,实现代码重用
class 子类 : public 父类
多态(Polymorphism)
同一个接口可以有不同实现(运行时多态通常通过虚函数实现)
virtual + 覆盖函数
封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <iostream> #include <string> using namespace std;class Person {private : string name; int age;public : Person (string n, int a) : name (n), age (a) {} void introduce () { cout << "我是 " << name << ",今年 " << age << " 岁。" << endl; } void setAge (int a) { if (a >= 0 ) age = a; } int getAge () { return age; } };int main () { Person p1 ("Alice" , 20 ) ; p1. introduce (); p1. setAge (21 ); cout << "修改年龄后: " << p1. getAge () << endl; return 0 ; }
继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Student : public Person { private : string school;public : Student (string n, int a, string s) : Person (n, a), school (s) {} void showSchool () { cout << "学校: " << school << endl; } };int main () { Student s1 ("Bob" , 18 , "清华大学" ) ; s1. introduce (); s1. showSchool (); }
多态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Animal {public : virtual void sound () { cout << "动物叫声" << endl; } };class Dog : public Animal {public : void sound () override { cout << "汪汪汪" << endl; } };class Cat : public Animal {public : void sound () override { cout << "喵喵喵" << endl; } };void makeSound (Animal* a) { a->sound (); }int main () { Dog dog; Cat cat; makeSound (&dog); makeSound (&cat); }
重载
函数重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> using namespace std;int add (int a, int b) { return a + b; }double add (double a, double b) { return a + b; }int add (int a, int b, int c) { return a + b + c; }int main () { cout << add (1 , 2 ) << endl; cout << add (1.5 , 2.3 ) << endl; cout << add (1 , 2 , 3 ) << endl; }
运算符重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <iostream> using namespace std;class Point {public : int x, y; Point (int a=0 , int b=0 ) : x (a), y (b) {} Point operator +(const Point& p) { return Point (x + p.x, y + p.y); } void show () { cout << "(" << x << "," << y << ")" << endl; } };int main () { Point p1 (1 , 2 ) ; Point p2 (3 , 4 ) ; Point p3 = p1 + p2; p3. show (); }
异常处理
C 语言 没有 try 和 catch ,也就是说 C 语言没有内置的异常处理机制,这是 C++ 引入的一部分特性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <iostream> #include <stdexcept> using namespace std;double divide (double a, double b) { if (b == 0 ) throw runtime_error ("Division by zero" ); return a / b; }int main () { try { cout << divide (10 , 2 ) << endl; cout << divide (10 , 0 ) << endl; } catch (const exception &e) { cout << "Caught exception: " << e.what () << endl; } cout << "Program continues execution" << endl; return 0 ; }
1 2 3 5 Caught exception: Division by zero Program continues execution
动态内存
特性
malloc ©
new (C++)
类型安全
否,需要强制转换
是,不需要转换
构造函数/析构函数
不调用
调用
内存释放
free
delete / delete[]
失败处理
返回 NULL
抛出异常 bad_alloc
可重载
否
是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <iostream> #include <cstdlib> using namespace std;class MyClass {public : MyClass () { cout << "Constructor called" << endl; } ~MyClass () { cout << "Destructor called" << endl; } void sayHello () { cout << "Hello from MyClass" << endl; } };int main () { cout << "=== Using malloc ===" << endl; MyClass *obj1 = (MyClass *)malloc (sizeof (MyClass)); free (obj1); cout << "\n=== Using new ===" << endl; MyClass *obj2 = new MyClass (); obj2->sayHello (); delete obj2; return 0 ; }
1 2 3 4 5 6 === Using malloc === === Using new === Constructor called Hello from MyClass Destructor called
命名空间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <iostream> namespace A { int x = 5 ; }namespace B { int x = 10 ; }int main () { std::cout << A::x << std::endl; std::cout << B::x << std::endl; }
模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <iostream> using namespace std;template <typename T>T add (T a, T b) { return a + b; }int main () { cout << add (10 , 20 ) << endl; cout << add (1.5 , 2.3 ) << endl; return 0 ; }
标准库
类别
头文件
简介
输入输出
<iostream>
标准输入输出流
<fstream>
文件输入输出流
<sstream>
字符串流
<iomanip>
输入输出流格式化
容器
<array>
定长数组容器
<vector>
动态数组容器
<deque>
双端队列容器
<list>
双向链表容器
<forward_list>
单向链表容器
<stack>
栈容器适配器
<queue>
队列容器适配器
<priority_queue>
优先队列容器适配器
<set>
集合容器(基于平衡二叉树)
<unordered_set>
无序集合容器(基于哈希表)
<map>
映射容器(键值对,基于平衡二叉树)
<unordered_map>
无序映射容器(基于哈希表)
<bitset>
二进制位容器
算法与迭代器
<algorithm>
常用算法(排序、查找等)
<iterator>
迭代器
函数对象与绑定
<functional>
定义函数对象及相关工具
数学与数值运算
<numeric>
数值操作(累计、乘积等)
<complex>
复数运算
<valarray>
数组类及相关操作
<cmath>
数学函数
字符串与正则
<string>
标准字符串类
<regex>
正则表达式
时间与日期
<ctime>
时间处理
<chrono>
时间库
多线程与并发
<thread>
多线程支持
<mutex>
互斥量
<condition_variable>
条件变量
<future>
异步编程支持
<atomic>
原子操作
内存管理
<memory>
智能指针及动态内存管理
<new>
动态内存分配
类型特性与 RTTI
<type_traits>
类型特性
<typeinfo>
运行时类型识别
异常处理
<exception>
异常处理基类及相关工具
<stdexcept>
常用异常类(如 std::runtime_error)
C 风格输入输出
<cstdio>
C 风格输入输出
其他工具
<cstdint>
定长整数类型
<utility>
通用工具(如 std::pair、std::move)
<random>
随机数生成
<locale>
本地化支持
<codecvt>
字符编码转换
<cassert>
断言
<cctype>
字符处理
<cstring>
字符串处理
<cwchar>
宽字符处理
<climits>
数值极限
<cfloat>
浮点极限
<cstdlib>
常用工具(如 std::rand、std::abs)