探索 C 与 Java/Kotlin 的语言差异:从指针到高阶函数
作为一名熟悉 Java 和 Kotlin 的开发者,初次接触 C/C++ 时常会遇到一系列概念上的“文化冲击”。本文将从几个关键点出发,帮助你更好地理解 C/C++ 与 Java/Kotlin 在语言设计上的核心区别。
1. 指向未知类型的指针 void*
、结构体指针访问 ->
、空指针常量 nullptr
(1) void*
:可以指向任何类型的指针
在 C 中,void*
是一种通用指针类型,常用于参数类型不确定的场景。
void print_value(void* ptr, int type) {if (type == 0) printf("%d", *(int*)ptr);else if (type == 1) printf("%f", *(float*)ptr);
}
你可以将 void*
转换为具体类型后使用,相当于 Java 中的 Object
,但它完全没有类型安全保障。
(2) ->
:结构体指针访问成员的语法
如果你有一个结构体指针,可以用 ->
操作符访问它的成员。
struct Person {int age;
};Person p = {20};
Person* ptr = &p;
printf("%d", ptr->age); // 等价于 (*ptr).age
这相当于 Kotlin 中的 person.age
,不过这里访问的是指针指向的结构体成员。
(3) nullptr
:C++ 中的空指针常量
C++ 引入了 nullptr
,它是一个类型安全的空指针替代 NULL
:
int* p = nullptr; // 安全地表示一个空指针
类似于 Java/Kotlin 中的 null
,但 nullptr
是一个关键字,不会误用为整数 0。
2. 栈对象 vs 堆对象:C++ 中对象的创建方式
(1) 栈上创建对象
Person p{20}; // 栈上对象,生命周期随作用域结束自动释放
(2) 堆上创建对象
Person* p = new Person(20); // 堆上对象,需手动 delete
在 Kotlin 中,所有对象都是在堆上创建,由 JVM 的垃圾回收机制管理内存;而 C++ 给了开发者更多控制权,但也带来了内存管理的负担。
3. C 语言的结构体能定义函数指针,Java 的类只能定义变量/方法
在 Java 中,类中只能写方法和变量,方法不能被当作值赋给变量。
但在 C 中,结构体除了能声明变量,还能声明“函数指针”,如下所示:
struct Greeter {void (*sayHello)();
};void greet() {printf("Hello!\n");
}int main() {Greeter g = { greet };g.sayHello(); // 调用函数指针return 0;
}
这就像是给结构体添加了“行为”,尽管 C 并不是面向对象语言。
4. C 的函数指针 = Kotlin 的高阶函数?
C 语言中的函数指针,本质上就是“可以把函数当作变量”的方式:
void greet() {printf("Hi\n");
}void run_twice(void (*func)()) {func(); func();
}
而 Kotlin 的高阶函数也做了类似的事,只是语法更现代:
fun runTwice(action: () -> Unit) {action()action()
}fun greet() = println("Hi")fun main() {runTwice(::greet)
}
可以认为 Kotlin 把 C 的函数指针“包装”成了类型安全、可推断的高阶函数。
总结:不同语言,相似理念
特性 | C | Java | Kotlin |
---|---|---|---|
函数作为值 | ✅ 函数指针 | ❌(Java 8 前不支持) | ✅ 高阶函数 |
通用指针/对象 | void* | Object | Any? |
空指针 | NULL / nullptr | null | null |
方法指针 | 函数指针 | Lambda (Java 8+) | 函数类型 / Lambda |
对象内声明函数 | 函数指针变量 | 方法(不能赋值) | 可以将函数存为变量 |
学习 C/C++ 的过程,其实是补足你对内存、函数本质和语言底层的理解,非常适合有 Java/Kotlin 背景的开发者进阶。
如果你正在从 Java/Kotlin 走向底层世界,C/C++ 会是你绕不开的一站。理解这些基础概念,就像打开一扇通往计算机世界核心的大门 🚪