2.数组
2.1一维数组的创建和初始化
2.1.1数组的创建:数组是一组相同类型元素的集合。
数组的创建方式:
type_t arr_name [counst_n]
type_t是指数组的类型
arr_name是数组的名称
counst_n是一个常量表达式,用来指定数组的大小
数组的创建实例:
int main()
{
int arr[10];
char ch[10];
double data[10];
/*int n = 0;
scanf("%d",&n);
int arr2[n];*/ //这种支持了变长数组的代码只能在支持c99标准的编译器上编译,而且这种数组是不能初始化的
return 0;
}
2.1.2数组的初始化: 数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值。
实例:
int main()
{
int arr1[10] = { 1,2,3,4,5 } //这种初始化称为不完全初始化,在栈区中所储存的为{ 1,2,3,4,5,0,0,0,0,0 }
int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 } //这种初始化称为完全初始化,在栈区中所储存的为{ 1,2,3,4,5,6,7,8,9,10 }
int arr3[] = { 1,2,3,4,5 } //这种初始化也称为不完全初始化,在栈区中所储存的为{ 1,2,3,4,5 }
char ch1[10] = { 'a','b','c' } //这种初始化称为不完全初始化,在栈区中所储存的为{ 'a','b','c',0,0,0,0,0,0,0 }
char ch2[10] = "abc" //这种初始化也称为不完全初始化,在栈区中所储存的为{ 'a','b','c',\0,0,0,0,0,0,0 }这种字符串的结尾为‘\0’,也就是说这个字符串是四位有效字符,而上面的是三位有效字符
return 0;
}
注:数组在创建的时候如果想不指定数组的大小就初始化,数组的元素个数就会根据初始化的内容来确定。
2.1.3一维数组的使用
下标引用操作符[ ],就是数组访问的操作符。
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
int i = 0;
int log = sizeof(arr)/sizeof(arr[0]);
for( i=0; i < log; i++)
{
printf("arr[%d]=%d ",i,arr[i]);
}
return 0;
}
注:数组是使用下标来访问的,下标是从0开始;数组的大小可以通过计算得到。
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
int i = 0;
int log = sizeof(arr)/sizeof(arr[0]);
for( i=0; i < log; i++)
{
printf("arr[%d]=%p\n ",i,&arr[i]); //%p为打印地址
}
return 0;
}
根据结果我们可以分析出,随着数组下标的增长,元素的地址也在有规律的递增,由此可知数组在内存中是连续存放的。
2.2二维数组的创建和初始化
2.2.1二维数组的创建
int main()
{
int arr[3][4];
char ch[3][4];
double dwo[4][3];
return 0;
}
2.2.2二维数组的初始化
int main()
{
int arr[3][4] = { 1,2,2,3,2,2,3,3,6,6,2,3}; //完全初始化
int arr[3][4] = { {1,2,2},{3,2,2},{3,3} }; //不完全初始化,缺少的位置会自动补0
int arr[][4] = { 1,2,2,3,2,2,3,3,6,6,2,3 }; //二维数组在初始化的时候,行可以省略,列不可以省略
char ch[3][4] = { 'a','b','c','d','b','c','d','e','c','d','e','f'};
double dwo[4][3] = { 1.0,2.0,2.2,3.2,2.5,2.3,3.5,3.6,6.8,6.6,2.3,3.9 };
return 0;
}
2.2.3二维数组的使用
二维数组的使用也是通过下标的方式。
int main()
{
int arr1[3][4] = { 1,2,2,3,2,2,3,3,6,6,2,3}; //完全初始化
int arr2[3][4] = { {1,2,2},{3,2,2},{3,3} }; //不完全初始化,缺少的位置会自动补0
int arr3[][4] = { 1,2,2,3,2,2,3,3,6,6,2,3 }; //二维数组在初始化的时候,行可以省略,列不可以省略
char ch[3][4] = { 'a','b','c','d','b','c','d','e','c','d','e','f'};
double dwo[4][3] = { 1.0,2.0,2.2,3.2,2.5,2.3,3.5,3.6,6.8,6.6,2.3,3.9 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
printf("%c ", ch[i][j]); //arr1[i][j],arr2[i][j],arr3[i][j],ch[i][j],dwo[i][j](%fl)
}
printf("\n");
}
return 0;
}
2.2.4二维数组在内存中的存储
打印每个元素的地址。
int main()
{
int arr1[3][4] = { 1,2,2,3,2,2,3,3,6,6,2,3 }; //完全初始化
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
printf("%p ", &arr1[i][j]);
printf("\n");
}
}
return 0;
}
因为内存的地址是以字节为单位进行储存的,所以通过打印的结果我们可以分析到,其实二位数组在内存中也是连续存储的。
2.2.5数组越界
数组的下标是有范围界限的,数组的下标规定也是从0开始的,如果有n个元素,最后一个元素的下标既是n-1;所以数组的下标小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。但c语言本身是不做数组下标越界检查的,编译器也不一定会报错,但是编译器不报错并不意味着程序就是正确的。
int main()
{
int arr1[3][4] = { 1,2,2,3,2,2,3,3,6,6,2,3 }; //完全初始化
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", arr1[i][j]);
}
printf("\n");
}
return 0;
}
这里不难发现 j 大于了二维数组的列数,打印结果如下:
可以发现程序并没有报错,但是发生了越界访问。
解释图:
二维数组的初始化为3行4列,但是调用的是3行5列,所以打印的时候数组每一行最后的列,会自动的往后打印一位,如上图。
2.3.数组作为函数参数
在写代码的时候,我们往往会将数组作为参数传给函数,例如下列的冒泡程序。
//数组传参的时候,有两种写法:1.数组 2.指针;形参是数组的形式
void bubble_sort(int arr[],int sz)
{
//趟数:sz-1
int i = 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;
}
}
}
}
//冒泡数组的核心思想是两个相邻的元素进行比较
//一趟冒泡排序让一个数据来到他最终应该出现的位置
int main()
{
//数组
//把数组的数据排成升序
int arr[] = { 9,2,5,4,3,6,2,1 };
int sz = sizeof(arr) / sizeof(arr[0]);
//冒泡排序的算法,对数组进行排序
bubble_sort(arr,sz); //传参的时候数组名实质上是:数组首元素的地址
int c = 0;
for ( c = 0; c < sz; c++)
{
printf("%d ", arr[c]);
}
printf("\n");
return 0;
}