欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数组小结

程序员文章站 2024-02-11 09:22:22
...

这次我们来简单对数组的知识做一个小结。

数组的定义:

数组是一组相同类型元素的集合。

数组的创建方式:

<数组类型> 数组名[数组大小]

我们来建立一个数组来举一个例子,如下:

#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;
}

好啦,今天就写这些啦,如果有不足之处还请大家多多指正,^-^