【C/C++】基本数据类型—数组、指针和引用

数组

数组的创建和初始化

数组是一种完全静态的数据结构,在初始化的时候我们就需要给数组指定大小,并且不能修改。指定数组的大小,也称为数组的维度。数组的维度必须像switch的case后面的表达式那样,是一个在编译的时候就能确定的整型常量表达式。不能使用变量作为数组大小。
数值的创建示例如下:
int arr1[2];
const int constNum = 4;
float arr2[constNum];
int arr3[constNum + 1];
定义空数组,但没有给出数组的元素初始值,因此数组的初始值将会是编译器默认的初始值或者无法预计的随机数值。
数组的初始化列表示例如下:
int arr1[5] = {0, 1, 2, 3, 4};
int arr2[5] = {0, 1, 2};
int arr3[] = {0, 1, 2, 3, 4};
如果初始化列表中元素个数超出了数组大小,那么编译器会报错。在初始化列表时没有给定数组的大小,在这种情况下数组大小会随着初始化列表的大小而确定。

指针

在计算机的存储系统中,所有的数据都存放在存储器中。通常把存储器中的一个字节称为一个内存单元,不同的数据类型所占的内存单元也不尽相同。在32位机中,int型占4个存储单元,float型占8个存储单元等。计算机系统中为标识每个存储单元,对每个内存单元都进行了编号,这些内存编号就叫作内存地址,通过这些内存地址就能索引到某个存储单元。
C语言中,为了便于直接与硬件进行交互,有时需要在程序中访问这些内存单元,通常把能够标识内存单元的地址称为指针。
指针(Pointer),从其英文字面上来理解就是一个指向某一物件的东西,在程序中就是指向数据的地址。计算机的内存可以看作是一个紧密排列的数据序列,每一小块数据(也就是字节)的旁边都有一个编号代表数据的地址。
一般我们都会把指针初始化为NULL,也叫作空指针,NULL的实际数值为0,也就是地址0x00000000,这给我们提供了一个统一可管理的异常值。在程序中,我们只要检查指针是否为空就知道指针是否指向有效数据了。如果指针没有初始化,它可能指向一个未知的地址,那么我们在尝试读取数据的时候就可能造成程序崩溃。此外,在指针初始化的时候,不能使用0以外的整型给指针赋值。
对于指针来说,解引用和取地址是最重要的两个操作符。
符号“&”表示了取地址的操作,它可以获得变量的内存地址。解引用操作符“*”,*intPtr将会得到intPtr所指向的地址中的数据。解引用操作符也可以用来作为赋值语句的左值以修改数据。

指针的算术操作

指针可以像整型那样进行一部分算术操作,还可以对地址进行修改。因为计算后的指针不一定会指向具有有效数据的地址,所以我们在进行指针算术操作的时候需要格外小心。
指针与整型的算术操作不同于一般的数字加减,而是与指针的类型绑定的。
数组名其实可以看作是指向数组第一个元素的指针。指针的各种操作都适用于数组名,但是有一点区别,那就是数组名不能被重新赋值。这也是很容易理解的,因为数组是静态的,数组名代表了当前作用域唯一的一个数组,不可能像指针那样指向其他地址。
指针除了与整型的算术操作之外,还可以进行指针相减。指针相减返回的是指针地址之间的距离,并且是分正负的。这个距离也与类型绑定,单位是该类型数据的个数。指针之间不存在加法,每个指针代表的地址在计算机中都是唯一确定的,相加没有任何意义。这就好像门牌号码32减掉30得到的2,表示它们之间(包括30号)隔着两户,而32加上30却并不能代表什么。

const指针

使用左值解引用可以修改指针指向的原变量,但如果原变量是const,值是不能被修改的,因此我们也需要有一种特殊的指针来保证原变量不会被修改,这就是指向const对象的指针。普通指针不能指向const对象。
例如:const int num1 = 3;
const int *ptr1 = num1;
指向const对象的指针还是可以修改地址的,那么应该也有另外一种不能修改地址的指针,也就是const指针。
例如:const int num1 = 3;
const int *const ptr1 = num1;

指针的数组和数组的指针

指针的数组是一种数组,而数组的指针则是一种指针。
例如:
int arr[5] = {0, 1, 2, 3, 4};
//数组的指针
int (*arrPtr)[5] = &arr ;
//指针的数组
int *ptrArr[5] = { &arr[0], &arr[1], &arr[2], &arr[3], &arr[4] };

在声明数组指针arrPtr的时候,我们把数组的地址赋值给它作为初值,由于数组的指针解引用以后就相当于数组,我们可以用(*arrPtr)[i]来读取数组的元素。
指针数组ptrArr,它的每一个元素都是一个指针,在这里我们就将数组每个元素的地址分别赋值,而在遍历的时候我们使用 *(ptrArr[i])来读取数组中某一个指针指向的元素值。

指针的指针

指针的指针的声明多了一个星号,以表示指针指向的是指针类型。指针的指针一般用于函数传参数时修改传入的指针。
例如:
int num = 3;
int *numPtr = &num ;
int **numPtrPtr = &numPtr ;

引用

引用(Reference)是C++在C指针的基础上更新改进的一个概念。引用在使用的时候比指针方便,并且不需要考虑类似空指针的问题。

引用的使用

引用的本质是一个变量的别名(Alias),因此它一定要与某个变量绑定。引用和指针在语法上的区别就是在创建的时候把“*”改成“&”。我们在使用引用的时候不需要像使用指针那样考虑解引用和取地址的操作,使用引用就跟使用变量一样直观。在一般情况下引用都是用于函数的参数传递。

引用与指针的区别

引用与指针有如下两点区别:
(1)引用必须初始化为某个变量的别名,而指针却可以为空;
(2)修改引用时修改的是引用所代表的原变量的值,而修改指针时则是修改指针所指向的地址。

const引用

const引用是const变量的别名。由于const变量的值不能随意修改,而修改普通引用就会导致原变量的值改动,因此我们也需要一种专门用于const变量的引用。非const引用是不能绑定到const变量的。

最近更新

  1. TCP协议是安全的吗?

    2024-02-07 08:32:01       17 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-07 08:32:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-07 08:32:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-07 08:32:01       18 阅读

热门阅读

  1. Flask实现异步调用sqlalchemy的模型类

    2024-02-07 08:32:01       28 阅读
  2. 正则表达式 regex

    2024-02-07 08:32:01       36 阅读
  3. jvm一级缓存

    2024-02-07 08:32:01       31 阅读
  4. kyuubi 接入starrocks | doris

    2024-02-07 08:32:01       32 阅读
  5. VLM 系列——LLaVA-MoLE——论文解读

    2024-02-07 08:32:01       29 阅读
  6. ef core原始sql查询

    2024-02-07 08:32:01       28 阅读
  7. dynamic_cast运行阶段类型识别

    2024-02-07 08:32:01       33 阅读
  8. 详细了解Node.js的配置与使用!

    2024-02-07 08:32:01       27 阅读
  9. Python程序设计 深浅拷贝

    2024-02-07 08:32:01       30 阅读
  10. 腾讯云主机部署spring boot程序

    2024-02-07 08:32:01       30 阅读
  11. 时序数据库m3db集群二进制部署

    2024-02-07 08:32:01       31 阅读