• [C/C++基础--笔试突击] 1.数组


    概述: 

      数组是一种数据格式,能够存储多个同类型的值。

      一维数组可用来实现线性表的顺序存储、哈希表、堆(堆排序部分)等;

      二位数组可用来保存图的邻接矩阵等。

    1.1 一维数组的声明与字符数组

    1.1.1 一维数组的声明与初始化

    1.一维数组的声明

    应指出以下三点:

    1)存储在每个元素中的值的类型;

    2)数组名;

    3)数组中的元素数,数组的元素数必须用值大于等于1的常量表达式定义。

    需要引起注意的地方:数组定义中类型不能使引用,因为引用是不能赋值的,而数组中元素必须可以被赋值。

    如下面的定义就是错误的。

    int& a[10]; // 错误的

    虽然没有引用数组,但数组可以有引用。

    int a[6] = {0, 2, 4, 6, 8, 10};
    int (&p)[6] = a;  // p是数组a的引用

    注:数组的引用可以用于函数实参传递。此时可确保传递过来的数组长度合乎要求。

    2.一维数组的初始化

    1)函数体定义的内置类型数组(即内置类型的全局数组),元素初始化为0;

    2)函数体定义的内置类型数组,元素无初始化(注意,若只初始化部分元素,其后的元素此时也会被初始化为0);

    3)如果不是内置类型,则不管其在哪定义,自动调用其默认构造器函数为其初始化,若该类型无默认构造函数则会报错。

    注:当数组的大小未知时,需要动态声明一维数组,声明格式如下:

    int* a = new int[n];
    //....
    delete []a; // 当数组使用完毕,需要释放内存空间

    1.1.2 字符数组

    字符数组的初始化既可以用字符常量也可以用常量字符串(末尾有空字符)记性初始化:

    方式1:char ca1[] = {'C', '+', '+'}; // 末尾没有null字符
          char ca1[] = {'C', '+', '+', ''}; // 末尾显示添加null字符
    方式2:char ca1[] = "C++"; // 末尾自动添加null字符

    注:ca1的长度为3,ca2和ca3的长度为4。

    const char ch4[5] = "Hello"; // 编译错误 数组长度应为6

    另外,C/C++很多字符串处理函数(strcpy,strcat等),传递给这些标准库函数的指针必须是非零值并且是指向以null结束的字符数组的第一个元素。

    1.2 二维数组

    1.2.1 二位数组的声明与初始化

    初始化方式分为两种:

    1)按行初始化:

    int a[3][4] = {{0, 1, 2, 3}, 
                   {4, 5, 6, 7},
                   {8, 9, 10, 11}};

    2)顺序初始化:

    int a[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

    注:如果只是初始化部分,则其余的规则按照一维数组的初始化规则。

    C++规定,在声明和初始化一个二维数组时,如果对二维数组的所有元素都赋值,则第一维(行数)可以省略,但第二维一定不能省略。

    1.2.2 行优先存储和列优先存储

    本质上讲,所有数组在内存中都是一维线性的,C/C++中,二维数组按照行优先顺序连续存储,因此按照行优先读取可以顺序读取,速度更快。

    注:二维数组a[x][y]转化为一维数组b:a[x][y] = b[x*列数 + y]。

    1.2.3 二维数组的动态声明

    int **a = new int* [m];
    for(int i = 0 ; i < m ; i++)
        a[i] = new int[n];

    动态声明的数组任意的a[k]都是一个int*类型,即一个地址,所以只能a[i][j]或者*(*(a+i)+j)来访问数组元素。

    此外动态声明的数组,使用后需要释放内存。

    for(int i = 0 ; i < m ; i++)
        delete []a[i];
    delete []a;

    1.3 数组指针、指针数组、数组名的指针

    1.3.1 指针运算---算数运算、关系运算

    C/C++规定的合法运算包括:指针与整数的加减、同类型指针间的比较、同类型的两个指针相减。

    指针与整数的加减

    当一个指针和一个整数进行算数运算的时候,整数在执行加法运算前始终会根据合适的大小进行调整,这个“合适的大小”就是指针所指向类型的大小

    例如:float占据4个字节,在计算float型指针加3的表达式时,这个3将根据float的类型大小(即此例中的4)进行调整为12。

    同类型的两个指针相减

    减法运算的值是两个指针在内存中的距离(以数组元素长度为单位,不是以字节为单位)。

    同类型的两个指针比较

    进行<、<=、>、>=运算,前提是它们都指向同一个数组中的元素。根据所使用的操作符,比较表达式的值表示那个指针指向数组更靠前或靠后。

    下面的代码用于清楚一个数组中所有的元素:

    float values[5];
    float *vp;
    vp = &values[0] ; 
    while(vp < &values[5]) {
      *vp = 0;
      *vp++; // 等价于 *vp ++= 0
    }

    1.3.2 指针数组与数组指针

    指针数组:一个数组里面装着指针,即指针数组为一个数组。

    例如一个有10个指针的数组,其中每个指针是指向一个整数型,那么此数组的定义为:

    int *a[10];

    数组指针:一个指向数组的指针,它其实还是指针,只不过它指向整个数组。

    例如一个指向有10个整型元素数组的指针定义为:

    int (*p)[10]; // 由于[]的优先级高于*,所以必须添加()

    注意:二维数组的数组名是一个数组指针,若有:

    int a[4][10];
    int (*)p[10];
    
    p = a; // a的类型是 int(*)[10]

     对应关系如下图:

    若有如下代码:

    int a[10];
    int (*p)[10] = &a; // 注意此处是&a,不是a,a的类型是int*,&a的类型是int(*)[10]
    int *q = a;

    对应关系如下图:

    可见,p与q虽然都指向数组的一个元素,但由于p的类型与q的类型不同,p是指向有10个元素整型数组的指针,*p的大小是40字节,故p+1跳过40字节;而q是指向整型的指针,*q的大小是4字节,故q+1跳过4字节。

    1.3.3 指针在数组中的应用

    指针和数组密切相关,特别是在表达式中使用数组名时,该名字会自动转换为指向数组首元素(第0元素)的指针。

    int ia[] = {0, 2, 4, 6, 8};
    int *ip = ia; // 指针ip指向了数组ia的首地址
    
    ip = &ia[4]; // ip指向了ia[4]
    
    ip = ia; // 重新指向ip[0]
    int *ip2 = ip + 4 // ip2指向ia[4]

    注:对于int a[10],可以有以下几种方式表示a[1]:

    &a[0] + 1;  // &a[0]等价于a,为首元素的地址
    (int*)&a + 1; // &a为指向数组的指针,与a类型不同(&a类型为int(*)[10]),但指向的单元相同,强制转化为int*,加1跳过一个int大小
    (int*)((char*)&a + sizeof(int)) ; // 强制转化为char*,加1跳过char的大小,跳了4次(int的大小), 再强制转化为int*(指向a[1]的指针类型为int*)

    &、*总结:

    例如这样的声明 int a[4][5];

    &a : 类型为 int(*)[4][5];

    a+i :类型为 int(*)[5];

    *(a+i) :类型为 int*;

    *(*(a+i) + j) :类型为int;

    *(a+i) = a[i];

    *(*(a+i) + j)  = *(a[i] + j) = a[i][j];

    数组就暂时告一段落,最后在强调一点,在遇到指针问题的时候,首先要明确指针指向的是什么,才能知道跳跃的长度。

    不明白的可以一起交流~希望可以加深大家的理解~.~

    返回目录 -> C/C++基础知识概述

  • 相关阅读:
    K8S常用命令
    【Python小随笔】输入字符串,检测出中文
    【Python】输入城市,输出省份
    【Python小随笔】词云
    【前端】中国地图资源与实现
    TCP和UDP及一些常见问题
    TCP实现可靠传输的相关机制
    三次握手和四次挥手过程及常见问题
    Docker网络
    数据安全管理总体要求
  • 原文地址:https://www.cnblogs.com/TinyBobo/p/4723943.html
Copyright © 2020-2023  润新知