Skip to content

C语言核心特性:函数、数组与指针

在掌握了C语言基础之后,我们现在来学习C语言的核心特性。这些特性是C语言强大功能的基础,也是区别于其他高级语言的重要特征。

1. 函数:代码的模块化工具

函数是C程序的基本构建块,它允许我们将复杂的任务分解为更小、更易管理的部分。

函数定义与声明

c
#include <stdio.h>

// 函数声明(原型)
int add(int a, int b);
void print_message(const char* message);
int factorial(int n);

// 主函数
int main() {
    int result = add(5, 3);
    printf("5 + 3 = %d\n", result);
    
    print_message("Hello, Function!");
    
    int fact = factorial(5);
    printf("5! = %d\n", fact);
    
    return 0;
}

// 函数定义
int add(int a, int b) {
    return a + b;
}

void print_message(const char* message) {
    printf("消息: %s\n", message);
}

// 递归函数示例
int factorial(int n) {
    if (n <= 1) {
        return 1;
    }
    return n * factorial(n - 1);
}

参数传递方式

C语言中的参数传递采用值传递方式:

c
#include <stdio.h>

// 值传递:不会修改原始变量
void modify_value(int x) {
    x = 100;
    printf("函数内 x = %d\n", x);
}

// 通过指针传递地址:可以修改原始变量
void modify_by_pointer(int* ptr) {
    *ptr = 200;
    printf("函数内 *ptr = %d\n", *ptr);
}

int main() {
    int num = 50;
    
    printf("调用前 num = %d\n", num);
    modify_value(num);
    printf("值传递后 num = %d\n", num);
    
    modify_by_pointer(&num);
    printf("指针传递后 num = %d\n", num);
    
    return 0;
}

函数的高级用法

c
#include <stdio.h>

// 可变参数函数
#include <stdarg.h>

int sum(int count, ...) {
    va_list args;
    va_start(args, count);
    
    int total = 0;
    for (int i = 0; i < count; i++) {
        total += va_arg(args, int);
    }
    
    va_end(args);
    return total;
}

// 内联函数(C99标准)
static inline int max(int a, int b) {
    return (a > b) ? a : b;
}

int main() {
    // 可变参数函数调用
    int result = sum(4, 10, 20, 30, 40);
    printf("sum(10, 20, 30, 40) = %d\n", result);
    
    // 内联函数
    printf("max(5, 8) = %d\n", max(5, 8));
    
    return 0;
}

2. 数组:数据的集合

数组是存储相同类型数据的连续内存区域。

一维数组

c
#include <stdio.h>

int main() {
    // 数组定义和初始化
    int numbers[5] = {1, 2, 3, 4, 5};
    int scores[10];  // 未初始化,值不确定
    int primes[] = {2, 3, 5, 7, 11};  // 自动计算大小
    
    // 数组访问
    printf("第一个元素: %d\n", numbers[0]);
    printf("最后一个元素: %d\n", numbers[4]);
    
    // 数组遍历
    printf("数组元素: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", numbers[i]);
    }
    printf("\n");
    
    // 数组大小
    int size = sizeof(numbers) / sizeof(numbers[0]);
    printf("数组大小: %d\n", size);
    
    return 0;
}

二维数组

c
#include <stdio.h>

int main() {
    // 二维数组定义和初始化
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };
    
    // 访问二维数组元素
    printf("matrix[1][2] = %d\n", matrix[1][2]);
    
    // 遍历二维数组
    printf("矩阵内容:\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%3d ", matrix[i][j]);
        }
        printf("\n");
    }
    
    return 0;
}

字符数组与字符串

c
#include <stdio.h>
#include <string.h>

int main() {
    // 字符数组定义
    char name1[] = "张三";
    char name2[20] = "李四";
    char name3[10];
    
    // 字符串输入输出
    printf("请输入姓名: ");
    scanf("%s", name3);
    printf("你好, %s!\n", name3);
    
    // 字符串处理函数
    printf("name1长度: %zu\n", strlen(name1));
    printf("name1和name2比较: %d\n", strcmp(name1, name2));
    
    // 字符串复制
    char copy[20];
    strcpy(copy, name1);
    printf("复制的字符串: %s\n", copy);
    
    // 字符串连接
    char full_name[50] = "姓名: ";
    strcat(full_name, name1);
    printf("%s\n", full_name);
    
    return 0;
}

3. 指针基础:C语言的灵魂

指针是C语言最强大也是最复杂的特性,它直接操作内存地址。

指针的基本概念

c
#include <stdio.h>

int main() {
    int num = 42;
    int* ptr;  // 声明指针变量
    
    // 指针赋值
    ptr = &num;  // &取地址运算符
    
    // 指针解引用
    printf("num的值: %d\n", num);
    printf("num的地址: %p\n", &num);
    printf("ptr的值(地址): %p\n", ptr);
    printf("ptr指向的值: %d\n", *ptr);  // *解引用运算符
    
    // 通过指针修改值
    *ptr = 100;
    printf("修改后num的值: %d\n", num);
    
    return 0;
}

指针与数组

c
#include <stdio.h>

int main() {
    int arr[5] = {10, 20, 30, 40, 50};
    int* ptr = arr;  // 数组名就是指向首元素的指针
    
    // 通过数组下标访问
    printf("数组元素: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    // 通过指针访问
    printf("指针访问: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", *(ptr + i));  // 指针算术运算
    }
    printf("\n");
    
    // 指针递增
    printf("指针递增访问: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", *ptr);
        ptr++;  // 指针指向下一个元素
    }
    printf("\n");
    
    return 0;
}

指针与函数

c
#include <stdio.h>

// 通过指针交换两个数
void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 函数返回指针
int* find_max(int arr[], int size) {
    int* max_ptr = &arr[0];
    for (int i = 1; i < size; i++) {
        if (arr[i] > *max_ptr) {
            max_ptr = &arr[i];
        }
    }
    return max_ptr;
}

int main() {
    int x = 10, y = 20;
    printf("交换前: x = %d, y = %d\n", x, y);
    
    swap(&x, &y);
    printf("交换后: x = %d, y = %d\n", x, y);
    
    int numbers[] = {3, 7, 1, 9, 5};
    int* max_ptr = find_max(numbers, 5);
    printf("数组最大值: %d\n", *max_ptr);
    
    return 0;
}

4. 结构体与共用体:自定义数据类型

结构体允许我们创建包含不同类型数据的复合数据类型。

结构体定义与使用

c
#include <stdio.h>
#include <string.h>

// 定义结构体
struct Student {
    int id;
    char name[50];
    int age;
    float score;
};

// 使用typedef简化结构体使用
typedef struct {
    char title[100];
    char author[50];
    float price;
    int pages;
} Book;

int main() {
    // 结构体变量声明和初始化
    struct Student student1 = {1001, "张三", 20, 85.5};
    
    // 逐个成员初始化
    struct Student student2;
    student2.id = 1002;
    strcpy(student2.name, "李四");
    student2.age = 21;
    student2.score = 92.0;
    
    // 访问结构体成员
    printf("学生信息:\n");
    printf("ID: %d\n", student1.id);
    printf("姓名: %s\n", student1.name);
    printf("年龄: %d\n", student1.age);
    printf("成绩: %.1f\n", student1.score);
    
    // 结构体数组
    Book library[3] = {
        {"C程序设计", "谭浩强", 39.8, 400},
        {"数据结构", "严蔚敏", 45.0, 380},
        {"算法导论", "Thomas", 128.0, 800}
    };
    
    printf("\n图书馆藏书:\n");
    for (int i = 0; i < 3; i++) {
        printf("《%s》 - %s - ¥%.1f - %d\n", 
               library[i].title, library[i].author, 
               library[i].price, library[i].pages);
    }
    
    return 0;
}

结构体指针

c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    int x, y;
} Point;

int main() {
    // 结构体变量
    Point p1 = {10, 20};
    
    // 结构体指针
    Point* ptr = &p1;
    
    // 访问结构体成员(通过指针)
    printf("通过指针访问: (%d, %d)\n", ptr->x, ptr->y);
    printf("等价写法: (%d, %d)\n", (*ptr).x, (*ptr).y);
    
    // 动态分配结构体内存
    Point* dynamic_point = (Point*)malloc(sizeof(Point));
    if (dynamic_point != NULL) {
        dynamic_point->x = 30;
        dynamic_point->y = 40;
        printf("动态分配的点: (%d, %d)\n", 
               dynamic_point->x, dynamic_point->y);
        free(dynamic_point);
    }
    
    return 0;
}

共用体和枚举

c
#include <stdio.h>

// 共用体:多个成员共享同一内存空间
union Data {
    int i;
    float f;
    char str[20];
};

// 枚举:定义命名常量
enum Color { RED, GREEN, BLUE };
enum Week { MONDAY = 1, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY };

int main() {
    // 共用体使用
    union Data data;
    
    data.i = 10;
    printf("data.i: %d\n", data.i);
    
    data.f = 220.5;
    printf("data.f: %f\n", data.f);
    
    // 注意:此时data.i的值已经被覆盖
    printf("data.i after f assignment: %d\n", data.i);
    
    // 枚举使用
    enum Color favorite_color = RED;
    enum Week today = WEDNESDAY;
    
    printf("最喜欢的颜色: %d\n", favorite_color);
    printf("今天是星期: %d\n", today);
    
    // 枚举与switch结合使用
    switch (favorite_color) {
        case RED:
            printf("红色是热情的颜色\n");
            break;
        case GREEN:
            printf("绿色是自然的颜色\n");
            break;
        case BLUE:
            printf("蓝色是宁静的颜色\n");
            break;
    }
    
    return 0;
}

5. 实践项目

学生成绩管理系统

c
#include <stdio.h>
#include <string.h>

#define MAX_STUDENTS 100

typedef struct {
    int id;
    char name[50];
    float chinese;
    float math;
    float english;
    float average;
} Student;

// 计算平均分
void calculate_average(Student* student) {
    student->average = (student->chinese + student->math + student->english) / 3.0;
}

// 添加学生
int add_student(Student students[], int count) {
    if (count >= MAX_STUDENTS) {
        printf("学生数量已达上限!\n");
        return count;
    }
    
    Student new_student;
    printf("请输入学生ID: ");
    scanf("%d", &new_student.id);
    printf("请输入学生姓名: ");
    scanf("%s", new_student.name);
    printf("请输入语文成绩: ");
    scanf("%f", &new_student.chinese);
    printf("请输入数学成绩: ");
    scanf("%f", &new_student.math);
    printf("请输入英语成绩: ");
    scanf("%f", &new_student.english);
    
    calculate_average(&new_student);
    students[count] = new_student;
    
    printf("学生添加成功!\n");
    return count + 1;
}

// 显示所有学生
void display_students(Student students[], int count) {
    if (count == 0) {
        printf("暂无学生信息!\n");
        return;
    }
    
    printf("\n%-5s %-10s %-8s %-8s %-8s %-8s\n", 
           "ID", "姓名", "语文", "数学", "英语", "平均分");
    printf("--------------------------------------------------------\n");
    
    for (int i = 0; i < count; i++) {
        printf("%-5d %-10s %-8.1f %-8.1f %-8.1f %-8.1f\n",
               students[i].id, students[i].name,
               students[i].chinese, students[i].math,
               students[i].english, students[i].average);
    }
}

// 按平均分排序
void sort_by_average(Student students[], int count) {
    for (int i = 0; i < count - 1; i++) {
        for (int j = 0; j < count - 1 - i; j++) {
            if (students[j].average < students[j + 1].average) {
                Student temp = students[j];
                students[j] = students[j + 1];
                students[j + 1] = temp;
            }
        }
    }
    printf("按平均分排序完成!\n");
}

int main() {
    Student students[MAX_STUDENTS];
    int count = 0;
    int choice;
    
    while (1) {
        printf("\n=== 学生成绩管理系统 ===\n");
        printf("1. 添加学生\n");
        printf("2. 显示所有学生\n");
        printf("3. 按平均分排序\n");
        printf("0. 退出\n");
        printf("请选择: ");
        
        scanf("%d", &choice);
        
        switch (choice) {
            case 1:
                count = add_student(students, count);
                break;
            case 2:
                display_students(students, count);
                break;
            case 3:
                sort_by_average(students, count);
                display_students(students, count);
                break;
            case 0:
                printf("再见!\n");
                return 0;
            default:
                printf("无效选择,请重新输入!\n");
        }
    }
    
    return 0;
}

字符串处理工具

c
#include <stdio.h>
#include <string.h>
#include <ctype.h>

// 字符串反转
void reverse_string(char* str) {
    int len = strlen(str);
    for (int i = 0; i < len / 2; i++) {
        char temp = str[i];
        str[i] = str[len - 1 - i];
        str[len - 1 - i] = temp;
    }
}

// 统计单词数
int count_words(const char* str) {
    int count = 0;
    int in_word = 0;
    
    for (int i = 0; str[i] != '\0'; i++) {
        if (isspace(str[i])) {
            in_word = 0;
        } else if (!in_word) {
            in_word = 1;
            count++;
        }
    }
    
    return count;
}

// 字符串转大写
void to_uppercase(char* str) {
    for (int i = 0; str[i] != '\0'; i++) {
        str[i] = toupper(str[i]);
    }
}

// 字符串转小写
void to_lowercase(char* str) {
    for (int i = 0; str[i] != '\0'; i++) {
        str[i] = tolower(str[i]);
    }
}

int main() {
    char text[200];
    
    printf("请输入一段文本: ");
    fgets(text, sizeof(text), stdin);
    
    // 移除换行符
    text[strcspn(text, "\n")] = '\0';
    
    printf("原始文本: %s\n", text);
    
    // 字符串反转
    char reversed[200];
    strcpy(reversed, text);
    reverse_string(reversed);
    printf("反转后: %s\n", reversed);
    
    // 单词统计
    printf("单词数: %d\n", count_words(text));
    
    // 大小写转换
    char upper[200], lower[200];
    strcpy(upper, text);
    strcpy(lower, text);
    to_uppercase(upper);
    to_lowercase(lower);
    printf("大写: %s\n", upper);
    printf("小写: %s\n", lower);
    
    return 0;
}

总结

本章节介绍了C语言的核心特性:

  • 函数的定义、声明和参数传递
  • 数组的定义、初始化和访问
  • 指针的基本概念和使用方法
  • 结构体、共用体和枚举的使用
  • 实际项目中的应用示例

掌握这些核心特性后,你已经具备了编写复杂C程序的能力。函数让你能够模块化代码,数组和指针提供了高效的数据处理方式,结构体让你能够创建复杂的自定义数据类型。

在下一章节中,我们将学习C语言的高级特性,包括指针的高级应用、预处理命令、标准库的深入使用等。

记住,指针是C语言的核心难点,需要多加练习。多编写涉及指针的程序,理解内存布局,这样才能真正掌握C语言的精髓。结构体和函数的结合使用是构建大型程序的基础,熟练掌握这些概念将为你的C语言学习之路打下坚实的基础。