【C语言进阶剖析】26、指针的本质分析

在本系列第一篇博客中讲到变量的本质是一段存储空间的别名,那么是不是必须通过这个别名才能使用这段存储空间呢?

我们先看一个问题?下面的程序输出什么,为什么?
在这里插入图片描述
我们来实际编译运行一下:

#include<stdio.h>
int main()
{
    int i = 5;
    int* p = &i;
    printf("%d, %p\n", i, p);
    *p = 10;
    printf("%d, %p\n", i, p);
    return 0;
}
$ gcc 26-1.c -o 26-1
$ ./26-1
5, 0x7ffd47f77a8c
10, 0x7ffd47f77a8c

可以看到我们并没有改变变量 i 的值,而是通过指针 p 修改它所指向的内存空间(就是变量 i),也就是修改了变量 i 的值。因为指针 p 指向变量 i

1 *号的意义

  • 在指针声明时,* 号表示所声明的变量为指针
  • 在指针使用时,* 号表示取指针所指向的内存空间中的值

在这里插入图片描述
可以这样理解,内存就是一间房子,变量就是房子里面放的东西,指针就是门牌号。定义指针就是拿到了一个门牌号,指针 p 指向变量 i,就是将这个门牌号装在了存放变量 i 的房子上,当然可以取下来装在别的房子上,也就是指针 p 指向了另一个变量。* 号就是一把钥匙,通过这个钥匙就可以拿到房子里面的东西,这就是 *p 解引用。

指针 p 保存着变量 i 的内存地址,可以这么理解

  • p 等价于 &i
  • *p 等价于 i

下面看一个指针使用示例:

// 26-1.c
#include<stdio.h>
int main()
{
    int i = 0;
    int* pI;
    char* pC;
    float* pF;
    pI = &i;
    *pI = 10;
    printf("%p, %p, %d\n", pI, &i, i);
    printf("%ld, %ld, %p\n", sizeof(int*), sizeof(pI), &pI);
    printf("%ld, %ld, %p\n", sizeof(char*), sizeof(pC), &pC);
    printf("%ld, %ld, %p\n", sizeof(float*), sizeof(pF), &pF);
    return 0;
}

编译运行结果如下:

$ gcc 26-1.c -o 26-1
$ ./26-1
0x7ffca1ad8f8c, 0x7ffca1ad8f8c, 10
8, 8, 0x7ffca1ad8f90
8, 8, 0x7ffca1ad8f98
8, 8, 0x7ffca1ad8fa0
  • 上面的程序,指针 pI 的值和变量 i 的地址是一样的,pI 和 &i 等价,* 号是钥匙,*pI 拿到了房间的钥匙,并更换的房间的东西,由 0 变成 10
  • 可以看到不管定义什么类型的指针,指针大小是一样的,也很好理解,不管房子是多大的,里面放的什么东西,门牌号长度都不会变,不能因为你住的是豪宅就换个贼长的门牌号吧
  • 32位系统指针长度为 4 字节,64 位系统指针长度为 8

2 传值调用与传址调用

  • 指针是变量,因此可以声明指针参数
  • 当一个函数体内部需要改变实参的值,则需要使用指针参数
  • 函数调用时实参将复制到形参
  • 指针适用于复杂数据类型作为参数的函数中

下面看一个指针使用的示例,:利用指针交换变量

// 26-2.c
#include<stdio.h>
void SWAP(int *a, int *b)
{
    int t = *a;
    *a = *b;
    *b = t;
}
int main()
{
    int a = 1;
    int b = 2;
    printf("a = %d, b = %d\n", a, b);
    SWAP(&a, &b);
    printf("a = %d, b = %d\n", a, b);
    return 0;
}

注意,千万不能写成如下代码:

void SWAP(int a, int b)
{
    int t = a;
    a = b;
    b = t;
}

这样是达不到交换目的的,采用值传递时,形参是实参的拷贝,改变形参的值不影响实参的变化。因为形参有自己独立的存储空间,作为函数内部的局部变量,在函数调用结束后就被释放,因此不影响实参的值。 所以 SWAP(int a, int b) 函数中 a, b 的交换不会影响到 main() 函数中。

3 常量与指针

通过几个例子来学习 const 修饰指针的情形
在这里插入图片描述
上面的内容不用死记,只需要看清楚 const 修饰的是谁就可以了。如果 const 修饰 *p,则 *p 不可变;如果 const 修饰 p,则 p 不可变;如果两个都修饰,都不可变

下面就来实际操作一个,看下面代码中,哪些行会报错

// 26-3.c
#include<stdio.h>
int main()
{
    int i = 0;
    const int *p1 = &i;
    int const *p2 = &i;
    int* const p3 = &i;
    const int* const p4 = &i;
    *p1 = 1;
    p1 = NULL;

    *p2 = 1;
    p2 = NULL;

    *p3 = 1;
    p3 = NULL;

    *p4 = 1;
    p4 = NULL;
    return 0
}

根据前面的知识,我知道,*p1, *p2, p3, *p4, p4 被 const 修饰,是不可修改的,下面就编译一下,看看我们的分析是否正确。

在这里插入图片描述
编译结果在第 10,13,17,19,20 行报错,和我们的分析结果完全一样

4 小结

1、指针是 C 语言中一种特别的变量
2、指针所保存的值是变量的地址
3、可以通过指针修改内存中得任意地址内容

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页