• C++指针解读(4)-- 指针和数组(一维数组)


    1、数组及数组的访问

    1.1 数组的存储方式

    在内存中,数组是一块连续的区域。数组的存储结构有如下特点:

    (1)数组中的元素是同质的数据;

    (2)索引从0开始;

    (3)数组在内存中的存储单元是连续的;

    (4)数据元素是按顺序连续存放的;

    比如数组:

    int a[6] = {1, 2, 3, 3, 5, 6};

    它在内存中的存储结构是这样的:

    1.2 数组指针

    访问数组可以用下标法访问,比如a[0]访问数组的第一个元素;也可以通过指针访问。在C语言中,数组名代表数组首个元素的地址。比如a与&a[0]是等价的。所以,我们可以通过*a访问数组的第1个元素,*(a+1)访问数组的第2个元素,等。

    在用数组名时,有几个地方不能把数组名当首地址看:

    (1)sizeof(a)求数组空间长度时。这里的a代表整个数组。注意这个sizeof()不是函数,是关键字,用来计算数据在内存中使用的字节数,是在编译时确定的。比如,sizeof(a) = 6*4 = 24个字节。

    (2)&a表示取数组a的地址,跟&a[0]是不同的。

    a只是代表数组首元素的地址,是指向数组首元素的指针;和指向这个数组的指针不是一码事。在指针变量的定义时我们知道,指针变量包含数据类型和指针名字,所以指向数组的指针的数据类型是数组,其指针值+1就代表地址往下移动 “每个数组元素字节*数组长度” 的字节数。而a+1指针只是往后移动1个数组元素字节。

    1. int a[6] = {1, 2, 3, 3, 5, 6};
    2. int *pi = &a[0];
    3. pi = &a[1]; //可以的
    4. pi = &a; //会报错,因为pi是个int指针,可以指向数组里的元素,但不能指向整个数组
    5. int (*pi2)[6]; //指向包含6个int元素的数组的指针
    6. pi2 = &a; //这么写就可以了

    (3)数组赋值的错误方式:

    1. char str[10];
    2. str = "abcd"; //报错
    3. int arr_i[10];
    4. arr_i = { 1, 2, 3 }; //报错

    正确的赋值方式:

    1. char str[10];
    2. strcpy(str, "abc");
    3. int arr_i[10];
    4. for (int i = 0; i < 10; i++) {
    5. arr_i[i] = i;
    6. }

    或者在定义的时候初始化:

    1. char str[10] = "abcd";
    2. int arr_i[10] = { 1, 2, 3 };

    2、数组指针相关运算

    2.1 基础运算规则

    假如定义了下面的数组和数组指针:

    1. int a[6] = {1, 2, 3, 3, 5, 6};
    2. int *p1 = &a[0];
    3. int *p2 = &a[2];

    (1)p1表示数组的首地址,则p1+i表示数组元素a[i]的地址。

    (2)*p1表示数组元素a[0]的值,*(p1+i)表示数组元素a[i]的值。

    (3)p2 - 1表示上一个数组元素,即a[1];p2 + 1表示下一个数组元素,即a[3]。

    (4)p2 - p1是2个地址之差。

    1. int a[6] = { 1, 2, 3, 3, 5, 6 };
    2. int* p1 = &a[0];
    3. int* p2 = &a[2];
    4. printf("%p\n", p1);
    5. printf("%p\n", p2);
    6. int size1 = (char)p2 - (char)p1; //转成char后的差才是字节数
    7. int size2 = p2 - p1;
    8. printf("size1 = %d, size2 = %d\n", size1, size2);

    输出结果如下:

    这里需要注意,因为p2、p1是地址,所以减之前要转成char,这样减的差值才是地址字节数。

    2.2 数组指针运算应注意的几个问题

    1. int a[6] = {1, 2, 3, 3, 5, 6};
    2. int *p = a;

    (1)*p++

    从右往左读。因此它等价于*(p++)。++在变量后表示先返回变量的值,然后再+1。比如i++表示先返回i的值,然后i+1。所以*(p++)先返回*p的值,然后指针再加1,指向p+1,即a[2]的位置。

    (2)*(p++)和*(++p)

    我们知道i++表示先返回i的值,然后i+1;++i表示先i+1,然后返回i的值。所以*(++p)先把指针往下移动1个数组元素,然后再返回这个元素的值,即返回a[2]的值。

    (3)++(*p)

    从右往左读。先得到*p的值,即a[1]的值。然后把a[1]的值加1。

    3、用数组名作函数参数

    数组名作函数参数可以写成下面的形式:

    1. func(int arr[], int len)
    2. //或
    3. func(int* parr, int len)

    上面2种方式是等价的,另外要记住数组作形状参时,必须同时传入数组的长度,否则可能会造成读取数组越界。这里有人可能会有疑问,不是可以在函数里用sizeof(arr)去获取数组的长度吗?不行的,因为形参int arr[]其实传过来的是实参数组的首地址。所以函数里的sizeof(arr)返回的是指针的长度,在32位系统中是4个字节,64位系统中是8个字节。

    3.1

    (1)数组表示法

    1. void print(int arr[], int len) {
    2. for (int i = 0; i < len; i++) {
    3. //printf("arr[%d] = %d\n", i, *(arr + i)); //2种打印方法都可以
    4. printf("arr[%d] = %d\n", i, arr[i]);
    5. }
    6. }
    7. int main()
    8. {
    9. int a[6] = { 1, 2, 3, 3, 5, 6 };
    10. print(a, 6);
    11. return 0;
    12. }

    (2)指针表示法

    1. void print(int *arr, int len) {
    2. for (int i = 0; i < len; i++) {
    3. printf("arr[%d] = %d\n", i, *(arr + i));
    4. //printf("arr[%d] = %d\n", i, arr[i]); //2种打印方法都可以
    5. }
    6. }

  • 相关阅读:
    realvnc-server-aarch64-ubuntu
    10月26日,每日信息差
    使用Jenkins做持续集成,这个知识点必须要掌握
    【Linux】进程信号
    一文带你读懂 Hbase 的架构组成
    [附源码]计算机毕业设计springboot高校车辆管理系统
    基于SpringBoot的大学生就业与创业管理平台
    Django ORM
    【微服务】Day02
    C函数学习(2):GLib HashTable函数
  • 原文地址:https://blog.csdn.net/mars21/article/details/133830835