C语言数组常见操作有哪些关键点?

99ANYc3cd6
预计阅读时长 31 分钟
位置: 首页 C语言 正文

数组的基础概念

  1. 定义与声明

    c语言关于数组的常见操作汇总
    (图片来源网络,侵删)
    • 语法: 数据类型 数组名[数组长度];
    • 说明: 数组在内存中是连续存储的,数组的索引从 0 开始。
    • 示例:
      int numbers[5]; // 定义一个可以存放5个整数的数组
      char name[10];  // 定义一个可以存放10个字符的数组
      float scores[30]; // 定义一个可以存放30个浮点数的数组
  2. 初始化

    • 完全初始化: 在声明时为数组的所有元素赋值。
      int a[5] = {1, 2, 3, 4, 5};
      // 如果省略长度,编译器会自动根据初始化列表的个数确定数组长度
      int b[] = {10, 20, 30}; // b的长度为3
    • 部分初始化: 只为前几个元素赋值,其余元素自动初始化为0。
      int c[5] = {1, 2}; // c[0]=1, c[1]=2, c[2]=0, c[3]=0, c[4]=0
    • 全部初始化为0:
      int d[5] = {0}; // 所有元素都被初始化为0

数组的常见操作

遍历数组

这是最基本也是最重要的操作,即访问数组中的每一个元素。

  • 使用 for 循环 (最常用)

    int arr[] = {10, 20, 30, 40, 50};
    int length = sizeof(arr) / sizeof(arr[0]); // 计算数组长度
    printf("使用 for 循环遍历:\n");
    for (int i = 0; i < length; i++) {
        printf("arr[%d] = %d\n", i, arr[i]);
    }
  • 使用 while 循环

    c语言关于数组的常见操作汇总
    (图片来源网络,侵删)
    int j = 0;
    printf("\n使用 while 循环遍历:\n");
    while (j < length) {
        printf("arr[%d] = %d\n", j, arr[j]);
        j++;
    }

访问与修改元素

通过索引(下标)可以直接访问或修改数组中的元素。

int scores[3] = {88, 92, 75};
// 访问元素
printf("第一个学生的分数是: %d\n", scores[0]); // 输出 88
// 修改元素
scores[2] = 85; // 将第三个学生的分数从75改为85
printf("修改后的第三个学生的分数是: %d\n", scores[2]); // 输出 85

插入元素

插入元素比其他操作复杂,因为数组长度固定,通常需要创建一个新数组或移动现有元素。

  • 在指定位置插入一个元素 (移动后续元素)

    #include <stdio.h>
    int main() {
        int arr[10] = {1, 2, 4, 5, 6}; // 假设数组已使用5个位置
        int length = 5;
        int pos = 2; // 在索引2的位置插入
        int value = 3; // 要插入的值
        // 1. 检查数组是否已满和位置是否合法
        if (length >= 10 || pos < 0 || pos > length) {
            printf("插入失败!\n");
            return 1;
        }
        // 2. 从后向前移动元素,为新元素腾出空间
        for (int i = length; i > pos; i--) {
            arr[i] = arr[i - 1];
        }
        // 3. 插入新元素
        arr[pos] = value;
        // 4. 更新数组长度
        length++;
        // 打印结果
        printf("插入后的数组: ");
        for (int i = 0; i < length; i++) {
            printf("%d ", arr[i]);
        }
        printf("\n");
        return 0;
    }
    // 输出: 插入后的数组: 1 2 3 4 5 6

删除元素

删除元素也需要移动元素来填补空缺。

  • 删除指定位置的元素

    #include <stdio.h>
    int main() {
        int arr[10] = {1, 2, 3, 4, 5, 6}; // 假设数组已使用6个位置
        int length = 6;
        int pos = 2; // 删除索引2的元素
        // 1. 检查位置是否合法
        if (pos < 0 || pos >= length) {
            printf("删除失败!\n");
            return 1;
        }
        // 2. 从前向后移动元素,覆盖被删除的元素
        for (int i = pos; i < length - 1; i++) {
            arr[i] = arr[i + 1];
        }
        // 3. 更新数组长度
        length--;
        // 打印结果
        printf("删除后的数组: ");
        for (int i = 0; i < length; i++) {
            printf("%d ", arr[i]);
        }
        printf("\n");
        return 0;
    }
    // 输出: 删除后的数组: 1 2 4 5 6

查找元素

  • 顺序查找 (适用于无序数组) 从头到尾依次查找,直到找到目标元素或遍历完整个数组。

    int arr[] = {15, 8, 25, 36, 42};
    int target = 25;
    int index = -1; // 假设-1表示未找到
    for (int i = 0; i < 5; i++) {
        if (arr[i] == target) {
            index = i;
            break; // 找到后立即退出循环
        }
    }
    if (index != -1) {
        printf("元素 %d 的索引是: %d\n", target, index);
    } else {
        printf("未找到元素 %d\n", target);
    }
  • 二分查找 (适用于有序数组) 查找效率更高,但要求数组必须是有序的(升序或降序)。

    #include <stdio.h>
    int binarySearch(int arr[], int size, int target) {
        int left = 0;
        int right = size - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2; // 防止溢出
            if (arr[mid] == target) {
                return mid;
            } else if (arr[mid] < target) {
                left = mid + 1; // 在右半部分查找
            } else {
                right = mid - 1; // 在左半部分查找
            }
        }
        return -1; // 未找到
    }
    int main() {
        int arr[] = {2, 5, 8, 12, 16, 23, 38, 56};
        int size = sizeof(arr) / sizeof(arr[0]);
        int target = 16;
        int result = binarySearch(arr, size, target);
        if (result != -1) {
            printf("元素 %d 的索引是: %d\n", target, result);
        } else {
            printf("未找到元素 %d\n", target);
        }
        return 0;
    }

排序数组

排序是数组操作中的核心内容。

  • 冒泡排序 (简单易懂,但效率较低)

    #include <stdio.h>
    void bubbleSort(int arr[], int size) {
        for (int i = 0; i < size - 1; i++) {
            // 每一轮内层循环,都会将最大的元素“冒泡”到最后
            for (int j = 0; j < size - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    // 交换两个元素
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
    int main() {
        int arr[] = {64, 34, 25, 12, 22, 11, 90};
        int size = sizeof(arr) / sizeof(arr[0]);
        bubbleSort(arr, size);
        printf("冒泡排序后的数组: ");
        for (int i = 0; i < size; i++) {
            printf("%d ", arr[i]);
        }
        printf("\n");
        return 0;
    }
  • 选择排序 (思路简单) 每次从未排序的部分找到最小(或最大)的元素,放到已排序部分的末尾。


多维数组

最常见的多维数组是二维数组,可以看作是“数组的数组”。

  1. 定义与初始化

    // 定义一个3行4列的整型二维数组
    int matrix[3][4];
    // 初始化
    int matrix2[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };
    // 部分初始化
    int matrix3[3][4] = {{1}, {5, 6}}; // 第一行 {1,0,0,0}, 第二行 {5,6,0,0}, 第三行 {0,0,0,0}
  2. 访问与遍历 使用双重循环进行遍历,外层循环控制行,内层循环控制列。

    int matrix[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
    // 遍历并打印
    for (int i = 0; i < 3; i++) { // 遍历行
        for (int j = 0; j < 4; j++) { // 遍历列
            printf("%d ", matrix[i][j]);
        }
        printf("\n"); // 每行结束后换行
    }

数组作为函数参数

将数组传递给函数时,传递的是数组首元素的地址,而不是整个数组的副本,这被称为“地址传递”或“引用传递”。

  1. 形参的写法

    • void func(int arr[])
    • void func(int arr[10]) // 方括号中的数字通常被忽略
    • void func(int *arr) // 指针写法,与数组写法等价
  2. 关键点:传递数组长度 由于函数无法知道传入数组的实际长度,所以必须额外传递一个表示数组大小的参数

    #include <stdio.h>
    // 函数声明:接受一个整型数组和它的大小
    void printArray(int arr[], int size);
    int main() {
        int myNumbers[] = {10, 20, 30, 40, 50};
        int size = sizeof(myNumbers) / sizeof(myNumbers[0]);
        printArray(myNumbers, size); // 传递数组名和长度
        return 0;
    }
    // 函数定义
    void printArray(int arr[], int size) {
        printf("函数接收到的数组: ");
        for (int i = 0; i < size; i++) {
            printf("%d ", arr[i]);
        }
        printf("\n");
    }
  3. 数组作为返回值 C语言不允许直接返回一个完整的数组,你可以返回一个指向数组首元素的指针

    #include <stdio.h>
    // 返回一个整型指针
    int* getArray() {
        static int arr[5] = {1, 2, 3, 4, 5}; // 必须是静态变量或全局变量,否则函数返回后内存会被释放
        return arr;
    }
    int main() {
        int *ptr;
        ptr = getArray();
        printf("从函数返回的数组: ");
        for (int i = 0; i < 5; i++) {
            printf("%d ", *(ptr + i)); // 使用指针算术访问
        }
        printf("\n");
        return 0;
    }

字符数组与字符串

在C语言中,字符串通常被实现为字符数组,一个关键的区别是,字符串必须以一个空字符 '\0'

  1. 定义与初始化

    // 方式1: 定义字符数组
    char str1[6] = "Hello"; // 需要额外一个位置给'\0'
    // 方式2: 初始化时省略长度
    char str2[] = "World"; // 编译器自动分配6个字节 (W,o,r,l,d,\0)
    // 方式3: 逐个字符初始化
    char str3[] = {'H', 'i', '\0'}; // 必须手动添加'\0'
  2. 常用字符串函数 (需要包含 <string.h> 头文件)

    • strcpy(dest, src): 复制字符串 srcdest
    • strcat(dest, src): 将字符串 src 拼接到 dest 的末尾。
    • strcmp(str1, str2): 比较两个字符串,返回0(相等)、正数(str1>str2)、负数(str1<str2)。
    • strlen(str): 返回字符串的长度(不包括 '\0')。
    • strchr(str, c): 查找字符 c 在字符串 str 中首次出现的位置。
    • strstr(str1, str2): 查找字符串 str2 在字符串 str1 中首次出现的位置。
    #include <stdio.h>
    #include <string.h>
    int main() {
        char str1[50] = "Hello, ";
        char str2[] = "C Language!";
        // 复制
        strcpy(str1, "Hello, "); // 确保str1足够大
        // 拼接
        strcat(str1, str2);
        printf("拼接后的字符串: %s\n", str1); // 输出: Hello, C Language!
        // 比较
        char a[] = "apple";
        char b[] = "banana";
        int cmp = strcmp(a, b);
        if (cmp < 0) {
            printf("a < b\n");
        }
        // 计算长度
        printf("str1 的长度是: %zu\n", strlen(str1)); // 使用 %zu 打印 size_t 类型
        return 0;
    }

注意事项与常见错误

  1. 数组越界 访问数组索引范围之外的元素是未定义行为,可能导致程序崩溃或数据损坏。

    int arr[5] = {0};
    arr[5] = 10; // 错误!索引5超出了范围 [0, 4]
  2. 忘记计算数组长度 在函数中处理数组时,一定要记得传递数组长度,或者使用 sizeof 在函数外部计算好再传递。

  3. 混淆数组和指针 虽然数组名在多数情况下会“退化”为指向首元素的指针,但它们本质不同。

    • sizeof(arr) 在函数内部得到的是指针的大小(通常是4或8字节),而在外部得到的是整个数组的大小。
    • 数组名是常量指针,不能被赋值。
  4. 字符串忘记 '\0' 如果字符数组没有以 '\0' 使用 printf("%s", str)strlen() 等函数时,会继续读取内存中的后续数据,直到遇到一个 '\0',这会导致不可预测的错误。

  5. 动态内存分配与数组 对于长度在运行时才能确定的数组,应使用动态内存分配:

    • int *arr = (int*)malloc(n * sizeof(int)); // 分配
    • free(arr); // 释放 动态分配的数组在 [] 中使用的方式与静态数组完全相同,但记得在不需要时 free 掉,避免内存泄漏。
-- 展开阅读全文 --
头像
织梦cms管理静态网站
« 上一篇 今天
c语言生成10000个随机数
下一篇 » 今天
取消
微信二维码
支付宝二维码