第一部分
1. 数组的概念
一维数组是文件夹,二维数组是书架
指针是存放地址信息的文件
数组是一组相同类型元素的集合
• 数组中存放的是1个或者多个数据,数组元素个数不能为0。
• 数组中存放的多个数据,类型是相同的。
2. 一维数组的创建和初始化
01-数组的创建
存放在数组的值被称为数组的元素,数组在创建的时候可以指定数组的大小和数组的元素类型。
02-数组的初始化
数组在创建的时候,我们需要给定⼀些初始值,这种就称为初始化。
03-数组的类型
数组也是有类型的,数组算是⼀种自定义类型,去掉数组名留下的就是数组的类型。
3. 一维数组的使用【核心】
⼀维数组可以存放数据,存放数据的目的是对数据的操作
01-数组下标【下标引用操作符】
C语言规定数组是有下标的,下标是从0开始的,
假设数组有n个元素,最后⼀个元素的下标是n-1,下标就相当于数组元素的编号。
在C语言中数组的访问提供了⼀个操作符 [ ] ,这个操作符叫:下标引用操作符
02-数组元素的打印
使用for循环产生元素的下标,使用下标访问即可
03-数组的输入
使用for循环产生元素的下标,使用下标访问即可
4. 一维数组在内存中的存储
从输出的结果我们分析,数组随着下标的增长,地址是由小到大变化的,
并且我们发现每两个相邻的元素之间相差4(因为⼀个整型是4个字节)。
所以我们得出结论:数组在内存中是连续存放的。
5. sizeof 计算数组元素个数
sizeof 中C语言是⼀个关键字,是可以计算类型或者变量大小的,
其实 sizeof 也可以计算数组的大小。
这里输出的结果是40,计算的是数组所占内存空间的总大小,单位是字节。
【一维数组的综合应用】
#include <stdio.h>
int main()
{
int score[10] = { 0 };//创建并初始化数组
printf("请存入数据:");
int i = 0;
for (i = 0; i < 10; i++)
{
scanf("%d", &score[i]);
//变量前面必须加上& 运算符(指针变量除外),因为 scanf() 传递的不是值,而是地址
//[]是下标引用操作符,说明数组元素的地址,即存储空间所在位置
}
printf("存入的数据为:\n");
for (i = 0; i < 10; i++)
{
printf("score[%d]=%d &score[%d]=%p\n", i, score[i], i, &score[i]);
//数组的访问,score[i]访问数组中的值
//%p为地址
}
int sz = sizeof(score) / sizeof(score[0]);//求数组中元素的个数
printf("存入的数据有%d个", sz);
return 0;
}
第二部分
6. 二维数组的创建
二维数组的数组元素是一维数组
三维数组的数组元素是二维数组
n维数组的数组元素是(n-1)维数组
7. 二维数组的初始化
在创建变量或者数组的时候,给定⼀些初始值,被称为初始化。
那二维数组如何初始化呢?像⼀维数组⼀样,也是使用大括号初始化的。
对于数组的初始化部分 ‘= {0}’,它将数组的所有元素初始化为 ‘0’。这是一种常见的初始化方法,用于确保数组中的所有元素都从一个已知的值开始,避免任何未定义的行为,因为未初始化的数组可能包含垃圾值。
01-按照行初始化【使用大括号,而不是小括号】
02-初始化时省略行,但是不能省略列
关于省略行数的问题:
-
静态分配的数组:在静态或全局数组中,你不能省略行数。编译时必须知道数组的完整大小,以便为其分配内存。因此,行数和列数都是必需的。
-
局部自动数组:在函数内部声明的自动数组同样需要行数和列数的完整定义。
-
动态分配的数组:只有在使用动态内存分配(例如使用指针和 ‘malloc’)时,你才能在某种意义上“省略”行数。但实际上,你是在创建一个指针数组,每个指针指向一行。
-
特殊情况:在某些特殊情况下,比如初始化时,你可以省略第一维度的大小(行数),因为编译器可以根据初始化的元素数量自动推断出来。例如:-
int Arr[][max_column] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}};
在这种情况下,编译器可以从提供的初始化值中推断出行数。
总之,在大多数情况下,二维数组在声明时需要指定行数和列数。省略行数通常是不允许的,除非在某些特定的上下文中(例如具体的初始化场景)。
8. 二维数组的使用【核心】
C语言规定,二维数组的行是从0开始的,列也是从0开始的
核心:使用for循环,产生二维数组的行列下标,使用下标访问二维数组
9. 二维数组在内存中的存储
二维数组中的每个元素都是连续存放
注意:二维数组的数组元素是一维数组
【二维数组的综合应用】
#include <stdio.h>
enum Array_2D//枚举必须在最前面,且不能以数字开头
{
max_row = 4,
max_column = 3
};
void StoreDate(int (*xy)[max_column])
{
int i = 0;
for (i = 0; i < max_row; i++)
{
int j = 0;
for (j = 0; j < max_column; j++)
{
if (scanf("%d", *(xy + i) + j) != 1)
{
printf("error\n");
return;
}
//编程习惯,检查scanf返回值的有效性
}
}
}
void PrintDate(int (*xy)[max_column])
{
int i = 0;
for (i = 0; i < max_row; i++)
{
int j = 0;
for (j = 0; j < max_column; j++)
{
//printf("xy[%d][%d]=%d &xy[%d][%d]=%p \n", i,j,xy[i][j],i,j,&xy[i][j]);
//printf("%d ", xy[i][j]);
printf("%d ", *(*(xy + i) + j));
}
printf("\n");
}
}
int main()
{
int Arr[max_row][max_column] = { 0 };//不可省略行列,否则栈堆将被破坏
printf("存入数据:");
StoreDate(Arr);
//数组名一般情况下是数组首元素的地址,除去sizeof()与&arr
//二维数组的数组元素是一维数组,故Arr在传参时,传递的是一维数组整个数组的地址
//数组的地址需要使用数组指针来接收
printf("存入的数据为:\n");
PrintDate(Arr);
return 0;
}
第三部分
存储器 int mid=0
计数器int count =0
状态器int flag=1
10. C99中的变长数组
在后面的“动态内存管理”会具体学习为数据分配内存空间
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);//根据输⼊数值确定数组的⼤⼩
int arr[n];
int i = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
}
for (i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
11. 数组练习
练习1:多个字符从两端移动,向中间汇聚
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
//定义两个字符数组,存放显示的数据
// 关键:使用下标访问
char show[]="My wife will win CET-6";
char cover[]="######################";
int left = 0;
size_t right = strlen(cover) - 1;//减去字符串的结束标识符
while (left <= right)
{
cover[left] = show[left];
cover[right] = show[right];
printf("%s\n", cover);
Sleep(1000);
system("cls");
left++;
right--;
}
printf("%s\n", cover);
return 0;
}
练习2:二分查找/折半查找【原生态数据库】(注意区分于“猜数字游戏”)
将杂乱无章的数据使用冒泡排序好,然后使用二分查找
#include <stdio.h>
int main()
{
int store[10] = { 12,56,89,112,664,998,1235,1237,8523,9654 };
int left = 0;
int right = sizeof(store)/sizeof(store[0]) - 1;
int key = 0;
int found = 0;//状态标识符
if (scanf("%d", &key) != 1)
{
printf("error\n");
return;
}
while (left <= right)
{
int mid = (left + right) / 2;
if (store[mid] == key)
{
printf("找到了,下标是%d\n",mid);
found = 1;;
break;//不可使用return,否则程序不会停止
}
else if (store[mid] < key)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
if (!found)
{
printf("找不到\n");
}
return 0;
}