数组小结
这次我们来简单对数组的知识做一个小结。
数组的定义:
数组是一组相同类型元素的集合。
数组的创建方式:
<数组类型> 数组名[数组大小]
我们来建立一个数组来举一个例子,如下:
#include <stdio.h>
int main()
{
int arr1[10];
char arr2[5];
int arr3[3+3];
char arr4[10];
double arr5[20];
return 0;
}
以上创建的数组都是合法的。在数组的创建中,数组类型可以是任意数据类型,而[ ]中的常量可以是一个表达式,但是绝对不可以是变量。
数组初始
数组创建过程中给数组初始值,即初始化
如下:
int arr[5]={1,2,3,4,5};
int arr2[]={1,2,3};
char arr3[4]={'a','b','c'};
char arr4[5]="abcdef";
特别的:
1.如果数组不想指定大小,那么就得初始化,这时候数组的大小就由数组初始化的内容来决定,比如数组arr2。
2.如果数组大小已经确定,但并未给数组初始值或者初始值个数小于数组大小,那么剩余空间的初始值默认为零。当然了,初始值的个数大于数组大小也是不可以的。
区别不同的数组存储
char arr1[]="abcd";
char arr2[]={'a','b','c','d'};
char* p="abcde";
数组arr1中的元素是5个,在数组开辟的内存块中存储内容为’a’,’b’,’c’,’d’,’\0’。
数组arr2中的元素是4个,数组开辟的内存块中存储内容为’a’,’b’,’c’,’d’。
第三种写法中,也能够打印出字符abcde,p只存放’a’的地址。
特别的:数组arr2在输出时,’\0’是字符数组的结束标志,如果没有’\0’,那么数组在输出时会因为找不到结束标志出现乱码。
一维数组
之前在操作符里面介绍过[ ]下标操作符,其实它就是一个数组访问的操作符。
1.数组是使用下标来访问的,并且下标是从0开始的。
2.数组的大小可以通过计算得到
int arr[5];
int size=sizeof(arr)/sizeof(arr[0]);
一维数组的存储方式
通过下面一段代码
#include <stdio.h>
int main()
{
int a[10] = { 0 };
int i = 0;
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("&a[%d]=%p\n", i, &a[i]);
}
return 0;
}
我们可以看到数组每个元素的地址,如下图
我们发现每个元素的地址之间相差4个字节,并且地址是连续的一段。
所以我们可以得到一个结论:
数组在内存中是连续存放的,并且存储方式由低地址向高地址的
就像这样
值得注意的是
&a[i]与p+i所表示的意义是完全相同的,都是表示第i各元素的地址,p中存储的是数组首元素的地址,所以p加i就为第i个元素的地址。。
代码证明如下:
#include <stdio.h>
int main()
{
int a[10] = { 0 };
int i = 0;
int *p = a;
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("&a[%d]=%p <====> %p\n", i, &a[i],p+i);
}
return 0;
}
结果如图:
根据数组在内存中连续存放的特点,我们可以发现数组不仅可以用下标访问,也可以用指针来访问。
以下两段代码都可以实现对数组元素的访问:
#include <stdio.h>
int main()
{
int a[10] = { 0 };
int i = 0;
int *p = a;
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
a[i]=i;
}
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("%d ", a[i]);
}
return 0;
}
#include <stdio.h>
int main()
{
int a[10] = { 0 };
int i = 0;
int *p = a;
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
*(p+i)=i;
}
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("%d ", a[i]);
}
return 0;
}
结果都相同
既然可以用指针访问,那我们就来介绍一下指针。
内存中的一个内存单元(或者说字节)对应一个地址,我们想要拿出某个变量的地址,就需要借助指针,指针是一个专门用来存放地址的变量,指针在32位机器上指针变量的大小是4个字节,而64位机器上指针的大小是8个字节。
当我们拿到指针的时候,也要能够找的指针所指向的变量。这里就借助到了*(解引用操作符)了。
int n=2;
int *p=&n;//这里就表示将n的地址存放在指针变量p中
*p=3;//实际上改变的是n的值
一维数组数组的指针访问
通过下面一段代码,
#include <stdio.h>
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
printf("%p\n", a);
printf("%d\n", *a);
return 0;
}
输出结果:
我们会惊喜的发现,数组的数组名其实是数组首元素的地址。
那么访问数组的其他元素我们就可以酱紫:
#include <stdio.h>
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
int i = 0;
int *p = a;
for (i = 0; i < sizeof(a) / sizeof(a[0]);i++)
{
*(p + i) = i;
}
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("%d --- %p\n", *(p + i), (p + i));
}
return 0;
}
结果如下:
二维数组
二维数组的创建与初始化
int arr1[3][4]={1,2,3,4,5};
int arr2[3][3]={{1,3},{2,4}};
int arr3[][4]={{1,2},{1,4}};
特别的:二维数组创建时,行数可以为空,但是列一定不能为空。
二维数组在内存中的存储
我们先来打印一个二维数组的地址
#include <stdio.h>
int main()
{
int arr1[3][3];
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
printf("&arr[%d][%d] ---> %p\n", i,j,&arr1[i][j]);
}
}
return 0;
}
结果如下:
通过数组各个元素的地址我们发现,二维数组在内存中也是连续存放的。
同一维数组一样,有了连续存储这个前提条件,二维数组也可以用指针来访问
像这样:
#include <stdio.h>
int main()
{
int arr1[3][3];
int *p = &arr1[0][0];
int i = 0;
int j = 0;
for (i = 0; i < 3 * 3; i++)
{
*(p + i) = i;
}
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
printf("%d ", arr1[i][j]);
}
}
return 0;
}
运行结果
关于数组的运算
一维数组
#include <stdio.h>
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 表示下标为1的数组元素的地址
printf("%d\n", sizeof(a[1]));//4 表示下标为1的数组元素
printf("%d\n", sizeof(*&a));//16 表示数组的总长度,*是对地址的解引用操作,所以等同于第一个
printf("%d\n", sizeof(*a));//4 表示数组的地址,特别注意,地址都是4个字节
printf("%d\n", sizeof(&a+1));//4 跳过整个数组的下一个地址
printf("%d\n", sizeof(&a[0]));//4 首元素的地址
printf("%d\n", sizeof(&a[0]+1));//4 下标为1的元素地址
return 0;
}
sizeof(数组名)—->数组名表示整个数组,计算的是数组的总大小。
&数组名—->数组名表示整个数组。
&数组名—->取出的是数组地址。
除此之外,所有数组名都表示首元素的地址。
#include <stdio.h>
int main()
{
char a[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(a));//6 数组总长度
printf("%d\n", sizeof(a+0));//4 首元素地址,即使是字符的地址,也一样是四个字节
printf("%d\n", sizeof(*a));//1 首元素
printf("%d\n", sizeof(a[1]));//1
printf("%d\n", sizeof(&a));//4 数组地址
printf("%d\n", sizeof(&a+1));//4 跳过数组的地址
printf("%d\n", sizeof(&a[0]+1));//4 第一个元素的地址
return 0;
}
好啦,今天就写这些啦,如果有不足之处还请大家多多指正,^-^
上一篇: 异常小结
下一篇: Android实现TCP与UDP传输