C语言:从Hello World开始 - 我的编程之旅

月落乌啼霜满天,江枫渔火对愁眠。 --枫桥夜泊 / 夜泊枫江 

引言:为什么选择C语言?

        作为编程世界的基石语言,C语言自1972年诞生以来,一直是系统编程、嵌入式开发和性能关键型应用的首选。它不仅是操作系统的构建基础(如Linux、Windows内核),更是理解计算机底层工作原理的最佳入口。在这篇博客中,我将带你从最简单的"Hello World"开始,逐步深入C语言的奇妙世界。

第一章:Hello World - 程序员的仪式

每个C语言学习者的旅程都从这段经典代码开始:

#include <stdio.h>  // 标准输入输出头文件

int main() {        // 程序入口函数
    printf("Hello, World!\n");  // 输出语句
    return 0;       // 程序正常结束
}

代码解析:

  1. #include <stdio.h> - 包含标准输入输出库,使我们可以使用printf()函数

  2. int main() - 程序执行的起点,操作系统从这里开始运行程序

  3. printf() - 格式化输出函数,\n表示换行符

  4. return 0; - 向操作系统返回0,表示程序成功执行

编译运行这个程序,你将在屏幕上看到:

Hello, World!

第二章:变量与数据类型 - 程序的基础元素

(1) 数据类型:

C语言提供了多种基本数据类型来存储不同种类的数据:

#include <stdio.h>

int main() {
    // 整数类型
    int age = 25;
    short year = 2023;
    long population = 7800000000L;
    
    // 浮点类型
    float pi = 3.14159f;
    double precise_pi = 3.141592653589793;
    
    // 字符类型
    char initial = 'A';
    
    // 布尔类型(C99)
    _Bool is_cool = 1; // 1表示true,0表示false
    
    // 输出变量值
    printf("Age: %d\n", age);
    printf("Pi: %.5f\n", pi);
    printf("Initial: %c\n", initial);
    printf("C is cool? %d\n", is_cool);
    
    return 0;
}

数据类型总结表:

数据类型名称大小(字节)格式说明符范围
char字符数据类型1%c-128 到 127
short短整型2%hd-32,768 到 32,767
int整型4%d-2,147,483,648 到 2,147,483,647
long长整型8%ld-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
float单精度浮点数4%f约 ±3.4e±38(7位有效数字)
double双精度浮点数8%lf约 ±1.7e±308(15位有效数字)
_Bool布尔类型(C99)1%d0 或 1

 计算机存储基本单位

不同字符在计算机中所占大小是不同的;

计算机存储的基本单位是比特(bit),而最常用的单位是字节(Byte)。

以下是常见的存储单位及其关系:

1. 比特(bit,简写为b):是计算机中最小的存储单位,表示一个二进制位,只能是0或1。

2. 字节(Byte,简写为B):1字节等于8比特。字节是计算机中数据处理的基本单位。

更大的单位来表示更大的存储容量:

3. 千字节(Kilobyte, KB):1 KB = 1024 Byte(注意,这里用的是二进制,所以是2的10次方)。

4. 兆字节(Megabyte, MB):1 MB = 1024 KB = 1024 * 1024 Byte。

5. 吉字节(Gigabyte, GB):1 GB = 1024 MB = 1024 * 1024 * 1024 Byte。

6. 太字节(Terabyte, TB):1 TB = 1024 GB = 1024 * 1024 * 1024 * 1024 Byte。

7. 拍字节(Petabyte, PB):1 PB = 1024 TB,以此类推。

如需要了解更多的计算机存储单位的知识,欢迎大家学习以下文章,谢谢

计算机存储单位详解:从比特到尧字节-CSDN博客

(2) 变量与常量

变量:程序运行期间其值可以改变的量。变量需要定义数据类型,并且分配存储空间。

2.1  变量(Variable) - 程序中的可变数据

1. 变量定义与特性
  • 定义:程序运行期间其值可以改变的量

  • 特性

    • 需要明确的数据类型

    • 必须先声明后使用

    • 存储在内存中,有唯一地址

    • 生命周期取决于作用域

#include <stdio.h>

int main() {
    // 变量声明与初始化
    int age = 25;           // 整型变量
    float height = 1.75f;   // 浮点型变量
    char grade = 'A';       // 字符型变量
    char name[] = "Alice";  // 字符数组变量
    
    // 变量值的修改
    age = 26;
    height = 1.77f;
    grade = 'B';
    
    printf("%s is %d years old, %.2f meters tall, grade %c\n", 
           name, age, height, grade);
    
    return 0;
}
2. 变量命名规则
  • 由字母、数字和下划线组成

  • 不能以数字开头

  • 区分大小写(age ≠ Age

  • 不能使用C语言关键字(如intfloat等)

  • 建议使用驼峰命名法(studentAge)或下划线命名法(student_age

 3. 变量作用域
#include <stdio.h>

int globalVar = 100;  // 全局变量 - 整个程序可见

void demoFunction() {
    int localVar = 50;  // 局部变量 - 仅在函数内可见
    static int staticVar = 0;  // 静态变量 - 函数调用间保持值
    
    staticVar++;
    printf("Static variable: %d\n", staticVar);
}

int main() {
    int localVar = 20;  // main函数的局部变量
    
    printf("Global variable: %d\n", globalVar);
    printf("Local variable: %d\n", localVar);
    
    demoFunction();  // 输出: Static variable: 1
    demoFunction();  // 输出: Static variable: 2
    
    // 块作用域变量
    {
        int blockVar = 30;
        printf("Block variable: %d\n", blockVar);
    }
    // printf("%d\n", blockVar); // 错误!blockVar在此不可见
    
    return 0;
}
Global variable: 100
Local variable: 20
Static variable: 1
Static variable: 2
Block variable: 30

常量:程序运行期间其值不能改变的量。常量也分为不同的类型,如整型常量、浮点常量、字符常量、字符串常量等。另外,C语言中还可以用#define和const来定义常量。

2.2 常量(Constant) - 程序中的不变数据

1. 常量类型与定义方式
常量类型定义方式示例
字面常量直接值423.14'A'
const常量const关键字const int MAX = 100;
#define常量预处理器指令#define PI 3.14159
枚举常量enum关键字enum Color {RED, GREEN}
 2. 常量使用示例
#include <stdio.h>

// 使用#define定义常量
#define MAX_USERS 100
#define PI 3.14159
#define WELCOME_MSG "Welcome to C Programming!"

// 使用const定义常量
const int MIN_AGE = 18;
const double GRAVITY = 9.8;

// 使用enum定义常量
enum Weekdays {MON=1, TUE, WED, THU, FRI, SAT, SUN};

int main() {
    // 字面常量
    printf("Integer literal: %d\n", 42);
    printf("Float literal: %.2f\n", 3.14);
    printf("Character literal: %c\n", 'X');
    printf("String literal: %s\n", "Hello World!");
    
    // const常量
    printf("\nConst constants:\n");
    printf("Minimum age: %d\n", MIN_AGE);
    printf("Gravity constant: %.1f m/s²\n", GRAVITY);
    
    // #define常量
    printf("\n#define constants:\n");
    printf("Max users: %d\n", MAX_USERS);
    printf("PI value: %.5f\n", PI);
    printf("%s\n", WELCOME_MSG);
    
    // 枚举常量
    printf("\nEnum constants:\n");
    printf("Monday: %d\n", MON);
    printf("Friday: %d\n", FRI);
    
    // 尝试修改常量(将导致错误)
    // MIN_AGE = 16;  // 错误:不能修改const常量
    // MAX_USERS = 200; // 错误:不能修改#define常量
    
    return 0;
}
Integer literal: 42
Float literal: 3.14
Character literal: X
String literal: Hello World!

Const constants:
Minimum age: 18
Gravity constant: 9.8 m/s²

#define constants:
Max users: 100
PI value: 3.14159
Welcome to C Programming!

Enum constants:
Monday: 1
Friday: 5
 3. 常量与指针的配合使用
#include <stdio.h>

int main() {
    // 指向常量的指针(不能通过指针修改值)
    const int ID = 12345;
    const int *ptr1 = &ID;
    // *ptr1 = 54321; // 错误:不能修改指向的值
    
    // 常量指针(不能修改指针指向的地址)
    int value = 100;
    int *const ptr2 = &value;
    *ptr2 = 200;    // 可以修改值
    printf("Value: %d\n", value);
    
    // 不能修改指针指向
    int another = 300;
    // ptr2 = &another; // 错误:ptr2是常量指针
    
    // 指向常量的常量指针
    const float PI = 3.14159;
    const float *const ptr3 = &PI;
    // *ptr3 = 3.14;    // 错误:不能修改值
    // ptr3 = NULL;     // 错误:不能修改指针
    
    return 0;
}

2.3、 变量与常量的核心区别

特性变量常量
值可变性可以改变不可改变
定义方式数据类型 + 变量名const/#define/enum
内存分配运行时分配内存可能直接替换(#define)
作用域取决于声明位置取决于定义位置
典型用途存储计算结果、用户输入等存储固定值、配置参数等

2.4、实战应用场景 

1. 配置管理系统(常量应用)
#include <stdio.h>

// 系统配置常量
#define MAX_CONNECTIONS 5
#define TIMEOUT 30
#define SERVER_IP "192.168.1.100"
const double VERSION = 2.5;
enum LogLevel {INFO, WARNING, ERROR};

void connectToServer() {
    printf("Connecting to %s...\n", SERVER_IP);
    printf("Timeout set to %d seconds\n", TIMEOUT);
}

int main() {
    // 当前连接数(变量)
    int currentConnections = 0;
    
    printf("System Version: %.1f\n", VERSION);
    printf("Max connections: %d\n", MAX_CONNECTIONS);
    

    // 模拟连接
    while(currentConnections < MAX_CONNECTIONS) {
        connectToServer();
        currentConnections++;
        
        if(currentConnections % 10 == 0) {
            printf("Current connections: %d\n", currentConnections);
        }
    }

    printf("Reached maximum connections: %d\n", MAX_CONNECTIONS);
    return 0;
}

 2. 温度转换程序(变量应用)
#include <stdio.h>

// 常量定义
#define FAHRENHEIT_BASE 32.0
#define CONVERSION_FACTOR (5.0/9.0)

int main() {
    // 变量定义
    float celsius, fahrenheit;
    
    printf("Enter temperature in Fahrenheit: ");
    scanf("%f", &fahrenheit);
    
    // 转换计算(使用变量)
    celsius = (fahrenheit - FAHRENHEIT_BASE) * CONVERSION_FACTOR;
    
    printf("%.1f°F = %.1f°C\n", fahrenheit, celsius);
    
    // 使用变量存储不同温度值
    float roomTempF = 68.0;
    float roomTempC = (roomTempF - FAHRENHEIT_BASE) * CONVERSION_FACTOR;
    
    printf("Room temperature: %.1f°F / %.1f°C\n", roomTempF, roomTempC);
    
    return 0;
}

3. 枚举常量在状态机中的应用 
#include <stdio.h>

// 定义电梯状态枚举常量
enum ElevatorState { 
    STOPPED, 
    MOVING_UP, 
    MOVING_DOWN, 
    DOOR_OPEN 
};

const char* stateNames[] = {
    "STOPPED",
    "MOVING_UP",
    "MOVING_DOWN",
    "DOOR_OPEN"
};

int main() {
    // 当前状态变量
    enum ElevatorState currentState = STOPPED;
    int currentFloor = 1;
    int targetFloor = 5;
    
    printf("Elevator initial state: %s at floor %d\n", 
           stateNames[currentState], currentFloor);
    
    // 状态转换
    if(currentFloor < targetFloor) {
        currentState = MOVING_UP;
    } else if(currentFloor > targetFloor) {
        currentState = MOVING_DOWN;
    }
    
    printf("Elevator now: %s\n", stateNames[currentState]);
    
    // 模拟移动
    while(currentFloor != targetFloor) {
        if(currentState == MOVING_UP) {
            currentFloor++;
        } else {
            currentFloor--;
        }
        printf("Current floor: %d\n", currentFloor);
    }
    
    currentState = STOPPED;
    printf("Arrived at floor %d. State: %s\n", currentFloor, stateNames[currentState]);
    
    return 0;
}

 

2.5 、最佳实践与常见错误

变量使用准则:
  1. 尽量缩小变量的作用域

  2. 初始化所有变量

  3. 避免使用全局变量(除非必要)

  4. 使用有意义的变量名

  5. 注意变量类型转换

常量使用准则:
  1. 使用const替代#define(类型安全)

  2. 常量命名全大写(如MAX_SIZE

  3. 使用枚举代替魔数(magic numbers)

  4. 整型常量添加后缀(如100L表示long)

  5. 浮点常量添加后缀(如3.14f表示float)

 常见错误示例:
#include <stdio.h>

int main() {
    // 错误1:未初始化变量
    int uninitialized;
    printf("%d\n", uninitialized); // 输出随机值
    
    // 错误2:修改常量
    const int FIXED = 100;
    // FIXED = 200; // 编译错误
    
    // 错误3:越界访问
    int arr[5] = {1, 2, 3, 4, 5};
    printf("%d\n", arr[5]); // 越界访问
    
    // 错误4:混淆=和==
    int x = 5;
    if(x = 10) { // 总是为真(赋值而非比较)
        printf("x is 10\n");
    }
    
    return 0;
}

 理解变量与常量的区别是掌握C语言的基础。变量提供了程序运行时的灵活性,而常量则确保了核心逻辑的稳定性。合理使用两者,可以构建出既灵活又可靠的程序系统。

第三章:控制流程 - 程序的决策能力

控制流程是编程中的核心概念,它决定了程序如何根据条件执行不同的代码块,或者重复执行某些任务。在C语言中,主要有以下控制结构:

(1) 条件语句

1. if 语句

最基本的条件判断结构,当条件为真时执行代码块

#include <stdio.h>

int main() {
    int age = 18;
    
    // 基本if语句
    if (age >= 18) {
        printf("You are an adult.\n");
    }
    
    return 0;
}

2. if-else 语句

当条件为真时执行一个代码块,否则执行另一个代码块

#include <stdio.h>

int main() {
    int number = 7;
    
    if (number % 2 == 0) {
        printf("%d is even.\n", number);
    } else {
        printf("%d is odd.\n", number);
    }
    
    return 0;
}

3. if-else if 语句

处理多个条件分支

#include <stdio.h>

int main() {
    int score = 85;
    
    if (score >= 90) {
        printf("Grade: A\n");
    } else if (score >= 80) {
        printf("Grade: B\n");
    } else if (score >= 70) {
        printf("Grade: C\n");
    } else if (score >= 60) {
        printf("Grade: D\n");
    } else {
        printf("Grade: F\n");
    }
    
    return 0;
}

4. 三元运算符 (?:)

简洁的条件表达式,适合简单的条件赋值

#include <stdio.h>

int main() {
    int a = 10, b = 20;
    
    // 使用三元运算符找出最大值
    int max = (a > b) ? a : b;
    printf("Max value: %d\n", max);
    
    // 更复杂的例子
    printf("The number is %s\n", (a % 2 == 0) ? "even" : "odd");
    
    return 0;
}

 5. switch 语句

处理多个固定值的条件分支,比多个if-else更清晰

#include <stdio.h>

int main() {
    char operator;
    double num1, num2;
    
    printf("Enter operator (+, -, *, /): ");
    scanf(" %c", &operator);
    
    printf("Enter two operands: ");
    scanf("%lf %lf", &num1, &num2);
    
    switch (operator) {
        case '+':
            printf("%.1lf + %.1lf = %.1lf\n", num1, num2, num1 + num2);
            break;
        case '-':
            printf("%.1lf - %.1lf = %.1lf\n", num1, num2, num1 - num2);
            break;
        case '*':
            printf("%.1lf * %.1lf = %.1lf\n", num1, num2, num1 * num2);
            break;
        case '/':
            if (num2 != 0.0)
                printf("%.1lf / %.1lf = %.1lf\n", num1, num2, num1 / num2);
            else
                printf("Error! Division by zero is not allowed.\n");
            break;
        default:
            printf("Error! Invalid operator.\n");
    }
    
    return 0;
}

switch语句要点:

  • case 后必须是整型常量表达式

  • break 防止"贯穿"执行下一个case

  • default 处理未匹配的情况

(2) 循环语句

1. while 循环

当条件为真时重复执行代码块

#include <stdio.h>

int main() {
    int count = 1;
    
    // 打印1到5
    while (count <= 5) {
        printf("%d ", count);
        count++;
    }
    printf("\n");
    
    return 0;
}

2. do-while 循环

先执行一次代码块,然后检查条件,适合需要至少执行一次的场景

#include <stdio.h>

int main() {
    int number;
    
    // 确保用户输入正数
    do {
        printf("Enter a positive number: ");
        scanf("%d", &number);
        
        if (number <= 0) {
            printf("Invalid input. Please try again.\n");
        }
    } while (number <= 0);
    
    printf("You entered: %d\n", number);
    return 0;
}

3. for 循环

最常用的循环结构,适合已知循环次数的场景

#include <stdio.h>

int main() {
    // 基本for循环
    for (int i = 1; i <= 5; i++) {
        printf("%d ", i);
    }
    printf("\n");
    
    // 更复杂的例子:打印乘法表
    for (int row = 1; row <= 9; row++) {
        for (int col = 1; col <= row; col++) {
            printf("%d*%d=%-2d ", col, row, col * row);
        }
        printf("\n");
    }
    
    return 0;
}

4. 无限循环与退出条件

使用while(1)for(;;)创建无限循环,配合break退出

#include <stdio.h>

int main() {
    int sum = 0, number;
    
    printf("Enter numbers to sum (0 to exit):\n");
    
    // 无限循环,直到用户输入0
    while (1) {
        printf("Enter a number: ");
        scanf("%d", &number);
        
        if (number == 0) {
            break; // 退出循环
        }
        
        sum += number;
    }
    
    printf("Total sum: %d\n", sum);
    return 0;
}

(3) 循环控制语句

1. break 语句

立即退出当前循环或switch语句

#include <stdio.h>

int main() {
    // 查找第一个能被7整除的数
    for (int i = 1; i <= 100; i++) {
        if (i % 7 == 0) {
            printf("Found: %d\n", i);
            break; // 找到后立即退出循环
        }
    }
    return 0;
}

2. continue 语句

跳过当前循环的剩余部分,进入下一次迭代

#include <stdio.h>

int main() {
    // 打印1-10的奇数
    for (int i = 1; i <= 10; i++) {
        if (i % 2 == 0) {
            continue; // 跳过偶数
        }
        printf("%d ", i);
    }
    printf("\n");
    return 0;
}

3. goto 语句

无条件跳转到指定标签(谨慎使用,容易导致代码混乱)

#include <stdio.h>

int main() {
    int number;
    
    printf("Enter a positive number: ");
    scanf("%d", &number);
    
    if (number <= 0) {
        goto error; // 跳转到错误处理
    }
    
    printf("Valid number: %d\n", number);
    return 0;
    
error: // 标签
    printf("Error! Number must be positive.\n");
    return 1;
}

(4) 嵌套控制结构

1. 嵌套if语句

#include <stdio.h>

int main() {
    int age = 25;
    char license = 'Y';
    
    if (age >= 18) {
        if (license == 'Y') {
            printf("You can drive a car.\n");
        } else {
            printf("You need a driver's license.\n");
        }
    } else {
        printf("You are too young to drive.\n");
    }
    
    return 0;
}

 2. 循环中的条件判断

#include <stdio.h>

int main() {
    // 找出1-100的质数
    for (int num = 2; num <= 100; num++) {
        int is_prime = 1; // 假设是质数
        
        for (int i = 2; i * i <= num; i++) {
            if (num % i == 0) {
                is_prime = 0; // 不是质数
                break;
            }
        }
        
        if (is_prime) {
            printf("%d ", num);
        }
    }
    printf("\n");
    return 0;
}

(5) 控制结构最佳实践

  1. 避免深层嵌套:嵌套超过3层应考虑重构

  2. 使用switch替代多个if-else:提高可读性

  3. 循环边界检查:防止数组越界

  4. 避免无限循环:确保有退出条件

  5. 谨慎使用goto:只在错误处理等特殊场景使用

  6. 使用括号明确范围:即使只有一行代码

  7. 添加注释说明复杂逻辑

(6) 综合应用:简易计算器

#include <stdio.h>

int main() {
    char choice;
    double num1, num2;
    
    do {
        printf("\nCalculator Menu:\n");
        printf("1. Addition (+)\n");
        printf("2. Subtraction (-)\n");
        printf("3. Multiplication (*)\n");
        printf("4. Division (/)\n");
        printf("5. Exit\n");
        printf("Enter your choice: ");
        scanf(" %c", &choice);
        
        if (choice == '5') {
            printf("Exiting calculator...\n");
            break;
        }
        
        if (choice < '1' || choice > '5') {
            printf("Invalid choice! Please try again.\n");
            continue;
        }
        
        printf("Enter two numbers: ");
        scanf("%lf %lf", &num1, &num2);
        
        switch (choice) {
            case '1':
                printf("Result: %.2lf + %.2lf = %.2lf\n", num1, num2, num1 + num2);
                break;
            case '2':
                printf("Result: %.2lf - %.2lf = %.2lf\n", num1, num2, num1 - num2);
                break;
            case '3':
                printf("Result: %.2lf * %.2lf = %.2lf\n", num1, num2, num1 * num2);
                break;
            case '4':
                if (num2 != 0.0) {
                    printf("Result: %.2lf / %.2lf = %.2lf\n", num1, num2, num1 / num2);
                } else {
                    printf("Error! Division by zero is not allowed.\n");
                }
                break;
        }
    } while (1); // 无限循环,直到用户选择退出
    
    return 0;
}

通过掌握这些控制结构,你可以编写出能够根据不同条件执行不同操作、重复执行任务直到满足条件的程序。这些是构建复杂程序的基础,建议通过实际编写各种小程序来加深理解。 

第四章:函数 - 模块化编程的基石

函数是C语言程序的基本构建块,它允许你将代码组织成可重用、可维护的模块。本章将深入探讨函数的各个方面,并通过代码示例帮助你全面掌握函数的使用。

(1)函数的基本概念

1. 什么是函数?

  • 完成特定任务的独立代码块

  • 有输入(参数)和输出(返回值)

  • 提高代码复用性和可读性 

2. 函数的结构

返回类型 函数名(参数列表) {
    // 函数体
    return 返回值; // 可选
}

(2)函数的定义与调用

1. 简单函数示例

#include <stdio.h>

// 函数声明(告诉编译器函数的存在)
void greet();

// 函数定义
void greet() {
    printf("Hello, welcome to C programming!\n");
}

int main() {
    greet(); // 函数调用
    return 0;
}

2. 带参数的函数

#include <stdio.h>

// 计算平方
int square(int num) {
    return num * num;
}

int main() {
    int number = 5;
    int result = square(number);
    printf("%d squared is %d\n", number, result);
    return 0;
}

 3. 带返回值的函数

#include <stdio.h>

// 查找最大值
int max(int a, int b) {
    if (a > b) {
        return a;
    } else {
        return b;
    }
}

int main() {
    int x = 10, y = 20;
    printf("The max of %d and %d is %d\n", x, y, max(x, y));
    return 0;
}

(3)函数参数详解

1. 值传递(默认行为)

#include <stdio.h>

// 值传递 - 不影响原始变量
void increment(int num) {
    num++;
    printf("Inside function: %d\n", num);
}

int main() {
    int value = 5;
    increment(value);
    printf("Outside function: %d\n", value); // 仍为5
    return 0;
}

2. 指针传递(修改原始变量)

#include <stdio.h>

// 指针传递 - 可以修改原始变量
void real_increment(int *num) {
    (*num)++;
    printf("Inside function: %d\n", *num);
}

int main() {
    int value = 5;
    real_increment(&value);
    printf("Outside function: %d\n", value); // 变为6
    return 0;
}

 3. 数组作为参数

#include <stdio.h>

// 数组作为参数(实际传递指针)
void print_array(int arr[], int size) {
    printf("Array elements: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

// 修改数组元素
void double_array(int *arr, int size) {
    for (int i = 0; i < size; i++) {
        arr[i] *= 2;
    }
}

int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    int size = sizeof(numbers) / sizeof(numbers[0]);
    
    print_array(numbers, size);
    double_array(numbers, size);
    print_array(numbers, size);
    
    return 0;
}

(4)函数原型与头文件

1. 函数原型的重要性

#include <stdio.h>

// 函数原型声明(放在文件顶部)
double calculate_average(int array[], int size);

int main() {
    int scores[] = {85, 90, 78, 92, 88};
    int size = sizeof(scores) / sizeof(scores[0]);
    
    double avg = calculate_average(scores, size);
    printf("Average score: %.2f\n", avg);
    
    return 0;
}

// 函数定义(放在main后面)
double calculate_average(int array[], int size) {
    int sum = 0;
    for (int i = 0; i < size; i++) {
        sum += array[i];
    }
    return (double)sum / size;
}

2. 使用头文件组织函数

math_utils.h

#ifndef MATH_UTILS_H
#define MATH_UTILS_H

// 函数原型
int factorial(int n);
int gcd(int a, int b);
int lcm(int a, int b);

#endif

 math_utils.c

#include "math_utils.h"

// 计算阶乘
int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

// 计算最大公约数
int gcd(int a, int b) {
    if (b == 0) return a;
    return gcd(b, a % b);
}

// 计算最小公倍数
int lcm(int a, int b) {
    return (a * b) / gcd(a, b);
}

 main.c

#include <stdio.h>
#include "math_utils.h"

int main() {
    int a = 5, b = 7;
    
    printf("%d! = %d\n", a, factorial(a));
    printf("GCD of %d and %d is %d\n", a, b, gcd(a, b));
    printf("LCM of %d and %d is %d\n", a, b, lcm(a, b));
    
    return 0;
}

(5)递归函数 

1. 基本递归:阶乘

#include <stdio.h>

int factorial(int n) {
    // 基线条件
    if (n <= 1) return 1;
    
    // 递归调用
    return n * factorial(n - 1);
}

int main() {
    int num = 5;
    printf("%d! = %d\n", num, factorial(num));
    return 0;
}

2. 经典递归:斐波那契数列

#include <stdio.h>

int fibonacci(int n) {
    // 基线条件
    if (n <= 0) return 0;
    if (n == 1) return 1;
    
    // 递归调用
    return fibonacci(n - 1) + fibonacci(n - 2);
}

int main() {
    printf("Fibonacci sequence: ");
    for (int i = 0; i < 10; i++) {
        printf("%d ", fibonacci(i));
    }
    printf("\n");
    return 0;
}

3. 递归应用:汉诺塔问题

#include <stdio.h>

void hanoi(int n, char from, char to, char aux) {
    if (n == 1) {
        printf("Move disk 1 from %c to %c\n", from, to);
        return;
    }
    
    hanoi(n - 1, from, aux, to);
    printf("Move disk %d from %c to %c\n", n, from, to);
    hanoi(n - 1, aux, to, from);
}

int main() {
    int disks = 3;
    printf("Solution for Tower of Hanoi with %d disks:\n", disks);
    hanoi(disks, 'A', 'C', 'B');
    return 0;
}

(6)高级函数技术

1. 函数指针

#include <stdio.h>

// 简单数学操作
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }

int main() {
    // 声明函数指针
    int (*operation)(int, int);
    
    int x = 10, y = 5;
    
    // 使用函数指针
    operation = add;
    printf("%d + %d = %d\n", x, y, operation(x, y));
    
    operation = subtract;
    printf("%d - %d = %d\n", x, y, operation(x, y));
    
    operation = multiply;
    printf("%d * %d = %d\n", x, y, operation(x, y));
    
    return 0;
}

2. 回调函数

#include <stdio.h>

// 回调函数类型
typedef void (*Callback)(int);

// 处理数据的函数
void process_data(int data, Callback callback) {
    printf("Processing data: %d\n", data);
    int result = data * 2;
    callback(result); // 调用回调函数
}

// 回调函数实现
void print_result(int result) {
    printf("Result: %d\n", result);
}

void save_result(int result) {
    printf("Saving result to file: %d\n", result);
}

int main() {
    process_data(5, print_result);
    process_data(10, save_result);
    return 0;
}

3. 可变参数函数

#include <stdio.h>
#include <stdarg.h>

// 计算任意数量整数的平均值
double average(int count, ...) {
    va_list args;
    va_start(args, count);
    
    double sum = 0;
    for (int i = 0; i < count; i++) {
        sum += va_arg(args, int);
    }
    
    va_end(args);
    return sum / count;
}

int main() {
    printf("Average of 1, 2, 3: %.2f\n", average(3, 1, 2, 3));
    printf("Average of 10, 20, 30, 40: %.2f\n", average(4, 10, 20, 30, 40));
    return 0;
}

(7)函数设计最佳实践

1. 函数设计原则

  • 单一职责原则:一个函数只做一件事

  • 合理命名:动词+名词(如calculate_sum()

  • 参数控制:不超过5个参数

  • 函数长度:不超过50行

  • 避免副作用:减少全局变量使用

2. 错误处理技术

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

// 安全除法函数
int safe_divide(int dividend, int divisor, int *result) {
    if (divisor == 0) {
        return 0; // 错误状态
    }
    
    *result = dividend / divisor;
    return 1; // 成功状态
}

int main() {
    int a = 10, b = 0;
    int result;
    
    if (safe_divide(a, b, &result)) {
        printf("%d / %d = %d\n", a, b, result);
    } else {
        printf("Error: Division by zero!\n");
    }
    
    return 0;
}

(8)综合应用:计算器程序

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

// 函数原型
double add(double a, double b);
double subtract(double a, double b);
double multiply(double a, double b);
double divide(double a, double b);
void display_menu();

int main() {
    char choice;
    double num1, num2, result;
    
    while (1) {
        display_menu();
        printf("Enter your choice: ");
        scanf(" %c", &choice);
        
        if (choice == '5') break;
        
        printf("Enter two numbers: ");
        scanf("%lf %lf", &num1, &num2);
        
        switch (choice) {
            case '1':
                result = add(num1, num2);
                break;
            case '2':
                result = subtract(num1, num2);
                break;
            case '3':
                result = multiply(num1, num2);
                break;
            case '4':
                if (num2 != 0) {
                    result = divide(num1, num2);
                } else {
                    printf("Error: Division by zero!\n");
                    continue;
                }
                break;
            default:
                printf("Invalid choice!\n");
                continue;
        }
        
        printf("Result: %.2lf\n\n", result);
    }
    
    printf("Calculator closed. Goodbye!\n");
    return 0;
}

// 显示菜单
void display_menu() {
    printf("\nCalculator Menu:\n");
    printf("1. Addition\n");
    printf("2. Subtraction\n");
    printf("3. Multiplication\n");
    printf("4. Division\n");
    printf("5. Exit\n");
}

// 加法
double add(double a, double b) {
    return a + b;
}

// 减法
double subtract(double a, double b) {
    return a - b;
}

// 乘法
double multiply(double a, double b) {
    return a * b;
}

// 除法
double divide(double a, double b) {
    return a / b;
}

(9)函数调试技巧

1. 调试打印函数

#include <stdio.h>

// 调试宏
#ifdef DEBUG
#define DEBUG_PRINT(fmt, ...) printf("DEBUG: " fmt, ##__VA_ARGS__)
#else
#define DEBUG_PRINT(fmt, ...)
#endif

// 复杂计算函数
int complex_calculation(int a, int b) {
    DEBUG_PRINT("Entering complex_calculation with a=%d, b=%d\n", a, b);
    
    int result = 0;
    for (int i = 0; i < a; i++) {
        result += b * i;
        DEBUG_PRINT("Iteration %d: result=%d\n", i, result);
    }
    
    DEBUG_PRINT("Exiting complex_calculation with result=%d\n", result);
    return result;
}

int main() {
    // 编译时加上 -DDEBUG 启用调试输出
    int x = complex_calculation(3, 5);
    printf("Final result: %d\n", x);
    return 0;
}

2. 断言检查

#include <stdio.h>
#include <assert.h>

// 计算阶乘(带断言)
int factorial(int n) {
    // 前置条件:n必须是非负整数
    assert(n >= 0);
    
    if (n == 0) return 1;
    return n * factorial(n - 1);
}

int main() {
    printf("5! = %d\n", factorial(5));
    // printf("-1! = %d\n", factorial(-1)); // 会触发断言失败
    return 0;
}

通过本章的学习,你应该掌握了函数的定义、使用和高级技巧。函数是C语言模块化编程的核心,合理使用函数可以:

  1. 提高代码复用性

  2. 简化复杂问题

  3. 增强代码可读性

  4. 便于团队协作

  5. 简化调试过程

在接下来的编程实践中,尝试将复杂任务分解为多个小函数,遵循单一职责原则,你会逐渐体会到函数带来的巨大优势。

第五章:数组 - 数据集合的处理

数组是存储多个相同类型元素的连续内存空间:

#include <stdio.h>

int main() {
    // 一维数组
    int numbers[5] = {2, 4, 6, 8, 10};
    
    printf("Array elements: ");
    for(int i = 0; i < 5; i++) {
        printf("%d ", numbers[i]);
    }
    printf("\n");
    
    // 二维数组(矩阵)
    int matrix[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    
    printf("\nMatrix:\n");
    for(int i = 0; i < 3; i++) {
        for(int j = 0; j < 3; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }
    
    return 0;
}

第六章:指针 - C语言的精髓

指针是C语言最强大也最容易出错的概念:

#include <stdio.h>

int main() {
    int num = 42;
    int *ptr = &num;  // ptr指向num的地址
    
    printf("Value of num: %d\n", num);         // 42
    printf("Address of num: %p\n", &num);      // 内存地址
    printf("Value via pointer: %d\n", *ptr);   // 42
    
    // 修改指针指向的值
    *ptr = 100;
    printf("New value of num: %d\n", num);     // 100
    
    // 指针与数组
    int arr[3] = {10, 20, 30};
    int *arr_ptr = arr;  // 指向数组第一个元素
    
    printf("\nArray via pointer:\n");
    for(int i = 0; i < 3; i++) {
        printf("Element %d: %d\n", i, *(arr_ptr + i));
    }
    
    return 0;
}

指针使用注意事项:

  1. 始终初始化指针(设置为NULL或有效地址)

  2. 检查指针是否为NULL后再解引用

  3. 注意指针算术(加减操作基于指向类型的大小)

  4. 避免野指针(指向已释放内存的指针)

第七章:结构体 - 自定义数据类型

结构体允许我们将不同类型的数据组合在一起:

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

// 定义结构体类型
struct Student {
    int id;
    char name[50];
    float gpa;
};

int main() {
    // 创建结构体实例
    struct Student student1;
    student1.id = 101;
    strcpy(student1.name, "Alice Johnson");
    student1.gpa = 3.8f;
    
    // 结构体指针
    struct Student *student_ptr = &student1;
    
    // 访问结构体成员
    printf("Student ID: %d\n", student1.id);
    printf("Student Name: %s\n", student_ptr->name);  // 指针使用->运算符
    printf("GPA: %.2f\n", student_ptr->gpa);
    
    return 0;
}

学习路线图:从Hello World到精通

 

下一步计划

在接下来的博客中,我将深入探讨:

  1. 动态内存管理(malloc、calloc、realloc、free)

  2. 文件操作与数据持久化

  3. C语言标准库深度解析

  4. 常用数据结构实现(链表、栈、队列、二叉树)

  5. 多文件编程与模块化设计

  6. 调试技巧与常见错误分析

结语

C语言的学习就像攀登一座高山 - 从Hello World这个起点出发,每一步都充满挑战但也收获满满。记住编程大师的名言:

"The only way to learn a new programming language is by writing programs in it." - Dennis Ritchie (C语言之父)

准备好你的编译器,让我们在代码的世界里继续探索!欢迎在评论区分享你的第一个C程序和学习心得。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值