C 语言学习笔记 09 - 指针运算、左右值

指针的运算

在上文说过,指针实际上就是内存地址,而且这个地址就是整数,因此指针也可以进行运算。不过,指针只支持加减运算操作,但从指针的作用来看也应该只能支持加减操作。

加减法操作

指针的运算不同于普通的数学运算,不是简单的数学加减。

给出以下操作整型 a 变量的例子:

#include <stdio.h>

int main() {
    int a = 2;
    int *p = &a;

    printf("%d\n", p + 1);
    printf("%d\n", p);
    printf("int size = %d\n", sizeof(int));
}

得到以下结果:

-815793880
-815793884
int size = 4

不必关注奇怪的负数,将目光转到两个地址的差值上。结果是 4,恰与 int 类型的大小相等。显然,p + 1 并不是简单的在地址数值上加一,而是加上对应数据类型的占用大小与加数的乘积,即 p + sizeof(int) * 1,可以尝试修改成其他数据类型尝试。

对数组使用加减法

之前提过,数组等价于指针。因此,我们也可以通过对数组使用加减法获取对应下标的元素。给出下列代码:

int arr[] = {0, 1, 2, 3, 4};
int *p = arr;
int secondp = arr + 2;
int second = arr[2];

printf("%d", secondp == second);
printf("%d",second == p[2]);

可以发现,三者均可以获取对应下标的元素。数组和不可变指针有些相似,你可以修改其中的元素,但你不能直接给指针赋值,以下的操作是不被允许的:

int arr[]; // 等价于 int *const arr
int arr2[];

arr = arr2; // 不能用数组赋值数组
arr = (int *) 10; // 也不能直接修改它的地址

除此之外,我们还可以使用以下逆天方式获取元素:

int arr[4];
int a = 3[arr];

虽然它能跑通,但十分不推荐使用这种方式,不然只能寄希望于你能跑了。

左值与右值

这并不是一个很重要的知识点,我们经常会使用到 a = b 这样的赋值表达式。

实际上在赋值表达式左边出现的一定代表内存空间,而右边则是要存入该内存空间的值。

因此,以下的代码是不被允许的:

int a;
a = 2;

int *p = &a;
&a = p; // 报错

上述代码中的 &a 并不是一个内存空间,因此不能作为左值。

comments powered by Disqus