04_明解C语言 - Yiwei666/05_C_programing GitHub Wiki

C语言是一种较为底层的编程语言,设计初衷是为了提供高效的系统级编程和硬件控制,而不是为了支持面向对象编程(OOP)的高级抽象。

1. 格式化输入输出、运算和数据类型

#include <stdio.h>

int main() {
    // 声明变量
    int num1, num2, sum;
    float floatNum;

    // 格式化输入
    printf("请输入第一个整数: ");
    scanf("%d", &num1);

    printf("请输入第二个整数: ");
    scanf("%d", &num2);

    // 基本运算
    sum = num1 + num2;

    // 格式化输出
    printf("\n=== 计算结果 ===\n");
    printf("第一个整数: %d\n", num1);
    printf("第二个整数: %d\n", num2);
    printf("它们的和: %d\n", sum);

    // 数据类型示例
    printf("\n=== 数据类型示例 ===\n");
    floatNum = (float)sum / 2;  // 类型转换
    printf("和的一半(作为浮点数): %.2f\n", floatNum);

    return 0;
}

这个示例程序首先通过scanf函数获取用户输入的两个整数,然后进行加法运算,并通过printf函数输出结果。在数据类型示例中,将整数和转换为浮点数,演示了类型转换的过程。

回到顶部

2. 分支结构和循环控制

1. 分支结构

#include <stdio.h>

int main() {
    // if语句示例
    int num;
    printf("请输入一个整数: ");
    scanf("%d", &num);

    if (num > 0) {
        printf("输入的数字是正数\n");
    } else if (num < 0) {
        printf("输入的数字是负数\n");
    } else {
        printf("输入的数字是零\n");
    }

    // switch语句示例
    char grade;
    printf("请输入一个字母等级(A, B, C, D, F): ");
    scanf(" %c", &grade);  // 注意这里的空格,防止缓冲区残留的换行符影响输入

    switch (grade) {
        case 'A':
            printf("优秀\n");
            break;
        case 'B':
            printf("良好\n");
            break;
        case 'C':
            printf("中等\n");
            break;
        case 'D':
            printf("及格\n");
            break;
        case 'F':
            printf("不及格\n");
            break;
        default:
            printf("无效的等级\n");
    }

    return 0;
}

在这个示例程序中,用户首先输入一个整数和一个字母等级。程序使用if语句判断整数的正负零情况,并使用switch语句判断字母等级对应的评价。请注意switch语句中的break语句,它用于跳出switch语句,以防止后续的case语句被执行。

2. 循环控制

#include <stdio.h>

int main() {
    // while循环示例
    int count_while = 0;
    printf("=== while循环示例 ===\n");
    while (count_while < 5) {
        printf("当前循环次数: %d\n", count_while);
        count_while++;
    }

    // do-while循环示例
    int count_do_while = 0;
    printf("\n=== do-while循环示例 ===\n");
    do {
        printf("当前循环次数: %d\n", count_do_while);
        count_do_while++;
    } while (count_do_while < 5);

    // for循环示例
    printf("\n=== for循环示例 ===\n");
    for (int i = 0; i < 5; i++) {
        printf("当前循环次数: %d\n", i);
    }

    return 0;
}

在这个示例程序中,首先展示了while循环,然后是do-while循环,最后是for循环。这三种循环结构分别用于执行一定次数的循环,循环的次数通过计数器变量来控制。请注意,for循环的结构包含了初始化、条件判断和迭代步骤。这些循环结构提供了不同的方式来控制程序的流程,使得程序能够重复执行特定的任务。

回到顶部

3. 数组

数组由数据类型相同的一系列元素组成。需要使用数组时,通过声明数组告诉编译器数组中内含多少元素和这些元素的类型。编译器根据这些信息正确地创建数组。与普通变量类似,数组元素的数据类型可以是整数、字符、浮点数等,但数组元素的类型必须一致。

1. 数组声明、访问和遍历

Image Description

#include <stdio.h>

int main() {
    // 声明一个整数数组并初始化
    int numbers[] = {1, 2, 3, 4, 5};

    // 访问数组元素
    printf("Accessing individual elements:\n");
    for (int i = 0; i < 5; i++) {
        printf("Element at index %d: %d\n", i, numbers[i]);
    }

    // 修改数组元素
    numbers[2] = 10;

    // 遍历数组
    printf("\nTraversing the array after modification:\n");
    for (int i = 0; i < 5; i++) {
        printf("%d ", numbers[i]);
    }

    return 0;
}

在这个例子中:

  • 声明了一个整数数组 numbers,并用大括号初始化了数组的值。
  • 使用 for 循环遍历数组,通过索引访问和打印每个元素。
  • 修改了数组的第三个元素的值。
  • 再次使用 for 循环遍历数组,打印修改后的所有元素。

请注意,C语言的数组索引从0开始,因此元素的索引范围是0到数组大小减1

2. 数组初始化

#include <stdio.h>

int main() {
    // 一维整数数组
    int intArr[5];

    // 赋值
    for (int i = 0; i < 5; ++i) {
        intArr[i] = i * 10;
    }

    // 输出一维整数数组
    printf("一维整数数组:\n");
    for (int i = 0; i < 5; ++i) {
        printf("%d ", intArr[i]);
    }
    printf("\n\n");

    // 字符数组(字符串)
    char charStr1[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
    char charStr2[] = "World";

    // 输出字符串数组
    printf("字符数组(字符串):\n");
    printf("%s %s\n\n", charStr1, charStr2);

    // 二维整数数组
    int intMatrix[3][3];

    // 赋值
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            intMatrix[i][j] = i * 3 + j + 1;
        }
    }

    // 输出二维整数数组
    printf("二维整数数组:\n");
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            printf("%d ", intMatrix[i][j]);
        }
        printf("\n");
    }

    // 浮点数数组
    float floatArr[4] = {1.2, 2.5, 3.7, 4.1};

    // 输出浮点数数组
    printf("\n浮点数数组:\n");
    for (int i = 0; i < 4; ++i) {
        printf("%.2f ", floatArr[i]);
    }
    printf("\n");

    return 0;
}

回到顶部

4. 函数

1. 函数定义

示例中包括了main函数、库函数的调用、自定义函数的定义、调用以及返回值等。

#include <stdio.h>

// 自定义函数的声明
int add(int a, int b);

// 主函数
int main() {
    // 调用库函数
    printf("=== 调用库函数 ===\n");
    printf("Hello, World!\n");

    // 调用自定义函数
    int result = add(5, 7);
    printf("\n=== 调用自定义函数 ===\n");
    printf("5 + 7 = %d\n", result);

    return 0;
}

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

在这个示例程序中,main函数是程序的入口点。它调用了库函数printf来输出一条简单的信息。同时,main函数还调用了自定义函数add,并输出了其返回值。自定义函数add用于计算两个整数的和,它包括了两个形参(参数)a和b,以及一个返回类型为int的返回值。

这个示例演示了如何声明、定义和调用函数,以及函数的返回值和形参的使用。函数的使用可以帮助组织代码,使其更具可读性和可维护性。

2. 函数设计

#include <stdio.h>

// 计算阶乘的函数
long factorial(int n) {
    if (n == 0) {
        return 1;
    } else {
        return n * factorial(n - 1); // 递归调用
    }
}

int main() {
    int number = 5;
    printf("Factorial of %d is %ld\n", number, factorial(number));
    return 0;
}

3. 作用域和存储期

函数内部声明的变量称为局部变量,它们的作用域限于函数内部。全局变量的作用域是整个程序,可以被程序中所有的函数访问。

#include <stdio.h>

int globalVar = 100; // 全局变量

void demoFunction() {
    int localVar = 10; // 局部变量
    printf("Local variable: %d\n", localVar);
    printf("Global variable: %d\n", globalVar);
}

int main() {
    demoFunction();
    // printf("%d\n", localVar); // 错误:localVar在这里不可见
    printf("Global variable in main: %d\n", globalVar);
    return 0;
}

4. 参数传递

C语言函数参数的传递可以是值传递,也可以通过指针来进行引用传递,后者允许函数修改调用者的数据。

#include <stdio.h>

// 使用指针参数修改外部变量的值
void addTen(int *number) {
    *number += 10; // 修改指针指向的值
}

int main() {
    int value = 5;
    addTen(&value); // 传递变量的地址
    printf("Value after adding ten: %d\n", value);
    return 0;
}

回到顶部

5. 基本数据类型

Image Description

1. 基本类型

C语言中的基本数据类型包括整数类型(int、short、long)、浮点数类型(float、double)、字符类型(char)、无符号整数类型(unsigned int、unsigned short、unsigned long)、和布尔类型(_Bool)。

这些数据类型用于定义变量和存储数据,每种类型有不同的取值范围和存储大小。在使用这些数据类型时,程序员需要注意避免溢出问题,选择合适的数据类型以满足程序需求,并使用正确的格式控制字符串进行输入输出。了解这些基本数据类型是编写C语言程序的基础,它们为程序提供了灵活性和效率。

#include <stdio.h>

int main() {
    // 整数类型
    int integerVar = 10;
    short shortVar = 20;
    long longVar = 3000000000;

    // 浮点数类型
    float floatVar = 3.14;
    double doubleVar = 2.71828;

    // 字符类型
    char charVar = 'A';

    // 无符号整数类型
    unsigned int unsignedVar = 42;
    unsigned short unsignedShortVar = 255;
    unsigned long unsignedLongVar = 4000000000;

    // 布尔类型
    _Bool boolVar = 1;  // 1表示真,0表示假

    // 输出各种数据类型的值
    printf("Integer: %d\n", integerVar);
    printf("Short: %d\n", shortVar);
    printf("Long: %ld\n", longVar);

    printf("Float: %f\n", floatVar);
    printf("Double: %lf\n", doubleVar);

    printf("Char: %c\n", charVar);

    printf("Unsigned Integer: %u\n", unsignedVar);
    printf("Unsigned Short: %u\n", unsignedShortVar);
    printf("Unsigned Long: %lu\n", unsignedLongVar);

    printf("Boolean: %d\n", boolVar);

    return 0;
}

这段代码声明了不同类型的变量,并使用 printf 函数输出它们的值。请注意,输出格式的控制字符串(比如 %d、%f、%c)需要与相应类型的格式匹配。

2. 整型范围

在C语言中,你可以使用标准库中的 <limits.h> 头文件来获取整数类型的范围。该头文件定义了一些常量,表示了整数类型的最小和最大值。以下是一个简单的示例程序,演示如何打印各整数类型的范围:

#include <stdio.h>
#include <limits.h>

int main() {
    printf("Range of int: %d to %d\n", INT_MIN, INT_MAX);
    printf("Range of short: %d to %d\n", SHRT_MIN, SHRT_MAX);
    printf("Range of long: %ld to %ld\n", LONG_MIN, LONG_MAX);

    // 如果支持 long long 类型,可以添加以下内容
    #if defined(LLONG_MIN) && defined(LLONG_MAX)
        printf("Range of long long: %lld to %lld\n", LLONG_MIN, LLONG_MAX);
    #endif

    return 0;
}

3. 整型与字符型

在C语言中,char 类型用于表示字符,它实际上是一个整数类型,占用1个字节的内存。每个字符都对应一个ASCII码,char 类型的变量可以存储字符的ASCII码值。

#include <stdio.h>

int main() {
    // 字符型变量
    char charVar = 'A';
    
    // 将字符的ASCII码值赋给整型变量
    int asciiValue = charVar;
    
    // 输出字符和对应的ASCII码值
    printf("Character: %c\n", charVar);
    printf("ASCII value: %d\n", asciiValue);

    // 字符型数据进行整数运算
    char charVar2 = 'B';
    int result = charVar + charVar2;
    
    // 输出字符相加的结果
    printf("Result of char addition: %d\n", result);

    return 0;
}

回到顶部

6. 字符串

1. 字符串操作

这个程序包含了字符串的表示、输入输出、长度计算、复制、拼接、比较、字符数组与指针、以及安全版本的字符串函数的使用。

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

int main() {
    // 字符串表示和输出
    char str1[] = "Hello, World!";
    printf("String: %s\n", str1);

    // 字符串长度
    int len = strlen(str1);
    printf("Length: %d\n", len);

    // 字符串复制和拼接
    char str2[20];
    strcpy(str2, str1);
    strcat(str2, " This is C.");
    printf("Copied and Concatenated String: %s\n", str2);

    // 字符串比较
    int cmp = strcmp(str1, str2);
    if (cmp == 0) {
        printf("Strings are equal.\n");
    } else {
        printf("Strings are not equal.\n");
    }

    // 字符数组与指针
    char str3[] = "Pointer";
    char *ptr = str3;
    printf("Array: %s\n", str3);
    printf("Pointer: %s\n", ptr);

    // 字符串输入
    char input[50];
    printf("Enter a string: ");
    fgets(input, sizeof(input), stdin);
    printf("Input String: %s\n", input);

    // 安全版本的字符串函数
    char dest[20];
    strncpy(dest, str1, sizeof(dest) - 1);
    dest[sizeof(dest) - 1] = '\0'; // 手动添加null字符
    printf("Safe Copy: %s\n", dest);

    return 0;
}

2. 二维字符数组与多个字符串操作

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

int main() {
    // 定义一个包含3个字符串的二维字符数组
    char strArray[3][20]; // 每个字符串最多包含19个字符 + 结尾的null字符

    // 初始化多个字符串
    strcpy(strArray[0], "Hello");
    strcpy(strArray[1], "World");
    strcpy(strArray[2], "C Programming");

    // 输出每个字符串
    for (int i = 0; i < 3; ++i) {
        printf("String %d: %s\n", i + 1, strArray[i]);
    }

    // 在第一个字符串末尾追加内容
    strcat(strArray[0], " from C");

    // 输出修改后的第一个字符串
    printf("\nModified String 1: %s\n", strArray[0]);

    // 使用 strlen 获取字符串长度
    printf("Length of String 2: %zu\n", strlen(strArray[1]));

    // 使用 strcmp 比较两个字符串
    if (strcmp(strArray[0], strArray[1]) == 0) {
        printf("String 1 and String 2 are equal.\n");
    } else {
        printf("String 1 and String 2 are not equal.\n");
    }

    // 使用 strncpy 复制部分字符串
    char temp[20];
    strncpy(temp, strArray[2], 5);
    temp[5] = '\0'; // 添加null字符以确保正确的字符串结束
    printf("Copied substring: %s\n", temp);

    // 使用 strstr 查找字符串中的子字符串
    char *substring = strstr(strArray[2], "Pro");
    if (substring != NULL) {
        printf("Substring found in String 3: %s\n", substring);
    } else {
        printf("Substring not found in String 3.\n");
    }

    return 0;
}

回到顶部

7. 指针

指针的主要优势

  1. 直接访问和修改内存地址: 指针允许直接访问和修改内存地址中的数据,而无需进行复制。这对于大型数据结构或动态分配的内存非常有用,可以提高程序的效率和性能。

  2. 传递参数和返回值的效率: 使用指针作为函数参数,可以在函数内部直接修改调用者提供的变量,而无需通过返回值传递结果。这可以减少不必要的数据复制,提高程序效率。

  3. 动态内存分配: 指针允许在运行时动态分配内存,这对于处理不确定大小的数据结构或需要灵活内存管理的情况非常有用。

  4. 数据结构操作: 指针使得在数据结构中移动和操作更为灵活。链表、树等数据结构通常使用指针来建立元素之间的关联。

  5. 数组操作: 指针可以用于直接访问数组中的元素,而无需通过数组索引。这对于数组的动态操作和遍历很有帮助。

1. 指针的基本概念

指针声明、初始化、运算符

#include <stdio.h>

int main() {
    // 声明一个整型变量
    int num = 42;

    // 声明一个指向整型的指针
    int *ptr;

    // 初始化指针,使其指向整型变量num的地址
    ptr = &num;

    // 使用指针访问变量的值
    printf("变量的值: %d\n", *ptr);

    // 修改变量的值,通过指针间接修改
    *ptr = 99;

    // 打印修改后的变量值
    printf("修改后的变量值: %d\n", num);

    // 演示指针运算符的使用
    int arr[] = {1, 2, 3, 4, 5};
    int *arr_ptr = arr;

    // 使用指针访问数组元素
    printf("第一个数组元素: %d\n", *arr_ptr);

    // 使用指针进行数组元素的递增
    arr_ptr++;
    printf("第二个数组元素: %d\n", *arr_ptr);

    return 0;
}

2. 指针和函数

通过将指针传递给函数,函数可以直接修改调用者提供的变量的值。这允许在函数内部对原始数据进行修改,而不是通过返回值传递修改后的结果。这样可以更有效地处理大量数据或者避免复制大型数据结构。

#include <stdio.h>

// 函数原型,接受一个整型指针作为参数
void multiplyByTwo(int *num) {
    // 通过指针修改调用者提供的变量的值
    *num = (*num) * 2;
}

int main() {
    // 定义一个整型变量
    int number = 5;

    // 打印原始变量的值
    printf("原始变量的值: %d\n", number);

    // 调用函数,并将变量的地址传递给函数
    multiplyByTwo(&number);

    // 打印经过函数处理后的变量的值
    printf("经过函数处理后的变量的值: %d\n", number);

    return 0;
}

3. 指针和数组

使用指针直接访问数组元素具有几个优势:

  1. 更灵活的数组操作: 指针允许对数组元素进行更灵活的操作。通过移动指针,可以直接访问数组中的任何元素,而不受数组索引的限制。这使得在处理不规则数组或需要跳跃访问元素的情况下更为方便。

  2. 更高效的内存访问: 通过指针直接访问数组元素,避免了通过数组索引进行间接访问的开销。指针可以直接指向内存地址,从而提高了访问速度,特别是在处理大型数据结构时。

  3. 方便的指针算术: 指针支持算术操作,例如递增(ptr++)或递减(ptr--),这使得在数组中移动变得非常方便。这对于循环遍历数组或进行复杂的数据操作很有帮助。

  4. 直接修改数组元素: 通过指针,可以直接修改数组元素的值。这对于对数组进行原地修改或处理大型数据集时非常有用,而无需创建临时变量。

#include <stdio.h>

int main() {
    // 定义一个整型数组
    int arr[] = {1, 2, 3, 4, 5};

    // 定义一个指向整型数组的指针,指向数组的第一个元素
    int *ptr = arr;

    // 使用指针遍历数组并打印每个元素
    for (int i = 0; i < 5; ++i) {
        printf("数组元素 %d: %d\n", i + 1, *ptr);

        // 修改数组元素的值
        *ptr = *ptr * 2;

        // 移动指针到下一个数组元素
        ptr++;
    }

    // 打印修改后的数组元素值
    printf("\n修改后的数组元素值:\n");
    for (int i = 0; i < 5; ++i) {
        printf("数组元素 %d: %d\n", i + 1, arr[i]);
    }

    return 0;
}
  • 指针类型和指针所指向的类型

指针数组和指针指向数组的概念不同,指针数组是一个数组,其中的每个元素都是指针,用于存储一组指针,每个指针可以指向不同的数据类型。指向数组的指针是一个指针,它指向数组的首元素,用于对整个数组进行操作,元素类型与数组元素相同。

#include <stdio.h>

int main() {
    // 指针数组
    int arr1[] = {1, 2, 3, 4, 5};
    int *ptrArr1[5];  // 声明一个包含5个整型指针的指针数组

    for (int i = 0; i < 5; ++i) {
        ptrArr1[i] = &arr1[i];  // 将每个指针指向数组中的对应元素
    }

    // 指针字符串
    char str[] = "Hello";
    char *ptrStr = str;  // 声明一个指向字符的指针,指向字符串的首字符

    // 指向数组的指针
    int arr2[] = {6, 7, 8, 9, 10};
    int *ptrArr2 = arr2;  // 声明一个指向整型数组的指针,指向数组的首元素

    // 使用指针数组遍历整型数组
    for (int i = 0; i < 5; ++i) {
        printf("指针数组元素 %d: %d\n", i + 1, *ptrArr1[i]);
    }

    // 使用指向数组的指针遍历整型数组
    printf("\n指向数组的指针元素:\n");
    for (int i = 0; i < 5; ++i) {
        printf("%d ", *ptrArr2);
        ptrArr2++;  // 移动指针到下一个数组元素
    }
    printf("\n");

    // 使用指针字符串遍历字符数组
    printf("\n指针字符串元素:\n");
    while (*ptrStr != '\0') {
        printf("%c ", *ptrStr);
        ptrStr++;  // 移动指针到下一个字符
    }
    printf("\n");

    return 0;
}
  • 指针数组与字符串
#include <stdio.h>

int main() {
    // 使用指针数组
    char *strArray[] = {"Apple", "Banana", "Orange", "Grapes", "Mango"};

    // 获取字符串的数量
    int numStrings = sizeof(strArray) / sizeof(strArray[0]);

    // 输出每个字符串
    printf("Using Pointer Array:\n");
    for (int i = 0; i < numStrings; ++i) {
        printf("%s\n", strArray[i]);
    }

    // 修改第二个字符串
    strArray[1] = "Cherry";

    // 输出修改后的字符串数组
    printf("\nModified Pointer Array:\n");
    for (int i = 0; i < numStrings; ++i) {
        printf("%s\n", strArray[i]);
    }

    // 使用二维数组
    char strArray2[][10] = {"Apple", "Banana", "Orange", "Grapes", "Mango"};

    // 获取字符串的数量
    int numStrings2 = sizeof(strArray2) / sizeof(strArray2[0]);

    // 输出每个字符串
    printf("\nUsing 2D Array:\n");
    for (int i = 0; i < numStrings2; ++i) {
        printf("%s\n", strArray2[i]);
    }

    // 修改第二个字符串
    strcpy(strArray2[1], "Cherry");

    // 输出修改后的字符串数组
    printf("\nModified 2D Array:\n");
    for (int i = 0; i < numStrings2; ++i) {
        printf("%s\n", strArray2[i]);
    }

    return 0;
}

4. 动态内存分配

C语言中与动态内存分配相关的主要函数包括malloc用于分配内存,calloc用于分配并初始化内存,realloc用于重新调整内存大小,以及free用于释放内存。这些函数提供了灵活的内存管理机制,但使用时需小心,确保合理分配和释放内存,以避免内存泄漏和悬空指针问题。

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

int main() {
    // 声明一个指向整数的指针
    int *dynamicArray;

    // 使用malloc分配5个整数大小的内存块
    dynamicArray = (int *)malloc(5 * sizeof(int));

    // 检查内存是否成功分配
    if (dynamicArray == NULL) {
        fprintf(stderr, "内存分配失败\n");
        return 1; // 返回错误码
    }

    // 使用指针访问动态分配的内存,给数组元素赋值
    for (int i = 0; i < 5; ++i) {
        dynamicArray[i] = i * 10;
    }

    // 打印数组的内容
    printf("动态数组的内容(使用malloc):\n");
    for (int i = 0; i < 5; ++i) {
        printf("%d ", dynamicArray[i]);
    }
    printf("\n");

    // 使用calloc分配另外3个整数大小的内存块,并将其初始化为零
    int *newDynamicArray = (int *)calloc(3, sizeof(int));

    // 检查内存是否成功分配
    if (newDynamicArray == NULL) {
        fprintf(stderr, "内存分配失败\n");
        free(dynamicArray);  // 释放之前分配的内存
        return 1; // 返回错误码
    }

    // 打印新数组的内容
    printf("新动态数组的内容(使用calloc):\n");
    for (int i = 0; i < 3; ++i) {
        printf("%d ", newDynamicArray[i]);
    }
    printf("\n");

    // 使用realloc调整之前分配的内存块的大小为8个整数
    int *resizedArray = (int *)realloc(dynamicArray, 8 * sizeof(int));

    // 检查内存是否成功重新分配
    if (resizedArray == NULL) {
        fprintf(stderr, "内存重新分配失败\n");
        free(dynamicArray);  // 释放之前分配的内存
        free(newDynamicArray);  // 释放新分配的内存
        return 1; // 返回错误码
    }

    // 使用指针访问调整大小后的内存,给数组元素赋新值
    for (int i = 5; i < 8; ++i) {
        resizedArray[i] = i * 5;
    }

    // 打印调整大小后数组的内容
    printf("调整大小后数组的内容(使用realloc):\n");
    for (int i = 0; i < 8; ++i) {
        printf("%d ", resizedArray[i]);
    }
    printf("\n");

    // 使用free释放动态分配的内存
    free(resizedArray);
    free(newDynamicArray);

    // 指针现在不再指向有效的内存,为了防止野指针,将指针置为NULL
    resizedArray = NULL;
    newDynamicArray = NULL;

    return 0; // 返回成功码
}

回到顶部

8. 结构体

1. 结构体定义、引用与初始化

#include <stdio.h>

// 定义结构体
struct Person {
    char name[50];
    int age;
    float height;
};

int main() {
    // 声明结构体变量并初始化
    struct Person person1 = {"John Doe", 25, 1.75};

    // 访问结构体成员并打印信息
    printf("Person Information:\n");
    printf("Name: %s\n", person1.name);
    printf("Age: %d\n", person1.age);
    printf("Height: %.2f meters\n", person1.height);

    // 修改结构体成员的值
    person1.age = 26;
    person1.height = 1.80;

    // 再次打印更新后的信息
    printf("\nUpdated Person Information:\n");
    printf("Name: %s\n", person1.name);
    printf("Age: %d\n", person1.age);
    printf("Height: %.2f meters\n", person1.height);

    return 0;
}

2. 结构体数组

与基本数据类型一样,结构体也可以形成数组,用于存储多个结构体变量。

#include <stdio.h>

struct Student {
    char name[50];
    int rollNo;
    float marks;
};

int main() {
    struct Student students[2] = {
        {"John", 101, 78.5},
        {"Sarah", 102, 88.5}
    };

    for (int i = 0; i < 2; i++) {
        printf("Student Name: %s\n", students[i].name);
        printf("Roll No: %d\n", students[i].rollNo);
        printf("Marks: %.2f\n\n", students[i].marks);
    }

    return 0;
}

3. 结构体和函数

结构体可以作为函数的参数和返回值,这使得函数可以直接操作复杂的数据结构。

#include <stdio.h>

struct Rectangle {
    int width;
    int height;
};

// 函数计算矩形的面积
int calculateArea(struct Rectangle rect) {
    return rect.width * rect.height;
}

int main() {
    struct Rectangle myRect = {10, 20};
    printf("Area: %d\n", calculateArea(myRect));
    return 0;
}

4. 指向结构体的指针

可以定义指向结构体的指针,通过指针访问结构体成员时使用->运算符。

#include <stdio.h>

struct Point {
    int x;
    int y;
};

int main() {
    struct Point p1 = {10, 20};
    struct Point *ptr = &p1; // 指针ptr指向p1

    printf("Point: (%d, %d)\n", ptr->x, ptr->y); // 通过指针访问

    return 0;
}

回到顶部

9. 文件处理

1. 文件的打开与关闭、读写

#include <stdio.h>

int main() {
    // 写入文件
    FILE *fileWrite = fopen("example.txt", "w");  // 打开文件以写入模式
    if (fileWrite == NULL) {
        perror("Error opening file for writing");  // 检查文件是否成功打开
        return 1;
    }

    // 向文件写入两行文本
    fprintf(fileWrite, "Hello, this is a sample text.\n");
    fprintf(fileWrite, "Writing to a file in C is easy!\n");

    fclose(fileWrite);  // 关闭文件

    // 读取文件
    FILE *fileRead = fopen("example.txt", "r");  // 再次打开同一个文件以读取模式
    if (fileRead == NULL) {
        perror("Error opening file for reading");  // 检查文件是否成功打开
        return 1;
    }

    printf("Contents of the file:\n");

    char buffer[100];
    // 逐行读取文件内容并打印到控制台
    while (fgets(buffer, sizeof(buffer), fileRead) != NULL) {
        printf("%s", buffer);
    }

    fclose(fileRead);  // 关闭文件

    return 0;
}

2. 文件与流

在C语言中,文件是通过指向FILE类型的指针来操作的。FILE是C标准库中定义的一个结构体,用于表示一个流(stream)。

#include <stdio.h>

int main() {
    FILE *filePtr;

    filePtr = fopen("example.txt", "w"); // 打开文件用于写入
    if (filePtr == NULL) {
        printf("Error opening file!\n");
        return 1;
    }

    // 文件操作代码(如写入文件)...

    fclose(filePtr); // 关闭文件

    return 0;
}

3. 文本和二进制模式

文件可以以文本模式或二进制模式打开。文本模式用于处理文本文件,二进制模式用于处理二进制数据或非文本文件。

#include <stdio.h>

int main() {
    FILE *filePtr;
    filePtr = fopen("example.txt", "w");
    if (filePtr != NULL) {
        fprintf(filePtr, "Hello, World!\n");
        fclose(filePtr);
    } else {
        printf("Failed to open the file.\n");
    }

    return 0;
}

4. 读写文件

使用 fprintf, fscanf, fputs, fgets 等函数可以在文件中进行读写操作。

#include <stdio.h>

int main() {
    char buffer[255]; // Buffer to store data
    FILE *filePtr = fopen("example.txt", "r");
    if (filePtr == NULL) {
        printf("Error opening file!\n");
        return 1;
    }

    while (fgets(buffer, 255, filePtr) != NULL) {
        printf("%s", buffer);
    }

    fclose(filePtr);
    return 0;
}

5. 使用freadfwrite进行二进制文件操作

#include <stdio.h>

int main() {
    int numbers[] = {1, 2, 3, 4, 5}; // 定义一个整型数组
    FILE *filePtr = fopen("binary.dat", "wb"); // 以二进制写入模式打开文件
    if (filePtr == NULL) { // 检查文件是否成功打开
        printf("Error opening file!\n"); // 如果打开失败,输出错误消息
        return 1; // 返回非零值表示出现错误
    }

    // 将整型数组写入到文件中
    fwrite(numbers, sizeof(int), 5, filePtr);
    
    fclose(filePtr); // 关闭文件

    int buffer[5]; // 定义另一个整型数组,用于存储从文件中读取的数据

    filePtr = fopen("binary.dat", "rb"); // 重新以二进制读取模式打开文件
    fread(buffer, sizeof(int), 5, filePtr); // 从文件中读取数据到数组中
    fclose(filePtr); // 关闭文件

    // 循环遍历数组并打印每个元素
    for (int i = 0; i < 5; i++) {
        printf("%d ", buffer[i]);
    }
    printf("\n"); // 输出换行符

    return 0; // 返回0表示程序正常结束
}

回到顶部

其他书籍

Image Description

数组

C语言中的数组是一种非常重要的数据结构,以下是您需要掌握的关于C语言数组的基本知识:

  • 数组的定义:在C语言中,数组是一组相同数据类型的元素的集合,这些元素存储在连续的内存位置上。数组的定义包括数据类型和数组的名称,例如:int myArray[5]; 定义了一个包含5个整数的数组。

  • 数组元素的访问:数组中的元素可以通过索引访问,索引从0开始。例如,myArray[0] 是数组中的第一个元素,myArray[1] 是第二个元素,以此类推。

  • 数组的大小:数组的大小是指数组中包含的元素数量。在定义数组时,需要指定数组的大小,如int myArray[5]; 中的5。数组的大小是固定的,不能在运行时改变。

  • 数组的初始化:可以在定义数组时初始化数组元素,也可以在后续的代码中进行初始化。例如:

int myArray[5] = {1, 2, 3, 4, 5};
  • 数组的遍历:可以使用循环结构(例如for循环)来遍历数组的元素,对每个元素进行操作。

  • 多维数组:C语言支持多维数组,例如二维数组和三维数组。这些数组在内存中以类似于表格或矩阵的方式组织。

  • 数组和指针:数组名本质上是一个指向数组第一个元素的指针。这意味着可以使用指针操作来访问和修改数组元素。

  • 数组的限制:在C语言中,数组没有内置的边界检查,因此需要小心防止数组越界访问,这可能导致程序崩溃或不可预测的行为。

  • 数组作为函数参数:可以将数组传递给函数,作为函数参数。通常,传递数组时需要传递数组的大小,以便函数可以正确地处理数组。

  • 动态分配数组:C语言还支持动态分配内存来创建数组,这允许在运行时根据需要分配和释放内存。

这些是关于C语言中数组的基本知识。深入理解这些概念将有助于您更有效地使用和操作数组以解决各种编程问题。

函数

  • 函数定义:了解如何定义C函数,包括函数名称、参数列表和返回类型。函数的定义通常遵循以下形式:
返回类型 函数名(参数列表) {
    // 函数体
}
  • 函数原型:了解函数原型的重要性,原型提供了函数的声明,以便编译器知道函数的名称、参数类型和返回类型。函数原型通常在函数调用之前出现。
返回类型 函数名(参数列表); // 函数原型
  • 函数调用:学会如何调用函数,将实际参数传递给函数,并接收返回值(如果有的话)。

  • 参数传递:了解C语言中的参数传递方式,包括传值(按值传递)和传引用(按引用传递)。

  • 返回值:理解如何使用return语句从函数中返回值。函数可以返回一个值,也可以不返回(使用void类型)。

  • 函数作用域:了解函数作用域,包括局部变量和全局变量的概念,以及函数内外变量的可见性。

  • 递归函数:掌握如何编写递归函数,即调用自身的函数,以解决适合递归解决的问题。

  • 函数指针:了解函数指针的概念,它们允许您在运行时动态选择要调用的函数。

  • 内联函数:了解内联函数,它们允许将函数的代码嵌入到调用点,以提高执行效率。

  • 标准库函数:熟悉C标准库中提供的常见函数,如printf、scanf、strlen等,以及它们的用法。

  • 函数参数传递方式:理解参数传递的方式,包括值传递、指针传递和引用传递,以及它们的区别。

  • 可变参数函数:了解如何编写可变参数函数,使用stdarg.h头文件中的宏来处理不定数量的参数。

  • 函数错误处理:学习如何处理函数中可能出现的错误,如返回错误码、抛出异常等。

这些知识点将帮助您有效地使用C语言中的函数来组织和管理代码。在编写C程序时,函数是模块化和重用代码的重要工具。

⚠️ **GitHub.com Fallback** ⚠️