1. 引言
C语言与C++是两门关系极为密切的编程语言。C++在C语言的基础上发展而来,最初被称为"带类的C",因此两者在基础语法上有大量相似之处。然而,C++在语法层面引入了许多新特性,使得两者在编写方式和编程思想上产生了明显差异。
本文将从变量声明、函数、输入输出、字符串处理、内存管理、结构体与类、命名空间、函数重载、默认参数、引用、类型转换、异常处理等多个维度,系统梳理C语言与C++在基础语法上的核心区别,帮助读者快速建立两门语言的语法对比认知。
2. 变量声明与初始化
2.1 声明位置
在C语言中,变量声明通常需要放在代码块的开头(C89标准要求),虽然C99之后允许在语句之间声明变量,但很多老代码和编译器仍习惯将声明集中在块首。
c
// C语言风格
void func() {
int a;
int b;
a = 10;
b = 20;
// 使用变量
}
在C++中,变量声明可以出现在任何位置,提倡"用时声明",即在使用变量前就近声明,提高代码可读性。
cpp
// C++风格
void func() {
int a = 10;
// 其他语句
int b = a * 2; // 就近声明
}
2.2 初始化方式
C语言中变量初始化主要使用赋值运算符 =。
c
int x = 10;
C++在C语言的基础上,增加了列表初始化(花括号初始化)语法,可以用于内置类型、数组、结构体、类对象等。
cpp
int x{10}; // 列表初始化
int arr[]{1, 2, 3}; // 数组列表初始化
列表初始化还有一个重要特性:防止窄化转换。当初始化值可能发生精度丢失时,编译器会报错。
cpp
int x{3.14}; // 编译错误:double 到 int 的窄化转换
int y = 3.14; // C语言风格:编译通过,y 被截断为 3
3. 函数定义与调用
3.1 函数原型
C语言中,函数原型可以省略参数列表(表示接受任意参数),且空参数列表 () 在C中表示接受任意参数。
c
// C语言
void func(); // 表示接受任意参数(旧式风格)
void func(void); // 表示不接受任何参数
C++中,() 明确表示不接受任何参数,且不允许省略参数列表。
cpp
// C++
void func(); // 明确表示不接受任何参数
3.2 函数重载
C语言不支持函数重载,同一作用域内函数名必须唯一。
c
// C语言:编译错误,重复定义
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
C++支持函数重载,允许同名函数根据参数类型、个数或顺序不同而共存。
cpp
// C++:合法,构成重载
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
3.3 默认参数
C语言不支持默认参数,调用时必须提供全部实参。
c
// C语言:无法实现默认参数
void print(int value) { /* ... */ }
C++支持默认参数,可以在函数声明中为参数指定默认值。
cpp
// C++:支持默认参数
void print(int value, int precision = 2) { /* ... */ }
print(3.14159); // 使用默认精度
print(3.14159, 4); // 指定精度
4. 输入输出
4.1 C语言风格
C语言使用 printf 和 scanf 进行格式化输入输出,需要包含 <stdio.h> 头文件,并且需要手动指定格式说明符。
c
#include <stdio.h>
int main() {
int age;
printf("请输入年龄:");
scanf("%d", &age);
printf("年龄是:%d\n", age);
return 0;
}
4.2 C++风格
C++使用 cout 和 cin 进行流式输入输出,需要包含 <iostream> 头文件,无需手动指定格式说明符,类型安全。
cpp
#include <iostream>
int main() {
int age;
std::cout << "请输入年龄:";
std::cin >> age;
std::cout << "年龄是:" << age << std::endl;
return 0;
}
C++的流式输出可以自动识别类型,且支持链式调用,代码更简洁直观。
5. 字符串处理
5.1 C语言字符串
C语言使用字符数组(char[])或字符指针(char*)表示字符串,以 \0 结尾。字符串操作依赖 <string.h> 中的库函数。
c
#include <stdio.h>
#include <string.h>
int main() {
char str1[20] = "Hello";
char str2[20] = "World";
strcat(str1, str2); // 拼接
printf("%s\n", str1);
return 0;
}
5.2 C++字符串
C++提供了 std::string 类,封装了字符串的存储和操作,支持 + 拼接、比较、自动管理内存等,使用更安全便捷。
cpp
#include <iostream>
#include <string>
int main() {
std::string str1 = "Hello";
std::string str2 = "World";
std::string result = str1 + str2; // 直接拼接
std::cout << result << std::endl;
return 0;
}
std::string 还支持 ==、< 等运算符直接比较,无需调用 strcmp。
6. 内存管理
6.1 C语言内存分配
C语言使用 malloc、calloc、realloc 和 free 进行动态内存管理,需要手动计算字节数并强制类型转换。
c
#include <stdlib.h>
int main() {
int *arr = (int*)malloc(10 * sizeof(int));
if (arr == NULL) {
// 处理分配失败
}
free(arr);
return 0;
}
6.2 C++内存分配
C++使用 new 和 delete 进行动态内存管理,语法更简洁,自动计算大小,且无需强制类型转换。
cpp
int main() {
int *arr = new int[10]; // 分配数组
delete[] arr; // 释放数组
int *p = new int(42); // 分配单个变量并初始化
delete p;
return 0;
}
此外,C++还支持 new 的初始化语法,如 new int(42),而C语言的 malloc 无法直接初始化内存内容。
7. 结构体与类
7.1 C语言结构体
C语言使用 struct 定义结构体,只能包含数据成员,不能包含成员函数。访问成员时需要使用 struct 关键字(除非使用 typedef)。
c
#include <stdio.h>
struct Point {
int x;
int y;
};
int main() {
struct Point p;
p.x = 10;
p.y = 20;
printf("(%d, %d)\n", p.x, p.y);
return 0;
}
7.2 C++类
C++使用 class 或 struct 定义类,可以同时包含数据成员和成员函数,支持访问控制(public、private、protected)、继承、多态等面向对象特性。
cpp
#include <iostream>
class Point {
private:
int x;
int y;
public:
Point(int x, int y) : x(x), y(y) {} // 构造函数
void print() {
std::cout << "(" << x << ", " << y << ")" << std::endl;
}
};
int main() {
Point p(10, 20);
p.print();
return 0;
}
C++的 struct 与 class 的唯一区别是默认访问权限不同:struct 默认 public,class 默认 private。
8. 命名空间
C语言没有命名空间的概念,所有全局标识符共享同一个全局作用域,容易产生命名冲突。
c
// C语言:全局命名冲突风险
int count = 0; // 全局变量
void count() {} // 编译错误:与变量重名
C++引入了命名空间 (namespace),用于组织代码、避免命名冲突。
cpp
#include <iostream>
namespace Math {
int add(int a, int b) { return a + b; }
}
namespace Physics {
int add(int a, int b) { return a + b; } // 与 Math::add 不冲突
}
int main() {
std::cout << Math::add(1, 2) << std::endl;
std::cout << Physics::add(1, 2) << std::endl;
return 0;
}
C++标准库中的内容都位于 std 命名空间中,这也是为什么使用 cout 时需要写 std::cout。
9. 引用
C语言没有引用类型,只能通过指针间接访问变量。
c
// C语言:使用指针
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
C++引入了引用 (&),作为变量的别名,使用更安全、语法更简洁。
cpp
// C++:使用引用
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
引用在定义时必须初始化,且不能重新绑定到其他变量,相比指针更安全。
10. 类型转换
10.1 C语言类型转换
C语言使用强制类型转换运算符 (type),语法简单但不够安全,编译器不做类型检查。
c
double pi = 3.14159;
int approx = (int)pi; // 强制转换
10.2 C++类型转换
C++提供了四种命名的类型转换运算符,语义更明确、更安全:
cpp
// static_cast:编译时类型转换
int approx = static_cast<int>(pi);
// dynamic_cast:运行时多态类型转换
Base* b = dynamic_cast<Base*>(derived);
// const_cast:去除 const 属性
const int* p = &x;
int* q = const_cast<int*>(p);
// reinterpret_cast:底层重新解释
int* p = reinterpret_cast<int*>(address);
C++的命名转换让代码意图更清晰,也便于代码审查和查找。
11. 异常处理
C语言没有 内置的异常处理机制,通常通过返回值、errno 全局变量或 setjmp/longjmp 来处理错误。
c
#include <stdio.h>
#include <errno.h>
int main() {
FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
printf("错误码:%d\n", errno);
return 1;
}
return 0;
}
C++提供了异常处理 机制,使用 try、catch、throw 关键字,可以抛出和捕获任意类型的异常对象。
cpp
#include <iostream>
#include <stdexcept>
int divide(int a, int b) {
if (b == 0) {
throw std::runtime_error("除数不能为零");
}
return a / b;
}
int main() {
try {
int result = divide(10, 0);
std::cout << result << std::endl;
} catch (const std::exception &e) {
std::cout << "捕获异常:" << e.what() << std::endl;
}
return 0;
}
12. 布尔类型
C语言(C89/C90)没有 内置的布尔类型,通常用 int 配合 0/1 或宏定义来表示真假。
c
// C语言:使用 int 或宏
#define TRUE 1
#define FALSE 0
int flag = TRUE;
C99引入了 _Bool 类型,但使用不便。C++直接提供了 bool 类型,取值 true 和 false。
cpp
// C++:内置 bool 类型
bool flag = true;
if (flag) {
// ...
}
13. 总结
| 对比维度 | C语言 | C++ |
|---|---|---|
| 变量声明位置 | 通常集中在块首 | 可随时就近声明 |
| 初始化方式 | = 赋值 |
支持列表初始化 {} |
| 函数重载 | 不支持 | 支持 |
| 默认参数 | 不支持 | 支持 |
| 输入输出 | printf/scanf |
cout/cin |
| 字符串 | char[] + 库函数 |
std::string |
| 内存管理 | malloc/free |
new/delete |
| 数据封装 | struct(仅数据) |
class(数据+方法) |
| 命名空间 | 无 | namespace |
| 引用 | 无 | 支持 & |
| 类型转换 | (type) |
static_cast 等四种 |
| 异常处理 | 返回值/errno | try/catch/throw |
| 布尔类型 | int 模拟 |
bool |
C语言简洁高效,贴近底层;C++在C的基础上引入了面向对象、泛型编程等高级特性,功能更强大,但语法也更复杂。理解两者的语法差异,有助于在不同场景下选择更合适的语言,也能帮助C程序员平滑过渡到C++。