Java开发工程师的C语言基础教程
1. 从Java到C:核心概念对比
1.1 内存管理对比
Java (自动内存管理)
// Java中,对象自动分配和回收
String str = new String("Hello");
// 不需要手动释放内存,JVM的垃圾回收器会自动处理
C (手动内存管理)
// C中需要手动分配和释放内存
char* str = malloc(6 * sizeof(char));
strcpy(str, "Hello");
// 必须手动释放内存,否则会造成内存泄漏
free(str);
1.2 变量声明和初始化
Java
// Java中变量有默认值
int number; // 默认值为0
String text; // 默认值为null
boolean flag; // 默认值为false
C
// C中变量没有默认值,包含随机数据
int number; // 未初始化,包含随机值
char* text; // 未初始化,指向随机地址
int flag; // 未初始化,包含随机值
// 正确的初始化方式
int number = 0;
char* text = NULL;
int flag = 0;
1.3 数组和字符串
Java
// Java中的数组
int[] numbers = {1, 2, 3, 4, 5};
String text = "Hello World";
C
// C中的数组
int numbers[] = {1, 2, 3, 4, 5};
char text[] = "Hello World"; // 字符串以'\0'结尾
char* text_ptr = "Hello World"; // 字符串字面量
2. 指针:C语言的核心概念
2.1 什么是指针
指针是C语言中最重要的概念,它存储内存地址。
int number = 42;
int* ptr = &number; // ptr存储number的地址
printf("number的值: %d\n", number); // 输出: 42
printf("number的地址: %p\n", &number); // 输出: 0x7fff5fbff8ac
printf("ptr存储的地址: %p\n", ptr); // 输出: 0x7fff5fbff8ac
printf("ptr指向的值: %d\n", *ptr); // 输出: 42
2.2 指针与Java引用的对比
Java引用
// Java中的引用
String str1 = "Hello";
String str2 = str1; // str2指向同一个对象
C指针
// C中的指针
char* str1 = "Hello";
char* str2 = str1; // str2指向同一个字符串
3. 函数和参数传递
3.1 值传递 vs 引用传递
Java
// Java中对象通过引用传递
public void modifyArray(int[] arr) {
arr[0] = 100; // 修改会影响原数组
}
public void modifyPrimitive(int num) {
num = 100; // 不会影响原值
}
C
// C中通过指针实现"引用传递"
void modifyArray(int arr[], int size) {
arr[0] = 100; // 修改会影响原数组
}
void modifyValue(int* num) {
*num = 100; // 通过指针修改原值
}
void modifyValueByValue(int num) {
num = 100; // 不会影响原值
}
3.2 函数指针
C语言支持函数指针,这在Java中需要通过接口或lambda表达式实现。
// 函数指针类型定义
typedef int (*operation_func)(int, int);
// 具体函数
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
// 使用函数指针
int calculate(int a, int b, operation_func op) {
return op(a, b);
}
// 调用
int result = calculate(10, 5, add); // 结果: 15
int result2 = calculate(10, 5, subtract); // 结果: 5
4. 结构体 vs Java类
4.1 基本结构体
Java类
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void display() {
System.out.println("Name: " + name + ", Age: " + age);
}
}
C结构体
// 结构体定义
struct Person {
char name[50];
int age;
};
// 结构体函数
void display_person(struct Person* person) {
printf("Name: %s, Age: %d\n", person->name, person->age);
}
// 使用
struct Person person = {"张三", 25};
display_person(&person);
4.2 结构体指针
// 动态分配结构体
struct Person* create_person(const char* name, int age) {
struct Person* person = malloc(sizeof(struct Person));
strcpy(person->name, name);
person->age = age;
return person;
}
// 释放结构体
void free_person(struct Person* person) {
free(person);
}
5. 内存管理最佳实践
5.1 常见错误
// 错误1:内存泄漏
void memory_leak() {
char* str = malloc(100);
// 忘记调用 free(str)
}
// 错误2:悬空指针
void dangling_pointer() {
char* str = malloc(100);
free(str);
// str现在指向已释放的内存
strcpy(str, "Hello"); // 危险!
}
// 错误3:缓冲区溢出
void buffer_overflow() {
char buffer[10];
strcpy(buffer, "This string is too long"); // 溢出!
}
5.2 正确的做法
// 正确的内存管理
char* safe_string_copy(const char* source) {
if (source == NULL) return NULL;
size_t len = strlen(source) + 1;
char* dest = malloc(len);
if (dest == NULL) {
return NULL; // 内存分配失败
}
strcpy(dest, source);
return dest;
}
// 使用
char* str = safe_string_copy("Hello World");
if (str != NULL) {
printf("%s\n", str);
free(str); // 及时释放
str = NULL; // 避免悬空指针
}
6. 练习项目
6.1 简单链表实现
// 链表节点
struct Node {
int data;
struct Node* next;
};
// 创建新节点
struct Node* create_node(int data) {
struct Node* node = malloc(sizeof(struct Node));
node->data = data;
node->next = NULL;
return node;
}
// 插入节点
void insert_node(struct Node** head, int data) {
struct Node* new_node = create_node(data);
new_node->next = *head;
*head = new_node;
}
// 打印链表
void print_list(struct Node* head) {
struct Node* current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}
// 释放链表
void free_list(struct Node* head) {
struct Node* current = head;
while (current != NULL) {
struct Node* temp = current;
current = current->next;
free(temp);
}
}
总结
作为Java开发者学习C语言,需要重点掌握:
- 内存管理:从自动管理转向手动管理
- 指针概念:理解内存地址和间接访问
- 函数指针:C语言的函数式编程特性
- 结构体:C语言的"类"概念
- 错误处理:C语言没有异常机制,需要手动检查
下一章我们将学习C语言的高级特性,包括预处理器、位操作、文件I/O等。