C语言基础-----数组详细解析 持续更新中......

devtools/2025/1/18 18:45:21/

1.在C语言中,我理解的数组类简单划分两大类:

        a.一般数组

        b.字符数组

2.C语言中的数组介绍

2.1.数组的基本概念
(1)数组是一组相同类型的元素的集合。
(2)数组在内存中是连续存储的。

2.2.数组的声明
(1)语法:数据类型 数组名[数组大小];
(2)示例:int arr[5];

2.3.数组的初始化
(1)静态初始化:在声明数组时直接指定初始值。
(2)动态初始化:在声明数组后,通过循环或逐个赋值的方式初始化。

2.4.数组的访问
(1)通过索引访问数组元素。
(2)索引从0开始,到数组大小减1结束。

2.5.数组的操作
(1)遍历数组:使用循环遍历数组的所有元素。
(2)插入元素:在指定位置插入新元素。
(3)删除元素:删除指定位置的元素。
(4)查找元素:查找指定元素在数组中的位置。

2.6.多维数组
(1)二维数组:可以看作是一个表格,有行和列。
(2)三维数组:可以看作是一个立方体,有长、宽、高。

2.7.数组与指针
(1)数组名是指向数组第一个元素的指针。
(2)可以通过指针访问数组元素。

2.8.数组的应用
(1)存储和处理大量数据。
(2)实现数据结构,如栈、队列、链表等。

2.9.1注意事项
(1)数组越界:访问数组时,索引不能超过数组大小减1。
(2)数组大小:数组大小在声明时必须指定,且不能改变。

3.数组核心代码详解

3.1.数组定义与初始化

(1)代码定义

// 一维数组声明与静态初始化
int arr1[5];
int arr2[5] = {1, 2, 3, 4, 5};//声明一维数组 arr1
int arr1[5];
声明一个包含5个整数的数组 arr1。
数组元素的初始值未指定,因此其值是未定义的(通常是垃圾值)。
声明并初始化一维数组 arr2int arr2[5] = {1, 2, 3, 4, 5};
//声明一个包含5个整数的数组 arr2。
数组元素被初始化为 {1, 2, 3, 4, 5}。
二维数组声明与静态初始化// 二维数组声明与静态初始化
int arr3[3][4];
int arr4[3][4] = 
{{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};//声明二维数组 arr3
int arr3[3][4];
声明一个3行4列的二维数组 arr3。
数组元素的初始值未指定,因此其值是未定义的(通常是垃圾值)。//声明并初始化二维数组 arr4
int arr4[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};//声明一个3行4列的二维数组 arr4。
数组元素被初始化为指定的值。
动态数组(使用 malloc)// 动态数组(使用malloc)
int *arr5 = (int *)malloc(5 * sizeof(int));
if (arr5 == NULL) {// 内存分配失败处理perror("Memory allocation failed");exit(EXIT_FAILURE);
}
for (int i = 0; i < 5; i++) 
{arr5[i] = i + 1;
}
free(arr5);
动态分配内存int *arr5 = (int *)malloc(5 * sizeof(int));
使用 malloc 动态分配一个包含5个整数的数组。
malloc 返回一个指向分配内存的指针,类型为 void *,需要显式转换为 int *。
5 * sizeof(int) 计算所需的内存大小。
检查内存分配是否成功if (arr5 == NULL) {// 内存分配失败处理perror("Memory allocation failed");exit(EXIT_FAILURE);
}
检查 malloc 是否成功分配内存。
如果 arr5 为 NULL,表示内存分配失败。
使用 perror 输出错误信息,并使用 exit(EXIT_FAILURE) 终止程序。
初始化动态数组for (int i = 0; i < 5; i++) {arr5[i] = i + 1;
}
使用 for 循环遍历数组并初始化每个元素。
arr5[i] 等价于 *(arr5 + i),表示访问数组的第 i 个元素。
释放动态分配的内存free(arr5);
使用 free 释放之前动态分配的内存。
释放内存后,arr5 指向的内存区域不再有效,不应再访问。/*总结
一维数组:声明和初始化示例。
数组元素的初始值可以未指定或静态指定。
二维数组:声明和初始化示例。
二维数组可以看作是数组的数组。
动态数组:使用 malloc 动态分配内存。
检查内存分配是否成功。
初始化动态数组。
使用 free 释放动态分配的内存。
*/

(2)代码示例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(int argc, const char *argv[])
{// 一维数组声明与静态初始化int arr1[5];int arr2[5] = {1, 2, 3, 4, 5};// 二维数组声明与静态初始化int arr3[3][4];int arr4[3][4] = 
{{1, 2, 3, 4}, {5, 6, 7, 8},{9, 10, 11, 12}};// 动态数组(使用malloc)int *arr5 = (int *)malloc(5 * sizeof(int));if (arr5 == NULL) 
{// 内存分配失败处理perror("Memory allocation failed");exit(EXIT_FAILURE);}for (int i = 0; i < 5; i++) 
{arr5[i] = i + 1;}// 打印一维数组 arr2printf("一维数组 arr2: ");for (int i = 0; i < 5; i++) 
{printf("%d ", arr2[i]);}printf("\n");// 打印二维数组 arr4printf("二维数组 arr4:\n");for (int i = 0; i < 3; i++) 
{for (int j = 0; j < 4; j++) 
{printf("%d ", arr4[i][j]);}printf("\n");}// 打印动态数组 arr5printf("动态数组 arr5: ");for (int i = 0; i < 5; i++) 
{printf("%d ", arr5[i]);}printf("\n");// 释放动态分配的内存free(arr5);return 0;
}

3.2.数组访问

(1)代码定义

访问一维数组元素
int value1 = arr2[0]; // 访问一维数组第一个元素
访问一维数组的第一个元素:
int value1 = arr2[0];
arr2 是一个包含5个整数的数组,初始化为 {1, 2, 3, 4, 5}。
arr2[0] 访问数组的第一个元素,即 1。
将 arr2[0] 的值赋给变量 value1,因此 value1 的值为 1。访问二维数组元素
int value2 = arr4[1][2]; // 访问二维数组第二行第三列元素
访问二维数组的第二个元素(第二行第三列):
int value2 = arr4[1][2];
arr4 是一个3行4列的二维数组,初始化为:
{{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}
}
arr4[1][2] 访问数组的第二个元素(第二行第三列),即 7。
将 arr4[1][2] 的值赋给变量 value2,因此 value2 的值为 7。边界检查示例
int index = 3;
if (index >= 0 && index < 5) {int value3 = arr2[index];
} else {printf("Index out of bounds\n");
}定义索引变量:
int index = 3;
定义一个整数变量 index,并赋值为 3。
边界检查:
if (index >= 0 && index < 5) {int value3 = arr2[index];
} else {printf("Index out of bounds\n");
}
/*使用 if 语句进行边界检查,确保 index 在有效范围内。
index >= 0 && index < 5 确保 index 在 0 到 4 之间(即数组 arr2 的有效索引范围)。
如果 index 在有效范围内:
int value3 = arr2[index]; 访问 arr2 的第 index 个元素,并将其赋值给 value3。
例如,当 index 为 3 时,arr2[3] 的值为 4,因此 value3 的值为 4。
如果 index 不在有效范围内:
printf("Index out of bounds\n"); 输出错误信息,表示索引超出范围。
总结
访问一维数组元素:使用 arr2[0] 访问数组的第一个元素。
将访问的值赋给变量 value1。
访问二维数组元素:使用 arr4[1][2] 访问数组的第二个元素(第二行第三列)。
将访问的值赋给变量 value2。
边界检查:使用 if 语句检查索引是否在有效范围内。
如果索引在有效范围内,访问数组元素并赋值给变量。
如果索引超出范围,输出错误信息。
*/

(2)代码示例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(int argc, const char *argv[])
{// 一维数组声明与静态初始化int arr2[5] = {1, 2, 3, 4, 5};// 二维数组声明与静态初始化int arr4[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};// 访问一维数组第一个元素int value1 = arr2[0];printf("Value1 (arr2[0]): %d\n", value1);// 访问二维数组第二行第三列元素int value2 = arr4[1][2];printf("Value2 (arr4[1][2]): %d\n", value2);// 边界检查示例int index = 3;if (index >= 0 && index < 5) {int value3 = arr2[index];printf("Value3 (arr2[%d]): %d\n", index, value3);} else {printf("Index out of bounds\n");}// 测试超出范围的索引index = 5;if (index >= 0 && index < 5) {int value3 = arr2[index];printf("Value3 (arr2[%d]): %d\n", index, value3);} else {printf("Index out of bounds\n");}return 0;
}

3.3.数组遍历

(1)代码定义

// 遍历二维数组
for (int i = 0; i < 3; i++) 
{for (int j = 0; j < 4; j++)
{printf("%d ", arr4[i][j]);}printf("\n");
}
初始化二维数组:int arr4[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}
};
声明并初始化一个3行4列的二维数组 arr4,值为:{{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 ", arr4[i][j]);}printf("\n");
}/*使用嵌套的 for 循环遍历二维数组 arr4。
外层循环变量 i 从 0 开始,每次递增 1,直到 i 小于 3。
内层循环变量 j 从 0 开始,每次递增 1,直到 j 小于 4。
在每次内层循环中,使用 printf 打印 arr4[i][j] 的值。
内层循环结束后,使用 printf("\n"); 打印一个换行符,使每行输出结束时换行。
外层循环结束后,整个二维数组遍历完成。
总结
遍历一维数组:使用单层 for 循环。
循环变量 i 从 0 到 4,访问并打印 arr2[i] 的值。
使用 printf("\n"); 打印换行符。
遍历二维数组:使用嵌套的 for 循环。
外层循环变量 i 从 0 到 2,表示行。
内层循环变量 j 从 0 到 3,表示列。
在每次内层循环中,访问并打印 arr4[i][j] 的值。
内层循环结束后,使用 printf("\n"); 打印换行符,使每行输出结束时换行。
*/

(2)代码示例

#include <stdio.h>int main() {// 一维数组声明与静态初始化int arr2[5] = {1, 2, 3, 4, 5};// 二维数组声明与静态初始化int arr4[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};// 遍历一维数组printf("一维数组 arr2: ");for (int i = 0; i < 5; i++) 
{printf("%d ", arr2[i]);}printf("\n");// 遍历二维数组printf("二维数组 arr4:\n");for (int i = 0; i < 3; i++) 
{for (int j = 0; j < 4; j++) 
{printf("%d ", arr4[i][j]);}printf("\n");}return 0;
}/*一维数组:arr2 初始化为 {1, 2, 3, 4, 5}。
使用单层 for 循环遍历并打印每个元素。
二维数组:arr4 初始化为指定的二维数组。
使用嵌套的 for 循环遍历并打印每个元素,每行结束后打印换行符。
通过这个示例代码,你可以更好地理解C语言数组的遍历方法。
*/

3.4.数组排序

1. 冒泡排序(Bubble Sort)
代码示例
#include <stdio.h>int main(int argc, const char *argv[]){int arr[] = {64, 25, 12, 22, 11};int n = sizeof(arr) / sizeof(arr[0]);int i, j, temp;printf("原始数组: \n");for (i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");// 冒泡排序算法for (i = 0; i < n - 1; i++) {for (j = 0; j < n - i - 1; j++) {if (arr[j] > arr[j + 1]) {// 交换 arr[j] 和 arr[j + 1]temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}printf("冒泡排序后的数组: \n");for (i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");return 0;
}
代码详解
数组声明与初始化:int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
声明并初始化一个包含5个整数的数组 arr,值为 {64, 25, 12, 22, 11}。
计算数组的长度 n,即数组中元素的数量。
打印原始数组:printf("原始数组: \n");
for (i = 0; i < n; i++) {printf("%d ", arr[i]);
}
printf("\n");
使用 for 循环遍历数组并打印每个元素。
打印原始数组的内容。
冒泡排序算法:for (i = 0; i < n - 1; i++) {for (j = 0; j < n - i - 1; j++) {if (arr[j] > arr[j + 1]) {// 交换 arr[j] 和 arr[j + 1]temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}
}
外层循环:控制遍历的次数。总共需要 n-1 次遍历。
i 从 0 到 n-2。
内层循环:比较相邻的元素并交换它们。
j 从 0 到 n-i-2。
每次内层循环结束后,最大的元素会被“冒泡”到数组的末尾。
比较和交换:
如果 arr[j] 大于 arr[j + 1],则交换这两个元素。
使用临时变量 temp 来交换元素的值。
打印冒泡排序后的数组:printf("冒泡排序后的数组: \n");
for (i = 0; i < n; i++) {printf("%d ", arr[i]);
}
printf("\n");
使用 for 循环遍历排序后的数组并打印每个元素。
打印冒泡排序后的数组的内容。
2. 选择排序(Selection Sort)
代码示例#include <stdio.h>int main(int argc, const char *argv[])
{int arr[] = {64, 25, 12, 22, 11};int n = sizeof(arr) / sizeof(arr[0]);int i, j, minIndex, temp;printf("原始数组: \n");for (i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");// 选择排序算法for (i = 0; i < n - 1; i++) {// 假设当前元素是最小的minIndex = i;// 在未排序部分中找到最小元素for (j = i + 1; j < n; j++) {if (arr[j] < arr[minIndex]) {minIndex = j;}}// 交换找到的最小元素和当前元素temp = arr[minIndex];arr[minIndex] = arr[i];arr[i] = temp;}printf("选择排序后的数组: \n");for (i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");return 0;
}
代码详解
数组声明与初始化:int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
声明并初始化一个包含5个整数的数组 arr,值为 {64, 25, 12, 22, 11}。
计算数组的长度 n,即数组中元素的数量。
打印原始数组:printf("原始数组: \n");
for (i = 0; i < n; i++) {printf("%d ", arr[i]);
}
printf("\n");
使用 for 循环遍历数组并打印每个元素。
打印原始数组的内容。
选择排序算法:for (i = 0; i < n - 1; i++) {// 假设当前元素是最小的minIndex = i;// 在未排序部分中找到最小元素for (j = i + 1; j < n; j++) {if (arr[j] < arr[minIndex]) {minIndex = j;}}// 交换找到的最小元素和当前元素temp = arr[minIndex];arr[minIndex] = arr[i];arr[i] = temp;
}
外层循环:控制遍历的次数。总共需要 n-1 次遍历。
i 从 0 到 n-2。
内层循环:在未排序部分中找到最小元素。
j 从 i+1 到 n-1。
如果 arr[j] 小于 arr[minIndex],则更新 minIndex。
交换:
找到最小元素后,使用临时变量 temp 交换 arr[minIndex] 和 arr[i] 的值。
打印选择排序后的数组:c
printf("选择排序后的数组: \n");
for (i = 0; i < n; i++) {printf("%d ", arr[i]);
}
printf("\n");
使用 for 循环遍历排序后的数组并打印每个元素。
打印选择排序后的数组的内容。
3. 插入排序(Insertion Sort)
代码示例
c
#include <stdio.h>int main(int argc, const char *argv[])
{int arr[] = {64, 25, 12, 22, 11};int n = sizeof(arr) / sizeof(arr[0]);int i, j, key;printf("原始数组: \n");for (i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");// 插入排序算法for (i = 1; i < n; i++) {key = arr[i];j = i - 1;// 将 arr[i] 插入到已排序部分的正确位置while (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j];j = j - 1;}arr[j + 1] = key;}printf("插入排序后的数组: \n");for (i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");return 0;
}
代码详解
数组声明与初始化:int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
声明并初始化一个包含5个整数的数组 arr,值为 {64, 25, 12, 22, 11}。
计算数组的长度 n,即数组中元素的数量。
打印原始数组:printf("原始数组: \n");
for (i = 0; i < n; i++) {printf("%d ", arr[i]);
}
printf("\n");
使用 for 循环遍历数组并打印每个元素。
打印原始数组的内容。
插入排序算法:for (i = 1; i < n; i++) {key = arr[i];j = i - 1;// 将 arr[i] 插入到已排序部分的正确位置while (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j];j = j - 1;}arr[j + 1] = key;
}
外层循环:从第二个元素开始遍历数组。
i 从 1 到 n-1。
插入过程:
key 存储当前要插入的元素 arr[i]。
j 初始化为 i-1,表示已排序部分的最后一个元素。
使用 while 循环将 key 插入到已排序部分的正确位置。
如果 arr[j] 大于 key,则将 arr[j] 向右移动一位。
j 递减,继续比较。
当 arr[j] 小于或等于 key 时,将 key 插入到 arr[j + 1] 的位置。
打印插入排序后的数组:printf("插入排序后的数组: \n");
for (i = 0; i < n; i++) {printf("%d ", arr[i]);
}
printf("\n");
使用 for 循环遍历排序后的数组并打印每个元素。
打印插入排序后的数组的内容。
总结
冒泡排序:通过多次遍历数组,比较相邻元素并交换它们,使最大的元素逐渐“冒泡”到数组的末尾。
时间复杂度为 (O(n^2))。
选择排序:每次从未排序部分中找到最小元素,并将其放到已排序部分的末尾。
时间复杂度为 (O(n^2))。
插入排序:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
时间复杂度为 (O(n^2))。
完整示例代码
以下是包含所有三种排序算法的完整示例代码:#include <stdio.h>int main(int argc, const char *argv[])
{int arr[] = {64, 25, 12, 22, 11};int n = sizeof(arr) / sizeof(arr[0]);int i, j, temp, minIndex, key;printf("原始数组: \n");for (i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");// 冒泡排序算法for (i = 0; i < n - 1; i++) {for (j = 0; j < n - i - 1; j++) {if (arr[j] > arr[j + 1]) {// 交换 arr[j] 和 arr[j + 1]temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}printf("冒泡排序后的数组: \n");for (i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");// 重新初始化数组int arr2[] = {64, 25, 12, 22, 11};n = sizeof(arr2) / sizeof(arr2[0]);printf("原始数组: \n");for (i = 0; i < n; i++) {printf("%d ", arr2[i]);}printf("\n");// 选择排序算法for (i = 0; i < n - 1; i++) {minIndex = i;for (j = i + 1; j < n; j++) {if (arr2[j] < arr2[minIndex]) {minIndex = j;}}temp = arr2[minIndex];arr2[minIndex] = arr2[i];arr2[i] = temp;}printf("选择排序后的数组: \n");for (i = 0; i < n; i++) {printf("%d ", arr2[i]);}printf("\n");// 重新初始化数组int arr3[] = {64, 25, 12, 22, 11};n = sizeof(arr3) / sizeof(arr3[0]);printf("原始数组: \n");for (i = 0; i < n; i++) {printf("%d ", arr3[i]);}printf("\n");// 插入排序算法for (i = 1; i < n; i++) {key = arr3[i];j = i - 1;while (j >= 0 && arr3[j] > key) {arr3[j + 1] = arr3[j];j = j - 1;}arr3[j + 1] = key;}printf("插入排序后的数组: \n");for (i = 0; i < n; i++) {printf("%d ", arr3[i]);}printf("\n");return 0;
}
代码说明:
冒泡排序:原始数组:{64, 25, 12, 22, 11}
排序后的数组:{11, 12, 22, 25, 64}
选择排序:原始数组:{64, 25, 12, 22, 11}
排序后的数组:{11, 12, 22, 25, 64}
插入排序:原始数组:{64, 25, 12, 22, 11}
排序后的数组:{11, 12, 22, 25, 64}


http://www.ppmy.cn/devtools/151626.html

相关文章

【实践】操作系统智能助手OS Copilot新功能测评

一、引言 数字化加速发展&#xff0c;尤其人工智能的发展速度越来越快。操作系统智能助手成为提升用户体验与操作效率的关键因素。OS Copilot借助语言模型&#xff0c;人工智能等&#xff0c;对操作系统的自然语言交互操作 推出很多功能&#xff0c;值得开发&#xff0c;尤其运…

tmux 中鼠标滚动异常:^[[A和^[[B是什么以及如何解决

tmux 中鼠标滚动异常问题及解决方案 在使用 tmux 时&#xff0c;有时我们会遇到一个现象&#xff1a;当尝试使用鼠标滚轮滚动窗口内容时&#xff0c;终端中会出现一串类似 ^[[A^[[A 的字符。这让人困惑&#xff0c;不知道鼠标滚动为什么不起作用&#xff0c;也不清楚这些字符究…

28:CAN总线入门一:CAN的基本介绍

CAN总线入门 1、CAN总线简介和硬件电路1.1、CAN简要介绍1.2、硬件电路1.3、CAN总线的电平标准 2、帧格式2.1、数据帧&#xff08;掌握&#xff09;2.2、遥控帧&#xff08;掌握&#xff09;2.3、错误帧&#xff08;了解&#xff09;2.4、过载帧&#xff08;了解&#xff09;2.5…

中间件 MetaQ

MetaQ&#xff08;全称Metamorphosis&#xff09;是一个高性能、高可用、可扩展的分布式消息中间件&#xff0c;其思路起源于LinkedIn的Kafka&#xff0c;但并不是Kafka的一个Copy。以下是关于MetaQ的详细介绍&#xff1a; 基本特性 • 高性能&#xff1a;具有消息存储顺序写、…

JavaScript语言的数据结构

JavaScript中的数据结构 引言 在编程的世界里&#xff0c;数据结构是处理和组织数据的重要方式。数据结构的选择往往直接影响到程序的性能和可维护性。JavaScript作为一门广泛使用的编程语言&#xff0c;在数据结构的设计和使用上也有其独特的特点。本文将深入探讨JavaScript…

力扣-数据结构-21【算法学习day.92】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;建议灵神的题单和代码随想录&#xff09;和记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关…

信创改造-龙蜥操作系统搭载MySql、Tomcat等服务

龙蜥操作系统 Anolis OS 8 是 OpenAnolis 社区推出的完全开源、中立、开放的发行版&#xff0c;它支持多计算架构&#xff0c;也面向云端场景优化&#xff0c;兼容 CentOS 软件生态。Anolis OS 8 旨在为广大开发者和运维人员提供稳定、高性能、安全、可靠、开源的操作系统服务。…

Apache Nifi 信息泄露漏洞复现(CVE-2024-56512)(附脚本)

免责申明: 本文所描述的漏洞及其复现步骤仅供网络安全研究与教育目的使用。任何人不得将本文提供的信息用于非法目的或未经授权的系统测试。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。 0x01 产品描述: Apache NiFi是一个易于使用、功能强大且可靠的数据…