数组
1.定义
一组相同类型元素的集合
2. 创建方式
type_t arr_name [const_n];
//type_t 数组的元素类型
//[const_n] 常量表达式,用来指定数组的大小
3.数组的类型
int b;
int arr[10];
对比两个声明,变量b的是一个标量,它的类型是整型;arr[10]的类型也是整型,这一声明表示arr是一个整型数组;数组名arr的值是一个指针常量,所指向的是首元素地址,并非数组的类型。int [10] 才是数组的类型,它是指向 int 的常量指针,
如果是 char arr[10],表示数组arr是指向 char 的常量指针。
4、数组名不用指针常量表示的两种情况
例:
int main()
{
int arr[]={1,2,3,4,5};
printf("%d\n",sizeof(arr));
printf("%p\n",&arr);
printf("%p\n",&arr+1);
return 0;
}
运行结果:
分析: sizeof操作符求的整个数组的长度,共20个字节,可见放在sizeof内部的数组名表示整个数组;&运算符此时取出整个数组的地址,当&arr+1时,取出的地址不再是arr数组中某一元素的地址,而是跳过整个数组,取出arr数组下一个数组的地址。
5、下标引用和指针
下标引用即对数组的每个元素给相对应的下标序号;对于数组而言,数组名是一个常量指针,故我们可以使用指针进行间接访问数组的每个元素。
例:int arr[10]={1,2,3,4,5,6,7,8,9,10};
int *p=arr+2;
请计算以下4个表达式:1)*p+6; 2) p+6; 3) *(p+6); 4) p[-1];
分析:
1)条件中,p指向的是数组第三个元素 arr[2],“*”与“+”相比,“*”先执行,故而此时的结果为 arr[2]+6=9
2) p指向arr[2],此时将p所指的元素是 arr[2] 向后移动6个整数位置的元素,即arr[8]或&arr[8];
3)括号的优先级高于*,故而先执行(p+6),则此表达式的值为arr[8],和2式结果一样。(见上图)
4)条件中p指向第3个元素(下标是2),偏移量-1使我们得到前一个元素arr[1];(见下图)
6.数组的初始化
6.1 不完整的初始化
以下这几个定义正确吗?
int arr1[5]={1,2,3,4,5,6,7}; /(1)
int arr2[5]={1,2,3,4}; /(2)
int arr3[5]={1,5}; /(3)
int arr3[]={1,2,3,4,5}; /(4)
分析:
1)第一定义错误;arr1数组中的元素个数为5个整型变量,而给出的却为7个整型数,5个元素的数组显然放不下7个整型值。(见下图)
2)第二个定义正确;arr2数组中的元素个数为5,而给出的为4个整型值,显然没有超过数组元素的个数,并且后面的值自动为0.(见下图)
3)第三个定义正确;给出的整型值为1和5,少了2、3、4三个值,此时编译器默认初始值不够,不会知道中间缺少的值,故此后面的值默认为0.
4)第四个定义正确;此时未给出数组的长度,编译器默认设置数组长度为刚好能够容纳所有初值的长度
6.2 字符数组初始化
以下这几个定义正确吗?
char arr1[]={'h','e','l','l','o','\0'};
char arr2[]="hello";
char *arr3="hello";
char arr4[]="hello";
分析:
1)正确;普通的初始化方法,将每个字符放到数组中。
2)正确;前例的另一种写法,但并不是字符串常量。
3)正确; 真正的字符串常量。这个指针变量被初始化为指向这个字符串的存储位置
4)正确;初始化一个字符数组的元素,不是字符串常量。
6.3 多维数组的初始化
以下这几个定义正确吗?
int arr1[3][4] = {1,2,3,4};
int arr2[3][4] = {{1,2},{4,5}};
int arr3 [ ][4] = {{2,3},{4,5}};
int arr2[3][4] = {{1,2},{4,5}};
int arr3 [ ][4] = {{2,3},{4,5}};
int arr4[3][ ] = {1,2,3,4 };
分析:
1)正确;此定义为一个3行4列的矩阵,其第一行为1,2,3,4,其余每行默认初值为0。
2)正确;和上一定义一样,也为3行4列的矩阵,但给出只有两行的数值,并且每行数都不完整,默认为0.
3)正确;不同于上一定义的是这里没有给出行数,编译器默认刚好能容纳所有初值的行数为数组的行数。
4)错误;这种定义是错误的,没有给出列数,即没有给出可容纳的长度,故不能确定数组大小。
7.一维数组的计算
第一组:
int main()
{
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a)); //16 整个数组的长度
printf("%d\n",sizeof(a+0)); // 4 首元素的地址
printf("%d\n",sizeof(*a)); // 4 首元素
printf("%d\n",sizeof(a+1)); //4 第二个元素的地址
printf("%d\n",sizeof(a[1])); //4 第二个元素
printf("%d\n",sizeof(&a)); //4 整个数组的地址
printf("%d\n",sizeof(&a+1)); //4 下一个数组的地址
printf("%d\n",sizeof(&a[0])); //4 首元素的地址
printf("%d\n",sizeof(&a[0]+1)); //4 第二个元素的地址
return 0;}
分析:sizeof操作符计算所占空间大小时,只有当数组名单独放在内部时,表示整个数组,其余表示首元素地址;故此可求的以上各式的大小。(注:地址所占空间为4个字节)
第二组:
int main()
{
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr)); // 6 整个数组的长度
printf("%d\n", sizeof(arr+0)); // 4 首元素的地址
printf("%d\n", sizeof(*arr)); // 1 第一个元素
printf("%d\n", sizeof(arr[1])); // 1 第二个元素
printf("%d\n", sizeof(&arr)); // 4 整个数组的地址
printf("%d\n", sizeof(&arr+1)); // 4 下一个数组的地址
printf("%d\n", sizeof(&arr[0]+1)); // 4 第一个元素的地址
return 0;
}
分析:字符所占空间大小是1个字节,此数组中有6个字符,故整个数组所占空间大小为6个字节。
第三组:
int main() { char arr[] = {'a','b','c','d','e','f'}; printf("%d\n", strlen(arr)); // 随机值 遇到\0结束, printf("%d\n", strlen(arr+0)); // 随机值 首元素地址 printf("%d\n", strlen(*arr)); // 错误 第一个元素 printf("%d\n", strlen(arr[1])); // 错误 第二个元素 printf("%d\n", strlen(&arr)); // 随机值 整个数组的地址 printf("%d\n", strlen(&arr+1)); // 随机值 下一个数组的地址 printf("%d\n", strlen(&arr[0]+1)); // 随机值 第一个元素的地址 return 0; }
分析:strlen的功能是求得字符数组的大小,故此当遇到‘\0’停止计算,此字符数组中没有‘\0’标志,故整个数组的长度为一随机值。
第四组:
int main()
{
char *p = "abcdef";
printf("%d\n", sizeof(p)); // 4 指针变量的大小是4个字节
printf("%d\n", sizeof(p+1)); // 4 指针变量
printf("%d\n", sizeof(*p)); // 1 指针变量p指向第一个元素a
printf("%d\n", sizeof(p[0])); // 1 第一个元素
printf("%d\n", sizeof(&p)); // 4 指针变量p的地址
printf("%d\n", sizeof(&p+1)); // 4 p后面空间的地址
printf("%d\n", sizeof(&p[0]+1)); // 4 b的地址
return 0;
}
分析:这一组为一常量字符串,并有指针变量p指向字符串。需要注意的是&p+1这个所表示的意思,&p所表示的是指针变量p的地址,故&p+1表示p后面空间的地址,而不是字符串常量某一字符的地址。
第五组:
int main()
{
char *p = "abcdef";
printf("%d\n", strlen(p)); // 6
printf("%d\n", strlen(p+1)); // 5
printf("%d\n", strlen(*p)); // 错误
printf("%d\n", strlen(p[0])); // 错误
printf("%d\n", strlen(&p)); // 随机值
printf("%d\n", strlen(&p+1)); // 随机值
printf("%d\n", strlen(&p[0]+1)); // 从b向后数
return 0;
return 0;
}
8.二维数组的计算
int main()
{
int a[3][4] = {0};
printf("%d\n",sizeof(a)); // 48 整个二维数组的大小
printf("%d\n",sizeof(a[0][0])); // 4 第一行第一列的元素
printf("%d\n",sizeof(a[0])); // 16 第一行的大小
printf("%d\n",sizeof(a[0]+1)); // 4 第一行第二个元素的地址
printf("%d\n",sizeof(a+1)); // 4 第二行地址
printf("%d\n",sizeof(&a[0]+1)); // 4 第二行的地址
printf("%d\n",sizeof(*a)); // 16 第一行的大小
printf("%d\n",sizeof(a[3])); // 16 第三行的大小
return 0;
}
分析:二维数组的首元素指第一行,故而 a[0]+1 指第一行第二个元素;sizeof(a[3]) 在这里是正确,sizeof操作符内部的表达式不参与运算,故而这里表示第三行的大小。
注:以上所有结果均在vs环境下测试