1.什么是数组?
数组是一组相同数据的集合
2.一维数组初始化
前面我们学习了如何定义一个变量,其中变量是这么定义的 :
int a; //int 数据类型 //变量名
那数组是如何定义的呢? 让我们看下面的代码
int arr[5]={0,1,2,3,4}; //int 数据类型 arr 数组名 //[5]代表里面有五个元素
所以这是一个包含有5个元素的int类型数组;
数组的初始化:
数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)
但是对于下面的代码要区分,内存中如何分配。
1. char arr1[] = "abc"; 2. char arr2[3] = {'a','b','c'};
对于数组的使用我们之前介绍了一个操作符: [] ,下标引用操作符。它其实就数组访问的操作符。 我们来看代码:
# include <stdio.h> int main (void) { int arr[5]={0,1,2,3,4};//数组的完全初始化 }
总结:
- 1.数组是使用下标来访问的,下标是从0开始。
- 2. 数组的大小可以通过计算得到。
int arr[10]; int sz = sizeof(arr)/sizeof(arr[0]);
2.1 一维数组遍历
数组是可以通过下标的方式来遍历,上面已经介绍过了数组的初始化,我们来尝试一下写写代码。
for(int i = 0;i<5;i++) { printf("%d ",arr[i]);//依次访问0-4的所有数组元素 } return 0;
于是这就是数组的一个简单的遍历。
补充:
数组的下标是有范围限制的。 数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。 所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。 C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就 是正确的, 所以程序员写代码时,最好自己做越界的检查。
#include <stdio.h> int main() { int arr[10] = {1,2,3,4,5,6,7,8,9,10}; int i = 0; for(i=0; i<=10; i++) { printf("%d\n", arr[i]);//当i等于10的时候,越界访问了 } return 0; }
二维数组的行和列也可能存在越界。
2.2 冒泡排序
冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。
作为最简单的排序算法之一,冒泡排序给我的感觉就像 Abandon 在单词书里出现的感觉一样,每次都在第一页第一位,所以最熟悉。冒泡排序还有一种优化算法,就是立一个 flag,当在一趟序列遍历中元素没有发生交换,则证明该序列已经有序。但这种改进对于提升性能来
说并没有什么太大作用。
1. 算法步骤
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
2. 动图演示
2.3 代码
#include <stdio.h> int main() { int a, b, temp; int m[10]; for (a = 0; a < 10; a++) { scanf("%d", &m[a]); } for (a = 0; a < 9; a++) { for (b = a + 1; b < 10; b++) { if (m[a] > m[a + 1]) { temp = a[m]; a[m] = a[m + 1]; a[m + 1] = temp; } } } for (a = 0; a < 10; a++) { printf("%d ", m[a]); } return 0; }
3.二维数组
二维数组只是比一维数组多一个维度,可以理解为矩阵。
3.1 二维数组的创建和初始化
创建:
//数组创建 int arr[3][4]; char arr[3][5]; double arr[2][4];
初始化:
int arr[3][4] = {1,2,3,4}; int arr[3][4] = {{1,2},{4,5}}; int arr[][4] = {{2,3},{4,5}};//二维数组如果有初始化,行可以省略,列不能省略
3.2 二维数组的遍历
define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { int arr[3][4] = { {2, 7, 8, 5}, {75, 8, 9, 8}, {26, 37, 99, 9} }; for (size_t i = 0; i < 3; i++) //行 { for (size_t j = 0; j < 4; j++) //列 { printf("%d ", arr[i][j]*2); } printf("\n"); }
4.数组作为函数元素传参
往往我们在写代码的时候,会将数组作为参数传个函数,比如:我要实现一个冒泡排序(这里要讲算法 思想)函数 将一个整形数组排序。
错误的冒泡排序:
#include<stdio.h> void sort(int arr[]); int main() { int i = 0; int rtr[10]={0}; for(i = 0;i<10;i++) { scanf("%d",&rtr[i]); } sort(rtr); for(i = 0;i<10;i++) { printf("%d ",rtr[i]); } return 0; } void sort(int arr[]) { int sz = sizeof(arr)/sizeof(arr[0]); int i,j = 0; for(i = 0;i<sz;i++) { for(j = 0;j<sz-1-i;j++) { if(arr[j]>arr[j+1]) { int temp = arr[j]; arr[j]=arr[j+1]; temp = arr[j]; } } } }
难道数组作为函数参数的时候,不是把整个数组的传递过去?
正确的冒泡排序:
#include<stdio.h> void sort(int arr[],int sz); int main() { int i = 0; int rtr[10]={0}; int sz = sizeof(rtr)/sizeof(rtr[0]); for(i = 0;i<sz;i++) { scanf("%d",&rtr[i]); } sort(rtr,sz); for(i = 0;i<sz;i++) { printf("%d ",rtr[i]); } return 0; } void sort(int arr[],int sz) { int i,j = 0; for(i = 0;i<sz;i++) { for(j = 0;j<sz-1-i;j++) { if(arr[j]>arr[j+1]) { int temp = arr[j]; arr[j]=arr[j+1]; temp = arr[j]; } } } }
数组名是什么?
#include <stdio.h> int main() { int arr[10] = {1,2,3,4,5}; printf("%p\n", arr); printf("%p\n", &arr[0]); printf("%d\n", *arr); //输出结果 return 0; }
如果数组名是首元素地址,那么:
1. int arr[10] = {0}; 2. printf("%d\n", sizeof(arr));
为什么输出的结果是:40?
- 补充: 1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数 组。
- &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。 除此1,2两种情况之外,所有的数组名都表示数组首元素的地址。
5.c99标准的变长数组(补充)
这样的代码会报错吗?
#include<stdio.h> int main() { int n = 5; int arr[n]; }
答案是在C99标准下,并不会;但如果在msvc里面则使用会提示你要使用变量而不是常量。这就是C99标准。