C语言数组学习笔记
一、数组定义
在C语言中,为统计一类数据,引出数组!
数组的定义形式为:类型说明符 数组名[常量表达式] ,其中:
• (1) 类型说明符:用于明确数组中存储的数据类型,例如int表示存储整型数据,float表示存储浮点型数据 。
• (2) 数组名:类似变量名,用于标识整个数组。它具有以下特性:
◦ 数据类型:数组名代表整个数组这种数据类型,通过sizeof(数组名)可以获取整个数组所占的内存字节数。
◦ 值:数组名代表数组首元素的地址,也是整个数组的起始地址,由于数组在内存中是连续存储的,通过该地址可以访问数组的所有元素。
• (3) 常量表达式:用[]括起来,用于指定数组的长度,即相同类型数据的个数。在定义数组时,[]明确表示定义的是一个数组。判断数据类型的通用方法是去掉变量名(标识符),剩下的部分即为数据类型。
数组大小的计算方式为:数组大小 = sizeof(数据类型) * 数组长度 ,由此可推导出 数组长度 = sizeof(数组名) / sizeof(单个数据类型) 。
二、数组特点
1. 单一性:数组中所有元素的类型必须一致,例如int类型的数组只能存储整型数据。
2. 连续性:数组在内存中开辟的是一块连续的内存空间,这使得数组元素的访问效率较高。
3. 有序性:数组元素按照顺序依次存储,每个元素都有唯一的下标,通过下标可以快速访问对应元素。
三、数组的初始化和赋值
(一)初始化
1. 全部初始化:int a[10] = {1,2,3,4,5,6,7,8,9,10}; ,使用花括号{}将所有初始值列出,依次赋给数组元素。
2. 部分初始化:int a[10] = {1,2,3,4,5}; ,只对前面部分元素赋值,未初始化的元素默认初始化为0。
3. 未初始化:int a[10]; ,此时数组中的元素值为随机值(垃圾值)。
4. 初始化全0数组:
◦ int a[]={}; ,定义时省略数组长度,根据初始化列表为空,编译器会创建一个长度为0的数组。
◦ int a[]={0}; ,定义一个长度为1且元素值为0的数组。
(二)赋值
1. 计算赋值:通过循环计算出一些值并赋值到数组中,示例代码如下:
for (int i = 0; i < len; ++i) {
a[i] = 表达式;
}
2. 键盘输入赋值(动态定义):从键盘读取数据赋值给数组元素,示例代码如下:
for (int i = 0; i < len; ++i) {
scanf("%d", &a[i]);
}
特别注意:在动态定义数组长度时,如int i; scanf("%d", &i); int a[i]; ,i的定义与scanf语句必须在定义数组a之前,否则编译器无法分配空间,会导致报错。
四、数组元素引用
通过 数组名[下标] 的方式引用数组元素,需要注意:
1. 数组下标可能越界,且编译时不会报错(因为没有语法错误),需要程序员在编程过程中仔细检查,避免出现逻辑错误。
2. 下标取值范围是[0,数组长度 - 1] 。
3. 数组长度必须是整型。
4. 定义数组时,数组长度可以省略,但前提是必须进行初始化,实际长度取决于初始化元素的个数,如int[]={1,2} ,若不初始化直接省略长度,编译器无法分配空间,会报错。
5. 数组不能整体赋值,只能对具体元素进行单个操作。
五、经典算法:排序与逆序
(一)选择排序
• 思想:每轮从剩余元素中选最小值,与当前位置交换。
• 步骤:
1. 外层循环控制当前位置i。
2. 内层循环从i+1到末尾找最小值下标j。
3. 交换a[i]与a[j]。
• 代码示例:
for (i=0; i min = i; for (j=i+1; j if (a[j] < a[min]) min = j; } swap(&a[i], &a[min]); } (二)冒泡排序 • 思想:相邻元素两两比较,大的后移(类似气泡上浮)。 • 步骤: 1. 外层循环控制轮数(n-1轮)。 2. 内层循环从0到n-1-i,比较a[j]与a[j+1],逆序则交换。 • 代码示例: for (i=0; i for (j=0; j if (a[j] > a[j+1]) swap(&a[j], &a[j+1]); } } (三)数组逆序 • 思路:首尾元素交换,逐步向中间逼近。 • 代码示例: for (i=0; i temp = a[i]; a[i] = a[n-1-i]; a[n-1-i] = temp; } 七、常见问题与练习 1. 动态定义数组(C99): int n; scanf("%d", &n); // 需在定义前赋值 int a[n]; // 可变长数组 2. 练习场景: ◦ 找出数组中能被3整除的元素。 ◦ 求最大值(“打擂台”法,初始值设为a[0])。 ◦ 数组循环移动(如输入n,将末尾n个元素移到开头)。 3、关键注意事项 • 数组名本质是地址,但sizeof(数组名)返回整个数组大小(非指针长度)。 • 初始化时省略长度需确保有初始值,否则编译报错。 • 排序算法需熟练掌握逻辑与代码实现,可结合流程图辅助理解。 大算法程序: (一)选择排序 选择排序的基本思想是将每个元素与它后面全部元素比较,如果后面存在元素小于它,则换位,每轮小循环都会找出当前轮次最小元素,可实现从低到高排序。示例代码如下: int main(void) { int i = 0; for (i = 0; i < n; ++i) { int j = 0; for (i = 0; i < n; ++i) { return 0; 冒泡排序的核心是当后一元素大于前一元素时进行交换,这样每轮循环的开始元素都是那一轮循环的最小值,从而实现将数组从小到大排序。示例代码如下:
#include
int n;
printf("Input a num:");
scanf("%d", &n);
int a[n];
for (i = 0; i < n; ++i) {
scanf("%d", &a[i]);
}
printf("%d ", a[i]);
}
putchar('\n');
for (i = 0; i < n - 1; ++i) { // 控制位置
for (j = i + 1; j < n; ++j) { // 控制选择合适的数
if (a[i] > a[j]) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
printf("%d ", a[i]);
}
putchar('\n');
}
(二)冒泡排序
#include
int main() {
int a[5] = {2, 3, 5, 8, 4};
int i, j, tmp;
int len = sizeof(a) / sizeof(a[0]);
for (i = 0; i < len - 1; i++) {
for (j = 0; j < len - 1 - i; j++) {
if (a[j] > a[j + 1]) {
tmp = a[j];
a[j] = a[j + 1];
a[j + 1] = tmp;
}
}
}
for (i = 0; i < len; i++) {
printf("%d ", a[i]);
}
}