当前位置: C语言 -- 专题 -- 指针的比较运算

指针的比较运算

本文讨论指针的比较运算时涉及到ISO/IEC 9899:2018标准中两类运算符:关系运算符(relational operators)和相等运算符(equality operators)。本文将按运算符的分类讨论指针的比较运算。


一、关系运算符

ISO/IEC 9899:2018标准中关系运算符包括:< > <= >=。如果关系运算符的操作数是指针,则指针应为兼容对象类型的限定版本或者非限定版本。当两个指针比较时,结果取决于其指向对象在地址中的位置关系。关系运算符的运算结果为int类型,如果指定的关系成立,则结果值为1;如果指定的关系不成立,则结果值为0


如果两个指针指向相同对象或者指向同一数组最后一个元素的后一个元素,那么这两个指针是相等的。

int a = 5;
int *ptrOne = &a;
int *ptrTwo = &a;

ptrOne <= ptrTwo;   //表达式的值为1。
ptrOne >= ptrTwo;   //表达式的值为1。

这里指针ptrOneptrTwo指向相同的对象,所以它们的值是相等的。

int arr[5] = {0};
int *ptrOne = &arr[5];
int *ptrTwo = &arr[5];

ptrOne <= ptrTwo;   //表达式的值为1。
ptrOne >= ptrTwo;   //表达式的值为1。

尽管数组元素arr[5]是不存在的,但对其使用地址运算符却是合法的。这里指针ptrOneptrTwo都指向该元素,所以它们的值是相等的。


如果两个指针指向同一结构的不同成员,由于先声明成员的地址值小于后声明成员的地址值,所以指向先声明成员的指针小于指向后声明成员的指针。

struct calendar {
        int year;
        int month;
        int day;
    } birthday;

&birthday.year < &birthday.month;   //表达式的值为1。

如果两个指针指向同一数组的不同元素,由于下标值大的数组元素的地址值大于下标值小的数组元素的地址值,所以指向下标值大的数组元素的指针大于指向下标值小的数组元素的指针。

int arr[5] = {0};
int *ptrOne = &arr[1];
int *ptrTwo = &arr[3];
    
ptrOne < ptrTwo;    //表达式的值为1。

如果两个指针指向同一联合的不同成员,这两个指针的值是相等的。

union data {
        int x;
        int y;
    } number;

&number.x <= &number.y; //表达式的值为1。

这里&number.x&number.y的值是相等的。


二、相等运算符

ISO/IEC 9899:2018标准中相等运算符包括:== !=。如果相等运算符的操作数中出现指针,应满足下述三种情况之一:

两个操作数均为指针,且为兼容类型的限定版本或者非限定版本。

一个操作数为对象类型指针,另一个操作数为void类型指针。

一个操作数为指针,另一个操作数为空指针常量(null pointer constant)。

除了运算优先级外,相等运算符的用法与关系运算符相似;相等运算符的运算优先级低于关系运算符。相等运算符的运算结果为int类型,如果指定的关系成立,则结果值为1;如果指定的关系不成立,则结果值为0

如果相等运算符的一个操作数是指针,另一个操作数是空指针常量,空指针常量将转换为指针类型。如果相等运算符的一个操作数是对象类型指针,另一个操作数是void类型指针,前者将转换为后者类型。


两个指针相等的情况包括:

 如果两个指针都是空指针,这两个指针是相等的。

int *ptrOne = 0;
int *ptrTwo = 0;

ptrOne == ptrTwo;   //表达式的值为1。

 如果两个指针指向相同的对象(包括一个是指向对象的指针,另一个是指向该对象开始的子对象的指针。)或者函数,这两个指针是相等的。

int arr[5] = {0};
int *ptrOne = arr;
int *ptrTwo = &arr[0];

ptrOne == ptrTwo;   //表达式的值为1。

指针ptrOne是指向数组arr的指针,指针ptrTwo是指向数组arr中第一个元素arr[0]的指针,所以指针ptrOne与指针ptrTwo是相等的。


 如果两个指针都是指向同一数组最后一个元素的后一个元素,这两个指针是相等的。

int arr[5] = {0};
int *ptrOne = &arr[5];
int *ptrTwo = &arr[5];

ptrOne == ptrTwo;   //表达式的值为1。

尽管数组元素arr[5]是不存在的,但对其使用地址运算符却是合法的。这里指针ptrOneptrTwo都指向该元素,所以它们的值是相等的。


 如果一个指针是指向数组最后一个元素的后一个元素,另一个指针指向不同数组的开始位置,但该数组在地址空间上紧接着第一个数组,这两个指针是相等的。

/* 数组的例子。*/
int arr[2][3] = {0};

&arr[0][3] == &arr[1][0];   //表达式的值为1。

/* 结构的例子。*/
struct data{
    int arrOne[4];
    int arrTwo[4];
} number;

&number.arrOne[4] == &number.arrTwo[0]; //表达式的值为1。

当两个对象是一个更大数组的相邻元素或者无填充结构的相邻成员时,这两个对象在内存中是相邻的。二维数组可以理解为是一个两个元素的一维数组,其中每个元素又都是一个一维数组。数组arr有两个数组元素arr[0]arr[1],元素arr[0][3]虽然不存在,但可认为是数组arr[0]最后一个元素的后一个元素;arr[1]是紧跟arr[0]的数组,arr[1][0]arr[1]的第一个元素,所以arr[1][0]arr[0][3]的地址是相同的。无填充结构的情况与二维数组的情况基本相似,这里就不重复了。