开始卷~C语言 day01

31 阅读4分钟

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语言,需要重点掌握:

  1. 内存管理:从自动管理转向手动管理
  2. 指针概念:理解内存地址和间接访问
  3. 函数指针:C语言的函数式编程特性
  4. 结构体:C语言的"类"概念
  5. 错误处理:C语言没有异常机制,需要手动检查

下一章我们将学习C语言的高级特性,包括预处理器、位操作、文件I/O等。