大家好,又见面了,我是你们的朋友全栈君。
数组是一组相同类型元素的集合。 数组的创建方式:
type_t arr_name [const_n];
//type_t 是指数组的元素类型
//const_n 是一个常量表达式,用来指定数组的大小
数组创建的实例:
//代码1
int arr1[10];
char arr2[10];
float arr3[1];
double arr4[20];
//代码2
//用宏定义的方式
#define X 3
int arr5[X];
//代码3
//错误使用
int count = 10;
int arr6[count];//数组时候可以正常创建?
注:数组创建, [] 中要给一个常量才可以,不能使用变量。可以直接用常量,或者使用宏定义。
数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)。 看代码: 1.
int arr1[5] = {
1,2,3,4,5};
初始化后各元素的值
int arr2[6] = {
1,2,3};
初始化后各元素的值
int arr3[] = {
1,2,3,4};
初始化后各元素的值
char arr5[] = {
'a','b','c'};
初始化后各元素的值
6.(1)
char arr6[] = "abcdef";
初始化后各元素的值
6.(2)
char arr6[6] = "abcdef";//注意数组大小和最后一项的差别
!!这样初始化是有问题的,因为无法正常读取字符串的结束标志('\0'),导致字符串的长度和内容不能得知!!
char arr7[6] = "zxc";
初始化后各元素的值
结论
在内存中的存储
[ ] ,下标引用操作符。它其实就数组访问的操作符。 我们来看代码:
#include <stdio.h>
int main()
{
int arr[10] = {
0 };//数组的不完全初始化
//计算数组的元素个数
int sz = sizeof(arr) / sizeof(arr[0]);
//对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以:
int i = 0;//做下标,此时可以是变量
for (i = 0; i < 10; i++)
{
arr[i] = i;
}
//输出数组的内容
for (i = 0; i < 10; ++i)
{
printf("%d ", arr[i]);
}
return 0;
}
注意:
sizeof()
操作符用于取长度,以字节为单位。sizeof(数组名)
即求的时整个数组的大小。sizeof(首元素)
即求数组单个元素大小。用0下标,是因为数组至少存在一个有效元素,所以0下标永远存在。sizeof(arr)/sizeof(arr[0])
这种方式。先看代码吧:
#include <stdio.h>
int main()
{
int arr[10] = {
0 };
int i = 0;
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i)
{
printf("&arr[%d] = %p\n", i, &arr[i]);
}
return 0;
}
输出的结果如下:
仔细观察输出的结果,可知随着数组下标的增长,元素的地址,也在有规律的递增。 由此可以得 出结论:数组在内存中是连续存放的。
总结:
//数组创建
int arr[3][4];//[行数][列数]
char arr[][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}};
注意: 花括号中的一个花括号代表一个一维数组的初始化。当里面无花括号分组时,按照顺序从第一个开始逐个进行初始化。余下的未赋值的元素用0初始化。
二维数组的使用也是通过下标的方式,用双重循环嵌套进行索引使用。 看代码:
#include <stdio.h>
int main()
{
int arr[3][4] = {
0 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
arr[i][j] = i * 4 + j;
}
}
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
printf("%d ", arr[i][j]);
}
}
return 0;
}
像一维数组一样,这里我们尝试打印二维数组的每个元素。
#include <stdio.h>
int main()
{
int arr[3][4];
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
}
}
return 0;
}
输出结果为:
通过结果我们可以分析到,其实二维数组在内存中也是连续存储的。
注意:
#include<stdio.h>
void Lisa(int arr[])
{
printf("a = %d\n", sizeof(arr));//数组降维成指针后的指针大小,在32位系统下指针都为4字节
printf("b = %d\n", sizeof(arr[0]));//数组首元素的大小
printf("sz =a / b = %d\n", sizeof(arr) / sizeof(arr[0]));//大小为1
printf("arr = %p\n", arr);//数组首元素地址
printf("&arr = %p\n", &arr);//指针的地址
printf("arr + 1 = %p\n", arr + 1);//下一个元素的地址
printf("&arr + 1 = %p\n", &arr + 1);//指针下一项的地址
}
int main(void)
{
int Shuzu[10] = {
0,1,2,3,4,5,6,7,8,9 };
printf("a = %d\n", sizeof(Shuzu));//数组总大小
printf("b = %d\n", sizeof(Shuzu[0]));//数组首元素大小
printf("sz =a / b = %d\n", sizeof(Shuzu) / sizeof(Shuzu[0]));//数组元素个数
printf("Shuzu = %p\n", Shuzu);//数组首元素地址
printf("&Shuzu = %p\n", &Shuzu);//代表整个数组,但是地址仍是首元素地址
printf("Shuzu + 1 = %p\n", Shuzu + 1);//下一个元素的地址
printf("&Shuzu + 1 = %p\n", &Shuzu + 1);//跳过整个数组后紧挨着的地址
//此时该地址减去首元素地址等于数组大小
printf("\n\n");
Lisa(Shuzu);
return 0;
}
补充
sizeof(数组名)
,计算整个数组的大小,sizeof
内部单独放一个数组名,数组名表示整个数组。&数组名
,取出的是数组的地址。&数组名
,数组名表示整个数组。!!画图解析!!
总结:
int arr[ ]
或者int *arr
,两者等价sizeof()
求数组元素个数时,尽量在数组定义时求。因为传参后数组会降维成指针。前面说了数组元素降维成指向数组内部元素类型的指针,二维int整型数组的内部元素不再是int整型,而是具有四个整型的一维数组。 对指针加一,加上所指向的类型的大小。对二维数组的指针加一,加上的值为内部一维数组的大小。 看代码:
#include<stdio.h>
void Lisa(int arr[][4])
{
printf("a = %d\n", sizeof(arr));//数组降维成指针后的指针大小,在32位系统下指针都为4字节
printf("b = %d\n", sizeof(arr[0][0]));//数组首元素的大小
printf("sz =a / b = %d\n", sizeof(arr) / sizeof(arr[0][0]));//大小为1
printf("arr = %p\n", arr);//数组首元素地址
printf("arr + 1 = %p\n", arr + 1);//下一个元素的地址
printf("&arr = %p\n", &arr);//指针的地址
printf("&arr + 1 = %p\n", &arr + 1);//指针下一项的地址
}
int main(void)
{
int Shuzu[3][4] = {
0,1,2,3,4,5,6,7,8,9 };
printf("a = %d\n", sizeof(Shuzu));//数组总大小
printf("b = %d\n", sizeof(Shuzu[0][0]));//数组首元素大小
printf("sz =a / b = %d\n", sizeof(Shuzu) / sizeof(Shuzu[0][0]));//数组元素个数
printf("Shuzu = %p\n", Shuzu);//数组首元素地址
printf("Shuzu + 1 = %p\n", Shuzu + 1);//下一个元素的地址,这时其内部元素的一维数组
printf("&Shuzu = %p\n", &Shuzu);//代表整个数组,但是地址仍是首元素地址
printf("&Shuzu + 1 = %p\n", &Shuzu + 1);//跳过整个数组后紧挨着的地址
//此时该地址减去首元素地址等于数组大小
printf("\n\n");
Lisa(Shuzu);
return 0;
}
画图解释
形参格式,例如:int arr[][4]
或者int (*arr)[4]
,这里为指向具有四个整型元素的一维数组的数组指针。除了第一个中括号里的数字可以省,后面的中括号的内容不能省略,因为下标是数组类型的一部分,省略掉就不明确其类型。
注意:
看待所有的数组时,都将它看作一维数组,只不过其内部元素不一样,例如:三维数组其内部元素为二维数组,而二维数组也是有一维数组组成,都是线性连续且相等的。
int (*arr)[10]
int *arr[10]
然后,需要明确一个优先级顺序:()>[]>*
所以:
(*p)[n]
:根据优先级,先看括号内,则p是一个指针,这个指针指向一个一维数组,数组长度为n,这是“数组的指针”,即数组指针;
*p[n]
:根据优先级,先看[]
,则p是一个数组,再结合*
,这个数组的元素是指针类型,共n个元素,这是“指针的数组”,即指针数组。
具体使用:
#include<stdio.h>
int main(void)
{
int *p[4];
int arr1[3] = {
1,2,3 };
int arr2[4] = {
2,4,6,8 };
int arr3[5] = {
0 };
int arr4[2] = {
2,2 };
p[0] = arr1;
p[1] = arr2;
p[2] = arr3;
p[3] = arr4;
printf("%d\n", *(p[0] + 1));
printf("%d\n", *(p[1] + 1));
printf("%d\n", *(p[2] + 1));
printf("%d\n", *(p[3] + 1));
return 0;
}
输出结果:
首先,对于语句int*p[4]
,因为[ ]
的优先级要比*
要高,所以 p 先与[ ]
结合,构成一个数组的定义,数组名为 p,而int*
修饰的是数组的内容,即数组的每个元素。也就是说,该数组包含 4 个指向int
类型数据的指针,如图所示,因此,它是一个指针数组。
使用:
#include<stdio.h>
int main(void)
{
int Shuzu[3][4] = {
0,1,2,3,4,5,6,7,8,9,0,0 };
int(*arr)[4] = Shuzu;
for (int i = 0;i < 3;i++)
{
for (int j = 0;j < 4;j++)
{
printf("arr[%d][%d]=%d ", i,j,arr[i][j] );
}
printf("\n");
}
return 0;
}
结果为:
其次,对于语句int(*arr)[4]
,“( )”
的优先级比[ ]
高,*
号和 arr 构成一个指针的定义,指针变量名为arr
,而int
修饰的是数组的内容,即数组的每个元素。也就是说,arr
是一个指针,它指向一个包含 4 个int
类型数据的数组,如图 所示。很显然,它是一个数组指针。
还有很多的瑕疵,欢迎提出并改正
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/162977.html原文链接:https://javaforall.cn