前言
一、一维数组的创建和初始化
1.一维数组的创建
数组是一组相同类型元素的集合。
数组的创建方式:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> //数组的创建方式: int main() { int arr[8]; //创建一个整型数组,里面可以放8个整型数据 char ch[10]; //创建一个字符型数组,里面可以放10个数据 return 0; }
注意:
a.C99标准前,数组的大小必须是常量表达式指定
b.C99标准中,引入变长数组的概念,变长数组中允许数组的大小用变量来指定
c.本编译器不支持C99标准中的变长数组
d.变长数组不可以初始化
e.非变长数组是可以初始化的,在创建的时候就可以初始化
2.一维数组的初始化
int main() { int arr1[10] = {1,2,3,4,5,6,7,8,9,10}; //完全初始化:有几个元素就把所有元素初始化 int arr2[10] = {1,2,3,4,5}; //不完全初始化:初始化其中的前几个元素,其余元素的初始值默认为0 //字符串数组的初始化 char ch1[5] = {'a','b',99}; //字符串数组的不完全初始化 char ch2[10] = "abcdef"; //相当于拿7个字符初始化这个数组(因为字符串的结尾是\0),剩余的三个位置相当于默认放的是0 //如果数组初始化了,,可以不指定数组的大小,数组的大小会根据初始化的内容来确定 char ch3[] = "abc"; //ch3里面放了4个字符,a,b,c,\0,但是这个数组的长度为3,\0不计入数组的长度 char ch4[] = { 'a','b','c'}; printf("%s\n", ch3); // ch3中隐藏一个\0 printf("%s\n", ch4); // ch4里面放了abc,之后放的什么不确定,所以会随机打印 //字符串打印\0的时候就会停下来,但是对于ch4来说后面没有\0,所以打印完c会一直往后打印,打印结果的后面会出现随机值 return 0; }
3.一维数组的使用
注意:
// 数组是通过下标来访问的
// 访问数组元素时的[]叫下标引用操作符
//去掉变量名或者数组名,剩下的就是它的类型
//计算变量的大小就是计算它的类型的大小
//计算数组的大小就是计算数组类型的大小
int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; //[]语法形式 // 下标: 0 1 2 3 4 5 6 7 8 9 printf("%d\n", arr[9]); //[]下标引用操作符 int i = 0; int sz = sizeof(arr) / sizeof(arr[0]); //计算数组的大小:40 for (i = 0; i < 10; i++) { //打印数组所有元素 printf("%d ", arr[i]); //下标引用操作符,访问数组时arr[i]可以使用 } //计算变量的大小就是计算它的类型的大小 // int a = 10; // printf("%d\n", sizeof(a)); //计算a变量的大小:4 // printf("%d\n", sizeof(int)); //计算a的类型的大小:4 //计算数组的大小就是计算数组类型的大小 // int arr[10]= { 1,2,3,4,5,6,7,8,9,10 }; 数组的类型是int [10] // printf("%d\n",arr); //计算arr数组的大小:40 // printf("%d\n",int [10]); //计算arr数组类型的大小:40 return 0; }
4.一维数组在内存中的存储
打印数组每个元素的地址
int main() { int arr[10] = { 0 }; int i = 0; int sz = sizeof(arr) / sizeof(arr[0]); for (i = 0; i < sz; i++) { printf("&arr[%d]=%p\n", i, &arr[i]); } }
发现每个数组元素地址相差4,刚好是一个整型长度.所以:
a.数组在内存中是连续存放的
b.随着下标的增长地址是由低到高变化的
通过指针也可以遍历数组所有的元素
pc是什么类型的指针,pc+1就跳过一个什么类型的元素
int main() { int arr[10] = {1,2,3,4,5,6,7,8,9,10}; int i = 0; int sz = sizeof(arr) / sizeof(arr[0]); int* p = &arr[0]; //p是一个整型指针,指向arr[0]的地址 for (i = 0; i < sz; i++) { printf("%p==%p\n", p + i, &arr[i]); //p+1 指的是从p地址跳过一个整型长度 printf("%d\n", *(p + i)); //通过上个操作发现p+i是下标元素的地址 } //char* pc; //pc是char类型的指针 //pc是什么类型的指针,pc+1就跳过一个什么类型的元素 return 0; }
二、二维数组的创建和初始化
1.二维数组的创建
int arr[3][4]; //创建一个二维数组,数组有三行四列,每个元素都是int类型
2.二维数组的初始化
(1)完全初始化
int arr1[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
(2)不完全初始化,第一行放入1,2;第二行放入3,4;第三行放入5,6,其余元素默认为0
int arr2[3][4] = { {1,2},{3,4},{5,6} };
(3)二维数组初始化的时候,行可以省略,但是列不可以省略
因为可以根据里面的大括号判断几行,但是必须表明有几列
int arr3[][4] = { {1,2},{3,4},{5,6} };
3.二维数组的使用
(1)通过下标来访问
(2)行从0开始,列也从0开始
// 0列 1列 2列 3列 // 0行: 1 2 3 4 // 1行: 5 6 7 8 // 2行: 9 10 11 12 int arr5[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
(3)如何定位每个元素?
printf("%d\n", arr5[1][2]); //定位7在1行2列
(4)如何访问二维数组的每个元素?
//打印二维数组每个元素 int i = 0; for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 4; j++) { printf("%-2d ", arr5[i][j]); //%2d 打印两位整数,右对齐,左边补位 //%-2d 打印两位整数,左对齐,右边补位 } printf("\n"); }
4.二维数组在内存中的存储
计算第i行,第j列元素的地址
int main() { int arr[3][4] = { 0 }; int i = 0; int j = 0; for (i = 0; i < 3; i++) { for (j = 0;j < 4; j++) { printf("&arr[%d][%d]=%p\n", i, j, &arr[i][j]); } } }
发现:
(1)看似是多行多列,真正内存中的存储方式也是连续的,第一行放完,放第二行…
(2)数组的起始地址是编译器给的
(3)二维数组地址的行可以省略.列不可以省略,因为连续存储,必须知道列,也就是每行放几个数字,这样才能方程二维数组,而行的话能放几行就放几行
(4)如果把二维数组的每一行看做一个一维数组,那么每一行一维数组也有数组名
arr[0] 就是第一行的数组名
arr[1] 就是第二行的数组名
三、数组越界问题
无论是一维数组还是二维数组:
C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的.
int main() { int arr[10]={ 0 }; int i = 0; for (i = 0; i < 10; i++) { //注意不要越界,不可以等用于10,因为在一些编译器中可能不会提示报错,直接执行错误代码 printf("%d ", arr[i]); } }
四、数组作为函数参数—冒泡排序
注意:往往我们在写代码的时候,会将数组作为参数传个函数.冒泡排序----核心思想:两两相邻的元素进行比较
**题目:**将arr[] = {3,1,5,9,2,4,7,6,8,0}用冒泡排序那升序排序打印结果.
一套冒泡排序----把一个数字放在应该出现的位置上
10个元素要九趟冒泡排序
3,1,5,9,2,4,7,6,8,0 3,1比较之后交换
1,3,5,9,2,4,7,6,8,0 3,5比较之后不需要交换
1,3,5,9,2,4,7,6,8,0 5,9比较之后不需要交换
1,3,5,9,2,4,7,6,8,0 9,2比较之后交换
1,3,5,2,9,4,7,6,8,0 9,4比较之后交换
1,3,5,2,4,9,7,6,8,0 9,7比较之后交换
1,3,5,2,4,7,9,6,8,0 9,6比较之后交换
1,3,5,2,4,9,6,9,8,0 9,8比较之后交换
1,3,5,2,4,9,6,8,9,0 9,0比较之后交换
1,3,5,2,4,9,6,8,0,9
错误设计:
//错误设计: void bubble_sort(int arr[]) { //数组名是数组首元素的地址 int i = 0; int sz = sizeof(arr) / sizeof(arr[0]); //错误的点在这里!!! //sz-1:冒泡排序的趟数 for (i = 0; i < sz - 1; i++) { //一趟冒泡排序的过程 int j = 0; //一趟冒泡排序的过程:10个元素(有九对)比较9次,九个元素比较8次.... for (j = 0; j < sz - 1 - i; j++) { //每进行一趟少一对 if (arr[j] > arr[j + 1]) { int tmp = arr[j]; //交换两个元素 arr[j] = arr[j+1]; arr[j+1] = tmp; } } } } //一套冒泡排序----把一个数字放在应该出现的位置上 // 10个元素要九趟冒泡排序 // 3,1,5,9,2,4,7,6,8,0 3,1比较之后交换 // 1,3,5,9,2,4,7,6,8,0 3,5比较之后不需要交换 // 1,3,5,9,2,4,7,6,8,0 5,9比较之后不需要交换 // 1,3,5,9,2,4,7,6,8,0 9,2比较之后交换 // 1,3,5,2,9,4,7,6,8,0 9,4比较之后交换 // 1,3,5,2,4,9,7,6,8,0 9,7比较之后交换 // 1,3,5,2,4,7,9,6,8,0 9,6比较之后交换 // 1,3,5,2,4,9,6,9,8,0 9,8比较之后交换 // 1,3,5,2,4,9,6,8,9,0 9,0比较之后交换 // 1,3,5,2,4,9,6,8,0,9 int main() { int arr[] = { 3,1,5,9,2,4,7,6,8,0 }; //排序--升序 //冒泡排序----核心思想:两两相邻的元素进行比较 bubble_sort(arr); int i = 0; //排完之后把数组打印一下 for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } return 0; }
发现结果没有按要求排序:
为什么呢?
数组名是数组首元素的地址
但是有两个例外情况:
(1)sizeof(数组名),数组名如果单独放在sizeof内部,这里的数组名表示整个数组,计算的是整个数组的大小
(2)&数组名,这里的数组名表示整个数组,表示的是整个数组的地址
除此之外,遇到的所有的数组名都是数组首元素的地址
下面可以验证一下:
int main() { int arr[10] = { 0 }; printf("%p\n", arr); //数组名是数组首元素的地址 printf("%p\n", arr+1); //数组名的地址+1--------------->跳过数组的一个元素 printf("%p\n", &arr[0]); //数组首元素的地址+1----------->跳过数组的一个元素 printf("%p\n", &arr[0]+1); printf("%p\n", &arr); //取地址数组名 printf("%p\n", &arr+1); // 数组的地址+1---------------->跳过整个数组 }
正确设计
(1)数组在函数写形式函数的时候可以写成数组也可以写成指针的形式
(2)数组在传参的时候,形参的部分不会创建数组,所以void bubble_sort(int arr[],int sz) 中的int arr[]不用写大小,不过写不写都可以
void bubble_sort(int arr[],int sz) { //数组名是数组首元素的地址 int i = 0; //int sz = sizeof(arr) / sizeof(arr[0]); 所以不能在函数内部计算数组的大小,这里计算的是指针的大小,求出来的不是数组的大小不是整个数组的大小 //冒泡排序的趟数 for (i = 0; i < sz-1; i++) { //一趟冒泡排序的过程 int j = 0; for (j = 0; j < sz - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int tmp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = tmp; } } } } //一套冒泡排序----把一个数字放在应该出现的位置上 // 10个元素要九套冒泡排序 // 3,1,5,9,2,4,7,6,8, // 1,3,5,9,2,4,7,6,8, 1.3比较之后交换 // 1,3,5,9,2,4,7,6,8, 3,5比较之后不需要交换 // 1,3,5,9,2,4,7,6,8, 5,9比较之后不需要交换 // 1,3,5,2,9,4,7,6,8 9,2比较之后交换 // 1,3,5,2,4,9,7,6,8 9,4比较之后交换 // 1,3,5,2,4,7,9,6,8 #include<string.h> int main() { int arr[] = {3,1,5,9,2,4,7,6,8,0}; int sz = sizeof(arr) / sizeof(arr[0]); //排序--升序 //冒泡排序----核心思想:两两相邻的元素进行比较 bubble_sort(arr,sz); //数组首元素的地址,整形指针来接收一个整形的地址 //函数拿指针去接收,虽然写成数组的形式,但是实质上是指针int* arr // int i = 0; //排完之后把数组打印一下 for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } return 0; }
总结
今天的内容你是否有收获呢小伙伴们?💕💕
如果哪里写的有问题,欢迎大家帮我指正.
最后,希望友友可以留下关注点赞收藏关注后续内容哦~🥰💕❤️