首先:数组:数组是一组相同类型元素的集合
一维数组:存储一串或者一行数据
int arr[10] = {0};
//type_t arr_name [const_n} 形式
tupe_t 是指数组的元素类型 比如一组数都是整型 那么type_t就是 int
arr_name 数组名。可以自己定,一定要相对有意义
const_n 是一个常量表达式用来指定数组的大小,不一定要是数字。
注意:数组创建,在c99标准之前,数组大小只能是常量表达式
c99标准中引入了变长数组的概念。使得数组在使用的时候可以使用变量,但是数组不能初始化。
局部变量存储在栈区,不符值,不初始化是随机值。 这个可以在gcc编译器去体验一下
数组的初始化:创建数组的时候给数组的内容一些合理初始值(比如初始化为0)。
数组初始化用大括号,中间元素用逗号隔开。
//形式:
int arr[10}= {10,2,3,4,5,6,7,8}; //这种数组大小和元素相对应的叫完全初始化
int arr[10] = {1,2,3} ; //这种叫做不完全初始化,剩下的元素都是0
int arr[10] = {0};// 把数组初始化为0,不完全初始化
int arr6[] ;// 不完全类型,错误写法
char arr1[] = “abc" ;// 这个叫省略数组大小的时候,数组必须初始化,数组的大小是根据数组的内容决定的,有几个元素就是多大
//字符串的特殊形式,这种也叫字符串的初始化,因为字符串数组是拿来存字符串的所以可以这样存
char arr2[3]= {'a','b','c'} ,// 上下两种存储的区别
//char arrr1 是中存储了四个元素 a,b,c /0 多了一个字符串的结束标志
char arr2 中只有3个元素 a,b,c
char arr3[10] = {"a",98,"c"} ;// arr2和arr3是一样的,98就是b的acsii码值
[] 为下标引用操作符,,就是数组访问的操作符。
C语言规定,数组的每一个元素都有一个下标,元素的下标是从0开始的。
整个数组大小的求法:sizeof(arr) 数组名和数组第一个元素保存的是数组的地址。
单个数组元素的大小 sizeof(arr[0])。
两者相除就是数组的长度单位,再减1就是数组的最大下标。
ps:为什么不用strlen,strlen是求字符串长度的。
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", arr[5]);//[]下标引用操作符
return 0;
}
运行结果如图:
如何访问到一维数组当中的每一个元素呢
答:使用for循环遍历
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
int sz = sizeof(arr) / sizeof(arr[0]);//数组长度10
//整个数组大小的求法:sizeof(arr) 数组名和数组第一个元素保存的是数组的地址
//单个数组元素的大小 sizeof(arr[0]);
//两者相除就是数组的长度单位,在减1就是数组的最大下标
// strlen是求字符串长度的
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);//什么使用for循环的时候数组的大小可以使用变量, 注意c99规定的是在数组创建的时候,数组大小只能是常量,但是这是在访问元素,下标可以用变量
}
return 0;
}
运行结果:
一维数组在内存中的存放是连续的 随着下标增长,地址是由低到高。
方法:看布局,看每个元素的地址,为了直观看出数组元素在内存中的分布,直接循环打印出元素的地址。
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
int sz = sizeof(arr) / sizeof(arr[0]);//数组长度10
//整个数组大小的求法:sizeof(arr) 数组名和数组第一个元素保存的是数组的地址
//单个数组元素的大小 sizeof(arr[0]);
//两者相除就是数组的长度单位,在减1就是数组的最大下标
// strlen是求字符串长度的
int i = 0;
for (i = 0; i < sz; i++)
{
printf("&arr[%d] == %p\n",i, arr[i]);//什么使用for循环的时候数组的大小可以使用变量, 注意c99规定的是在数组创建的时候,数组大小只能是常量,但是这是在访问元素,下标可以用变量
}
return 0;
}
注明:a是16进制中的10
二维数组:存储一组数据
数组类型 数组名[行数][列数]
a.int arr[3][4] = {{3,4,5,7},{5, 6, 7, 6} ,{1,2,3,5}} 一行一个大括号区分。
b. int arr[3][4] = {1,2,3,4,5,6,7,8,6,7,8,9} 这种初始化方式它会首先一行一行的放满再放下一行 不完全初始化,不够后面补0,单独一行括起来,够就走下一行,不够就补0。
c.int arr[3][4] = {{1,2,3}4,5,6,7,8,6,7,8,9} 这种第一行就补0,不建议,要括就都括 。
二维数组即使初始化了,行可以省略但是列可以省略,理由见下文内存。
int arr[3][4] = {{3,4,5,7},{5, 6, 7, 6} ,{1,2,3,5}};// 一行一个大括号区分
int arr[3][4] = {1,2,3,4,5,6,7,8,6,7,8,9};// 这种初始化方式它会首先一行一行的放满再放下一行 //不完全初始化,不够后面补0,单独一行括起来,够就走下一行,不够就补0
c.int arr[3][4] = {{1,2,3}4,5,6,7,8,6,7,8,9} ;//这种第一行就补0,不建议,要括就都括
二维数组即使初始化了,行可以省略但是列可以省略
[] 为下标引用操作符,,就是数组访问的操作符。
二维数组的元素访问是通过预算所在行数列数的下标来确定的,行数和列数都是从0开始的
二维数组的元素访问直观图:
int main()
{
int arr[3][4] = { {3,4,5,7},{5, 6, 7, 6} ,{1,2,3,5} };
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)//控制行数
{
for (j = 0; j < 4; j++)
{
printf("%d ", arr[i][j]);//控制列数
}
printf("\n");
}
return 0;
}
二维数组在内存中的存储也是连续存储的 一条龙存储
int main()
{
int arr[3][4] = { {3,4,5,7},{5, 6, 7, 6} ,{1,2,3,5} };
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)//控制行数
{
for (j = 0; j < 4; j++)
{
printf("%d ", arr[i][j]);//控制列数
}
printf("\n");
}
//打印地址看内存分布
for (i = 0; i < 3; i++)//控制行数
{
for (j = 0; j < 4; j++)
{
printf("&arr[%d][%d] = %p \n",i,j, &arr[i][j]);//控制列数
}
}
return 0;
}
结果分析:
可以看出,二维数组的内存也是一整块开辟,数组中的每个元素的位置都是相邻的。地址从小到大连续存储。所以可以解释为什么数组的存储中行可以省略,列不可以省略,因为是连续存储,只有知道第一行存放在那个位置,才能知道下一行放在哪里,行里面的元素个数是列决定的。
二维数组的个人理解:二维数组可以看做是每一行当做一个一维数组当做元素的数组
数组的下标是有范围限制的,
数组的下标规定是由0开始,如果有N个元素,最后一个元素是N-1
所以数组下标如果小于0或者大于N-1,就是数组越界访问了,超出了数组合法空间的访问
C语言本身不检查数组的越界,编译器也不一定报错,但是不代表程序没错,自己做越界检查
数组传参,传的是地址,自编函数里面虽然是个参数数组(也可以改为指针)在接收值
但是还是相当于指针所以数组的长度的求法在定义函数的外部求,带到自编函数来求就会产生bug 。所以建议如果自定义函数里面要用到数组的长度的时候,尽量在main函数内求出数组长度作为参数一起传递。
数组名知识补充:
1.sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组
2.&数组名,取的是数组的地址。&数组名,数组名表示整个数组
除了上面两种情况以外,所有的1数组名都表示数组首元素的地址。
总结:数组名表示两种情况,1是整个数组,2表示首元素的地址。但是只有上述两种情况满足1.
(注意事项的解释放在文章冒泡算法初了解中具体看)