跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

C++ 基础教程:从 Hello World 到变量类型

C++ 基础教程涵盖 Hello World 程序结构、main 函数定义、注释规范、语句声明、函数作用域及参数传递、基础数据类型(整型、字符型、浮点型)及其内存表示。内容涉及命名空间、变量初始化、特殊字符转义及常见编译错误处理,适合有一定编程基础的学习者快速掌握 C++ 核心语法概念。

无尘发布于 2026/3/15更新于 2026/10/17101 浏览
C++ 基础教程:从 Hello World 到变量类型

C++ 基础教程

本教程并非零基础新手教程,但有一定基础的新手可以参考。虽然直接选择章节阅读是一种高效的方法,但如果前面说过的内容后面不再细讲,建议通篇大致浏览。

阅读需求

  1. 懂得如何编译运行 C++ 代码,了解变量命名规范及基础语法。
  2. 明白代码中不要乱用全角字符,例如中文括号。
  3. 保持学习的热情。

大的功能向下拆分,直到形成最小单元,再逐个实现。

第一个程序 Hello, world!

打开代码编辑器输入:

#include <iostream> // 导入头文件
int main(void) { // 主函数
    using namespace std; // 使用命名空间
    cout << "Hello, world!" << endl; // 输出内容和空行
    return 0;
}

一个 C++ 程序必须有 main 函数,否则会报错 Undefined symbol: _main。#include <iostream> 是可选的,一个 C++ 程序可以只有 main 函数,但是 std 命名空间(namespace)就不能使用了,它在 iostream 这个头文件里面。

关于头文件,在 C 语言中,头文件会写上扩展名,例如 stdio.h, string.h 等。但是在 C++ 中,头文件的扩展名被省略了。在古老的 C++ 版本中,例如一个 1987 年的 C++ 编译器,里面使用 iostream.h,也就是旧式 C++。来自 C 语言的头文件(转换后的 C)前面会加个 c,例如来自 C 语言的 math.h 在 C++ 中变成了 cmath。C++ 新式风格是没有头文件扩展名了。

C 中头文件扩展名五花八门,有 hxx、hpp,或者 h,最后 ANSI/ISO 委员会觉得太乱套了,最后一致同意不使用任何扩展名。

main 函数

main 函数又叫做主函数。int main(void) {xxx; return 0;} 是 main() 函数,其中 int main(void) 叫做函数头,后面的 {xxx; return 0;} 叫做函数体。

int(数据类型)表示 main 函数的返回类型是整数类型 (integer),return 0; 表示函数的返回值是 0。(void) 表明函数不接受任何参数,括号中写的是函数接受的参数,void 在英文中的解释是'空的'、'空白的'。

如果想让函数接受浮点数(数据类型叫做 float,可以理解为小数,因计算机中处理浮点数的方式得名'浮点'),并且函数的名字叫做 fun,接受的参数是一个整数类型 int,参数的名字叫做 num,返回值是 1,代码如下:

// 你可能会尝试把这个代码直接编译,奇怪为什么会报错,先别急,C++ 程序是有结构的。
float fun{
     ;
}
(int num)
return
1.0

再举两个例子:

int fun2(int num2){
    return 0;
}
int fff(){ // 括号内可以留空,同样表示不接受参数(注意是不接受参数,不是忽略参数)。
    return 0;
}

C++ 11 新标准:

int f2r() = delete;

这是显式表示不定义参数,表示禁止调用该函数。

C++ 注释

用两个斜线,后面一个空格表示注释。双斜线后面的代码都不会被执行,直到换行。

例如下面的程序:

int plus(int a, int b) {
    // 双斜线后面的内容不会被执行
    a=a+1;
    // a=1;
    // b=2;
    return a+b;
}

第一行 (int a, int b) 表示这个函数接受两个参数,注意看这两个参数中间用逗号连接。

注释可以用来标记解释代码中的功能,写程序要养成写注释的好习惯,免得你以后看自己以前的代码,或者在公司里你的同事看你的代码一头雾水。

第三行 a=a+1 是一个'赋值运算'。对,它是一种运算。这句代码的等号就是赋值运算符,在赋值运算中,优先计算赋值运算符右侧的内容,也就是 a+1,然后轮到左侧,a 增大 1 的结果被赋值给 a 本身,所以 a 的值被增大 1。例如调用函数(函数英文叫做 function,我在下面简单介绍)的时候

函数(function),function 在英文中是功能的意思,也就是函数可以实现一个功能。一个很推荐的程序设计思想叫做'模块化'、'结构化编程',大的功能向下拆分,直到形成最小单元,再逐个实现。

上面展示的函数的作用和它的名字一样,'加'(plus)。调用函数的时候给函数塞两个整数参数进去,它就能返回相加的结果。

int result; // 存储运算结果
result = plus(1, 2); // 调用 plus 函数

result 的结果会是 3。

还记得小学学的字母表示数吗?你还可以这样调用:

int a=1;
int b=2; // 或者这样写:int a = 1, b = 2;
result = plus(a, b);

更多内容在函数章节细讲。

C++ 语句

C++ 有很多种语句,函数也是语句,前面还说过赋值语句,下面说一下声明变量。

变量是给一块内存空间取的名字,用来存储和操作数据。这块空间有多大和变量类型有关,不同操作系统不同编译器上变量类型占用空间可能有差别。MS-DOS Turbo C++ 3.0 上的 char 是 1 字节(byte)。1Byte=1/1024KB,B, KB, MB, GB, TB 都是这个换算规律。

举例几个合规的变量名:使用有意义的、以小写字母开头的单词组合,单词间可用下划线分隔或驼峰式命名,避免使用保留关键字(例如 int、char、void 和 return 等)和数字开头。关键字是 C++ 专用的词语,不能用做其他用途,你不能把 int 作为函数名,也不能把 void 作为变量名。

  • 蛇形命名法:user_name、total_count
  • 驼峰命名法:userName、totalCount
  • 常量:MAX_SIZE
  • 类名:ClassName

变量要有类型,没有一个默认的数据,程序只会给它分配一个空闲的数据块,但是不保证里面是空的,可能有其他程序或者内容留下的垃圾内容,所以你在读取它之前应该赋值,或者给它一个默认值。给予默认值的操作叫做'初始化'。在 C++ 中变量在使用之前需要先声明,其他语言例如 Python 不需要这样做,使用前需要先声明这个机制好就好在你不会因为笔误不小心造一个变量出来,而且自己还看不出来,例如下面的 BASIC 代码:

CastleDark =34
CastleDank = CasleDark + MoreGhosts
PRINT CastleDark

上面的代码意图是把值为 34 的变量 CastleDark 增加 MoreGhosts,然后输出 MoreGhosts 的数值。然而第二行不小心写错个字母,一眼看上去还看不出来,这样 CastleDark 的值永远是 34。

实际第二行做的工作是新建个变量 CastleDank,给它加上 MoreGhosts。CastleDark 的值还是 34,没有被修改。

看下面代码演示变量相关操作。

int a; // 声明变量
int b = 0; // 声明变量的同时初始化为 0;

如果你想知道不初始化直接读取变量会发生什么,请看下面程序:

# include <iostream>
int main(void){
    int a;
    std::cout << a << std::endl;
    return 0;
}

在 macOS 系统上,使用 Xcode 集成开发环境和 Apple clang 编译器,得到的结果如下:

-278069152 Program ended with exit code: 0

可以看出这确实是个杂乱无章的数值。

函数

函数用于创建 C++ 程序的模块,与面向对象编程有关,高级内容后面细说。

函数接受和传入返回值的方法前面'C++ 注释'章节已经说过了一些,下面再用例子演示函数多个参数的传入:

#include <iostream> // 函数头
int plus(int a, int b, int c); // 此为函数头,也可以简写为 int plus(int, int, int);
// 主函数
int main(void){
    int result;
    int num1 = 2;
    int num2 = 3;
    int num3 = 6;
    result = plus(num1, num2, num3);
    std::cout << "Result: " << result << std::endl; // 双引号中间的部分是字符串,可以试试自己修改成别的。
    return 0; // 结束 main() 函数,返回值为 0,但实际上现代 C++ 中可以省略。
} // 函数定义
int plus(int a, int b, int c){
    return a+b+c;
}

运行结果:

Result: 11 Program ended with exit code: 0

如果你在主函数(main 函数)里面加上 using namespace std; 代码会报错,因为 std 名称空间中有同名的、也叫 plus 的内容,这引起了冲突。如果非要使用这个代码,就要把 plus 函数换个别的名字,例如 plus1。

第二个例子:

#include <iostream> // 显示文字
void print(std::string); // string 是字符串类型,两个冒号不需要纠结,以后详细说,只需要知道 string 属于 std 命名空间。
// 重复字符串的内容
std::string duplicate(std::string); // 重复字符串并打印
void dup_and_print(std::string);
int main(int argc, char* argv[]){
    using namespace std;
    string str1 = "Hello"; // string 前面不需要 std::是因为前面前面引入了 std 命名空间
    str1 = duplicate(str1); // 重复 str1
    dup_and_print(str1); // 重复 str1 并向命令行输出文本
}
void print(std::string str){
    // using namespace std;
    // 把这行的注释去掉以后,下面的 std:: 就可以去掉了。
    // 不使用 using namespace std; 就要使用 std::cout,因为你要手动指定自己在使用这个命名空间中的 cout。
    std::cout << str << std::endl;
    return; // 什么也不返回,只是结束函数,你也可以省略这一行
}
std::string duplicate(std::string str){
    return str + str; // 把两个字符串连接起来
}
void dup_and_print(std::string strrr){
    using namespace std; // 函数中可以调用别的函数,层层组合,一个函数指挥多个函数协同运作,成为更强大的顶层的函数。
    strrr = duplicate(strrr);
    cout << strrr << endl;
}

运行结果:

HelloHelloHelloHello Program ended with exit code: 0

你可能会疑惑,上面的代码中为什么多个地方在使用 str 这个名字,这样是否会导致冲突?

其实并不会,C 和 C++ 有'作用域'的概念,作用域就是程序中变量/标识符的有效区域,决定了在哪里可以访问它。下面用几个例子讲解:

局部作用域(函数内):

void func() {
    int x = 10; // x 只在 func 内有效
    // x 可以在这里使用
}
// x 在这里不可访问

块作用域:

{
    int y = 20; // y 只在这个{}内有效
}
// y 在这里不可访问
if (true) {
    int z = 30; // 块作用域
}

如果你把变量/标识符放在任何块和局部作用域外面,那就是全局变量:

#include <iostream>
int a = 3; // a 在全局作用域
void visiablefunc(int b); // 同样,这个函数的位置也在全局作用域,任何地方都可见
int main(void){
    int c = 2;
    std::cout << a; // a 在任何地方都可见
    visiablefunc(a);
}
void visiablefunc(int b){
    std::cout << a; // std::cout << c; // 这会导致报错,因为 c 只在 main 函数里面可见。
}

命名空间作用域:

#include <iostream>
namespace myspace {
    // 自定义一个命名空间
    // 函数只在这个命名空间内可见
    int plus(int a, int b, int c){
        return a+b+c;
    }
}
int main(void){
    using namespace std;
    int result;
    int num1 = 2;
    int num2 = 3;
    int num3 = 6;
    // plus 函数的返回值被赋值给 result
    result = myspace::plus(num1, num2, num3); // 用 myspace::来访问 plus 函数
    cout << "Result: " << result << endl;
    return 0;
}

using namespace std; 引入了命名空间 std,如果直接使用 plus,程序会报错 No viable constructor or deduction guide for deduction of template arguments of 'plus',因为 std 中有叫做 plus 的东西了,准确说这个'东西'是函数对象类,它是这么用的 std::plus<int> add;,虽然不是个函数,却占用了 plus 这个名字。这时候名称空间就发挥了作用,我们自己定义的 plus 是个函数,被我们放在 mysapce 命名空间里面,我们使用的时候用 myspace::plus(xxx) 就能调用 plus 函数,而且不引起冲突,因为 myspace 里面只有一个叫做 plus 的东西。

基础变量

前面简单提过一点变量(Variable)的事情,它被分配到内存上的一块空间,我们使用变量名来向这块空间中存储数据,或者读取其中的数据。

在实际项目中变量名最好用有意义的名字,尽量不要用 a、var1、ffff 这种名字,result 甚至 jie_guo 都好很多,配合上注释,能快速清晰的了解程序。

整数类型、字符类型

整数类型有 short, int, long, long long 四种,int 适合多数情况的数字存储。C++ 确保这些类型的最小长度,short 至少 16 位,int 至少和 short 一样长,long 至少 32 位,至少与 int 一样长,long long 至少 64 位,至少与 long 一样长。

字符类型是 char,可以存储一个 ASCII 字符,ASCII 字符都有什么可以自己上网查询,里面包括字母、常见特殊符号。

整数类型和字符类型的运用示例代码如下:

#include <iostream>
#include <stdio.h> // 使用 printf() 需要引入这个头文件
int main(void){
    char ch = 'a'; // 存储一个字符
    char ch2 = 'b'; // 下面这个字符串在数组中实际的内容其实是'H' 'e' 'l' 'l' 'o' '\0'
    // 它之所以需要 6 个字符的空间是因为字符串"Hello"的结尾还有一个空字符'\0'
    char str[6] = "Hello"; // 通过声明一个字符数组来存储字符串
    int number1 = 8;
    int num2 = 6;
    std::cout << "ch: " << ch << ", ch2:" << ch2 << std::endl;
    std::cout << str << std::endl;
    std::cout << "8+6=" << number1 + num2 << std::endl;
    std::cout << "8-6=" << number1 - num2 << std::endl;
    // char str[6] 是 C 语言风格声明字符串,在 C++ 中这样的字符串可以直接赋值给 std 命名空间中的 string 类型。
    std::string str2 = str;
    std::cout << "str1: " << str << ", str2: " << str2 << std::endl;
    printf("str1: %s, str2: %s \n", str, str2.c_str()); // 如果你是从 C 语言来的,或者喜欢直观一点,可以试试这个。
    // %s 是字符串的占位符,函数执行的时候会按顺序替换成你后面用逗号分隔开的字符串变量,\n 是换行符。
    // printf 是 C 语言的东西,str2 是 C++ 中的 std::string 类型,C 语言的 printf 不认识,所以要用 str2.c_str() 转成 C 风格字符串
    // printf 是 print format 的缩写,占位符除了字符串占位符%s,还有%d, %c 等,更多内容可以自己查询。
}

不管是整数类型还是浮点类型、字符类型(char),都有一个最大值,我们可以查看一些符号常量来得知。看下面代码:

#include <iostream>
void show(int);
void show_l(long long); // 注意是 (long long),不是 (long, long),long long 是一个整体,类型。
int main(void){
    show(CHAR_BIT); // char 字符的位数
    show(CHAR_MAX); // char 字符的最大值
    show(CHAR_MIN); // MAX 是最大值,MIN 是最小值,下面内容也是如此。
    show(SCHAR_MAX); // signed char 有符号字符
    show(SCHAR_MIN);
    show(UCHAR_MAX); // usigned char 无符号字符
    show(SHRT_MAX); // short 短整数
    show(SHRT_MIN);
    show(USHRT_MAX); // unsigned short 无符号短整数
    show(INT_MAX); // int 整数
    show(INT_MIN); // 从 UINT_MAX 开始,数字就很大,超出了 int 的存储范围,所以我用了第二个函数。
    show_l(UINT_MAX); // unsigned int 无符号整数
    show_l(LONG_MAX); // long 长整数
    show_l(LONG_MIN);
    show_l(ULONG_MAX); // unsigned long 无符号长整数(32bit)
    show_l(LLONG_MAX); // long long 64 位的长整数
    show_l(LLONG_MIN);
    show_l(ULLONG_MAX); // unsigned long long 无符号长长整数
}
void show(int size){
    std::cout << size << std::endl;
}
void show_l(long long size){
    std::cout << size << std::endl;
}

变量的位数是有最大限度的,它总共就那么长,想表示正负数就肯定损失最大值,例如 short 类型范围可能(不同编译器和操作系统上可能有区别)是 -32767 到 +32767,无符号的 short 就能表示 0 到 65535,想让变量无符号,只需要在前面加个 unsigned.

变量不初始化(赋值),数值是不确定的,这个前面代码演示过。

char 不光能存储字符,还能存储数字,或者说 char 在存储字符的时候本来就是存储了一个字符对应的 ASCII 或者 UTF8 码。例如你要存储 256 色图像,就可以声明一个 unsigned char 类型的数组(Array,有顺序的存储一个或多个同一个类型的数据)来存储图像。

有些字符不是显示出来的,而是起到辅助作用的,例如换行符号,下面代码演示了换行符的作用:

#include <iostream>
int main(void){
    std::cout << "Hello\nworld!" << std::endl;
    std::cout << "\'Hello world!\'" << std::endl;
    std::cout << "\"Hello world!\"" << std::endl;
}

程序输出结果如下:

Hello world!
'Hello world!'
"Hello world!"
Program ended with exit code: 0

换行符几乎是最常用的符号之一,振铃 BEL 在现在的设备上不一定有用,如果你用的是一些 Linux 发行版的默认虚拟终端或者 macOS 系统虚拟终端,在执行程序的时候通常可以听到提示音或者窗口闪烁。问号一般不需要转义,直接用就行,反斜杠、单引号、双引号都有特殊的作用,转义符号、包装字符、包装字符串,所以如果你想把这些字符显示出来,就需要转义它们。

上面代码可以看到换行符号、转义后的单双引号发挥了作用,下表列举了一些特殊符号的 ASCII 符号、十六进制 ASCII 码对应关系:

Char nameASCII characterC++ codeHEX ASCII code
换行符NL(LF)\n0xA
水平制表符HT\t0x9
垂直制表符VT\v0xB
退格BS\b0x8
回车CR\r0xD
振铃BEL\a0x7
反斜杠\\0x5C
问号??0x3F
单引号''0x27
双引号""0x22
浮点数类型

C++ 总共两种浮点数表示方法,一种是普通的小数表示法,另一种是中学学过的科学计数法。

12.12 // 双 12 快到了
273.15
5.0 // 科学计数法
1.23E2 // 1.23 * 10^2(1.23 乘以 10 的 2 次幂)
1E5 // 1 * 10^5
1.0E+5 // 1.0 * 10^5
+1.89E-6

科学计数法:数字开头可以正号负号或者省略,E 后面是 10 的几次方,E 的前后都没有空格,E 的后面的数字可以有正号、负号或者省略(等同于正号)。

物理学上也经常使用科学计数法,例如电子质量是 9.11e-31kg,物理学上写作 9.11 * 10^31(我写公式要启用 LaTeX 支持,所以直接用计算器的风格写了,应该能看懂)。

复合类型

目录

  1. C++ 基础教程
  2. 阅读需求
  3. 第一个程序 Hello, world!
  4. main 函数
  5. C++ 注释
  6. C++ 语句
  7. include <iostream>
  8. 函数
  9. 基础变量
  10. 整数类型、字符类型
  11. 浮点数类型
  12. 复合类型

更多推荐文章

查看全部
  • Meta-Llama-3-8B-Instruct 部署常见问题与解决方案
  • Django Web 框架实战:从零构建产品管理系统
  • AIGC 时代 C++ 吞吐量优化技巧与性能提升实践
  • 大模型工程师的招聘现状与学习建议
  • 腾讯混元 7B 开源:256K 上下文与数学推理升级
  • PCL 点云处理算法与函数汇总
  • 网络安全入门学习指南:分支、路线与方法
  • 2025 年 AI 转型进展洞察:全面解析与未来展望
  • 基于Python的高性能JSON结构化编辑器架构详解
  • 无人机“黑飞”正式入法:2026 年 1 月 1 日起违规飞行将面临拘留
  • Java 中 Double 类型精度丢失原理与示例
  • Java 常见集合框架核心解析与选型指南
  • Buzz 离线语音转文字工具安装与使用(支持 Whisper 模型)
  • Python Literal 类型注解详解
  • PostgreSQL 结合 cpolar 实现无公网 IP 远程访问
  • FPGA 基础与架构面试题详解(一)
  • GitHub 推送报错?用 SSH 密钥替代密码认证方案
  • Linux 下 Java JNI 调用 .so 文件的方法
  • 基于 OpenClaw 与 Claude 的自动化写作工作流搭建
  • 移动端高颜值登录页实战:动态背景与仿幕布风格

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online