数组

5.1 定义

数组是一种数据结构,用于存储多个相同数据类型的值
格式是:数据类型 数据名 [长度]

特点:

  1. 连续的空间
  2. 一旦定义后长度不可变

5.2 数组的初始化

定义数组的时候,第一次给数组赋值
若省略长度,则编译器根据初始化列表的元素个数自动确定数组长度
若不省略长度,则初始化时不得超过该长度
没有定义的部分默认为 0/ 0.0/ '\0'/ NULL(整数,浮点数,字符,字符串)

int arr [5] = {4,6,1,9,4};

5.3 元素访问

5.3.1 索引

从0开始,连续+1,不间断

5.3.2 获取

变量 = 数组名[索引]

int arr [5] = {4,6,1,9,4};
int num1 = arr[2];			//获取第三个数,即1

5.3.3 修改

数据名[索引] = 数据值

int arr [5] = {4,6,1,9,4};
arr[3] = 8;					//修改第四个元素为8

5.4 遍历

依次获取数组中的每一个元素

for(int i=0; i<5; i++){
	printf("%d\n", arr[i]);
}

5.5 内存中的数组

printf("%d\n",arr[2]);
printf(*(arr + 2));

5.6 数组的长度

int len = sizeof(arr) / sizeof(arr[0]);

len即为数据的个数

5.7 数组的算法题

一定要自己动手写!!!

5.7.1 求最值

已知一个整数数组,找出数组中的最大值并打印在控制台
例:已知数组元素为 {33, 5, 22, 44, 55}

#include<stdio.h>
int main(){
    int arr[] = {33,5,22,44,55};
    int max = arr[0];
    int len = sizeof(arr) /sizeof(arr[0]);
  
    for(int i = 1; i < len; i++){
        if(arr[i] > max){
            max = arr[i];
        }
    }
    printf("%d\n",max);
  
    return 0;
}

思路:利用第三方变量储存数组里面的第一个值,再依次进行比较,将较大的数储存在变量里面,最后打印

5.7.2 数组求和(基础)

生成10个1~100之间的随机数存入数组

  1. 求出所有数据的和
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

int main(){
    //定义数组
    int arr[10];
    int len = sizeof(arr) / sizeof(arr[0]);
    //生成随机数
    srand(time(NULL));
  
    for(int i = 0; i < len; i++){
        int num = rand() % 100 + 1;
        //把随机数存入数组
        arr[i] = num;
    }
    /* 验证是否成功生成随机数的代码
    for(int i = 0; i < len; i++){
        printf("%d\n",arr[i]);
    }
    */
    //求和数据
    int sum = 0;
    for(int i = 0; i < len; i++){
        sum += arr[i];
    }
    //输出求和
    printf("%d\n",sum);
    return 0;
}

5.7.3 数组求和,求平均数,统计

生成10个1~100之间的随机数存入数组,且不能重复

  1. 求出所有数据的和;
  2. 求所有数据的平均数;
  3. 统计有多少个数据比平均数少;
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

int if_same(int arr[], int len, int num);

int main(){
  
    //定义数组
    int arr[10];
    int len = sizeof(arr) / sizeof(arr[0]);
  
    //生成随机数
    srand(time(NULL));
  
    for(int i = 0; i < len;){
        int num = rand() % 100 + 1;
        //存入之前,先做判断
        int flag = if_same(arr, len, num);
        if(!flag){
            arr[i] = num;//赋值
            i++;
        }   
    }
    // 打印所有随机数的代码
    printf("numbers:");
    for(int i = 0; i < len; i++){
        printf("%d ",arr[i]);
    }
    printf("\n");
  
    //求和数据
    int sum = 0;
  
    for(int i = 0; i < len; i++){
        sum += arr[i];
    }
  
    //输出求和
    printf("sum:%d\n",sum);
  
    //求平均数
    int avg = sum / len;
  
    //打印平均数
    printf("average:%d\n",avg);
  
    //统计有几个数字比平均数小
    int num1 = 0;
    for(int i = 0; i < len; i++){
        if(arr[i] < avg){
            num1++;
        }
    }
    //输出小于平均数的个数
    printf("The number of numbers smaller than the average:%d\n",num1);
  
}

//判断num是否在数组中存在
//若存在,返回1
//若不存在,返回0
int if_same(int arr[], int len, int num){
    for(int i = 0; i < len; i++){
        if(arr[i] == num){
            return 1;
        }
    }
    return 0;
}

这个程序以时间生成随机数,所以你在一秒钟之内运行多次程序后会发现随机的数是一样的

5.7.4 反转数组

键盘录入5个数据并存入数组

  1. 遍历数组
  2. 反转数组
  3. 再次遍历
#include<stdio.h>

void printArr(int arr[5], int len);

int main(){
    //定义数组
    int arr[5];
    int len = sizeof(arr) / sizeof(int);
  
    //键盘录入
    for(int i = 0; i < len; i++){
        printf("Please write the number %d:", i+1);
        scanf("%d", &arr[i]);
    }

    //打印数组
    printf("The numbers:\n");
    printArr(arr, len);

    //反转数组
    int i = 0;
    int j = len - 1;
    while(i < j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
        i++;
        j--;
    }

    //打印数组
    printf("The numbers:\n");
    printArr(arr, len);

    return 0;

}

//打印程序函数
void printArr(int arr[5], int len){
    for(int i = 0; i < len; i++){
        printf("%d\n", arr[i]);
    }

}

在Microsoft Visual Studio 2022中,scanf()可能被视为不安全的写法,可将其替换为scanf_s()

5.7.5 打乱数组

定义一个数组,存入1~5
打乱数组中所有数据的顺序

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

int main(){
    //定义数组
    int arr[5] = {1,2,3,4,5};
    int len = sizeof(arr) / sizeof(arr[0]);

    //打印数组
    printf("numbers:");
    for(int i = 0; i < len; i++){
        printf("%d ",arr[i]);
    }

    //生成随机数
    srand(time(NULL));

    //随机交换
    for (int i = 0; i < len; i++){
        int index = rand() % len;
        //交换
        int temp = arr[i];
        arr[i] = arr[index];
        arr[index] = temp;   
    }
  
    //打印数组
    printf("\n");
    printf("numbers:");
    for(int i = 0; i < len; i++){
        printf("%d ",arr[i]);
    }

    return 0;
}

5.8 内存分配方式

  • 静态数组

    内存在编译时分配(即在栈上分配内存)
    数组的大小必须在编译时确定,定义后大小不能更改

    例如:

    int arr[10];  // 静态数组,大小为10,编译时确定
    
  • 动态数组

    内存在运行时通过堆(heap)动态分配
    可以根据需求在运行时确定数组的大小,并且可以随时重新调整大小

    • 例如:

      int* arr = (int*)malloc(10 * sizeof(int));  // 动态数组,使用malloc分配10个元素的空间
      

5.8.1 内存管理

  • 静态数组

    内存由编译器自动管理,当数组超出其作用范围时(如函数结束后),内存自动释放。
    内存管理比较简单,不需要手动释放。

  • 动态数组

    需要手动管理内存,分配的内存必须在使用完后手动释放,否则会造成内存泄漏。
    释放内存时使用 free()函数,例如:

    free(arr);  // 手动释放内存
    

5.8.2 大小调整

  • 静态数组

    大小固定,不能在运行时调整。

    例如:

    int arr[10];  // 无法在运行时调整大小
    
  • 动态数组

    可以在运行时调整大小,常通过 realloc()函数重新分配内存空间。

    例如:

    arr = (int*)realloc(arr, 20 * sizeof(int));  // 调整动态数组大小为20
    

5.8.3 性能与效率

  • 静态数组:由于在栈上分配内存,栈的访问速度较快,性能较高。
    适合较小的数组(因为栈的空间有限),如函数局部数组。
  • 动态数组:在堆上分配内存,内存管理更灵活,但分配和释放内存的开销较大。
    适合需要存储大量数据的情况。

5.8.4 使用场景

  • 静态数组

    适用于数组大小已知且不需要在运行时调整的场景,常用于局部变量或程序生命周期固定的场景。

  • 动态数组

    适用于数组大小不确定或需要根据用户输入、文件数据等动态改变的场景。

5.8.5 代码示例

5.8.5.1 静态数组:

#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};  // 静态数组
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}

5.8.5.2 动态数组:

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

int main() {
    int* arr = (int*)malloc(5 * sizeof(int));  // 动态数组
    for (int i = 0; i < 5; i++) {
        arr[i] = i + 1;
        printf("%d ", arr[i]);
    }
    free(arr);  // 释放内存
    return 0;
}

5.8.6 总结

  • 静态数组:固定大小、在栈上分配、内存管理简单。
  • 动态数组:灵活调整大小、在堆上分配、需要手动管理内存。