C指针详解

指针详解

前言:指针是 C 语言中的一个重要概念,也是 C 语言 的一个重要特色。正确而灵活地运用它,可以使程序简洁、紧凑、高校。每一个学习和使用 C 语言地人,都应当深入地学习和掌握指针。可以说,不掌握指针就是没有掌握 C 的精华。

一、指针是什么

  1. 概念引入
  • 为了说清楚什么是指针,必须先弄清楚数据在内存中是如何存储的,又是如何读取的。如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配内存单元。编译系统根据程序中定义的变量类型,分配一定长度的空间。内存区的每一个字节有一个编号,这就是“地址”,它相对于旅馆中的房间号。在地址所标志的内存单元中存放的数据则相当于旅馆中居住的旅客。

  • 由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。打个比方,一个房间的门口挂了一个房间号 2008,这个 2008 就是房间的地址,或者说,2008 “指向”该房间。因此,将地址形象化地称为“指针”(即地址=指针)。意思是通过它能找到以它为地址地内存单元。

    说明:对计算机存储单元地访问比旅馆要复杂一些,在 C 语言中,数据是分类型地,对不同类型地数据,在内存中分配地存储单元大小(字节数)和存储方式是不同的。因此,为了有效地存取一个数据,除了需要位置信息外,还需要有该数据地类型信息(如果没有该数据的类型信息,只有位置信息是无法对该数据进行存取的)。C 语言中的地址包括位置信息(内存编号,或称纯地址)和它所指向的数据的类型信息,或者说它是“带类型的地址”。若定义 int a;&a,一般称它为“变量 a 的地址”,确切地说,它是“整型变量 a 的地址”。后面提到的“地址”,都是这个意思。

  1. 访问方式
  • 直接访问
    如果有语句 k = i + j;则从 2000 ~ 2003 字节取出 i 的值,再从 2004 ~ 2007字节取出 j 的值,将它们相加后再将其和送到所占用的 2008 ~ 2011 字节单元中。这种直接按变量名进行的访问称为**“直接访问”**方式。

  • 间接访问
    还可以采用另一种称为**“间接访问”**的方式,即将变量 i 的地址存放在另一变量中,然后通过该变量来找到变量 i 的地址,从而访问 i 变量。
    在 C 语言 程序中,可以定义整型变量、浮点型变量,字符变量等,也可以定义一种特殊的变量,用它存放地址。假设定义了一个变量 i_pointer(变量名可任意取),用来存放整型变量的地址。可以通过下面语句将 i 的地址(2000)存放到 i_pointer 中。

    i_pointer = &i;                //将 i 的地址存放到 i_pointer 中
    

    这时,i_pointer 的值就是 2000(即变量 i 所占单元的起始地址)。

    要存取变量 i 的值,即可以用直接访问的方式,也可以采用间接访问的方式:先找到存放”变量 i 的地址“的变量 i_pointer,从中取出 i 的地址(2000),然后到 2000 字节开始的存储单元中取出 i 的 值。如图1.

  1. 总结:

    A. 图 2 表示直接访问,根据变量名直接向变量 i 赋值,由于变量名与变量的地址有一一对应的关系,因此就按此地址直接对变量 i 的存储单元进行访问(如把数值 3 存放到变量 i 的存储单元中)

    图 3 表示间接访问,先找到存放变量 i 地址的变量 i_pointer,从其中得到变量 i 的地址(2000),从而找到变量 i 的存储单元,然后对它进行存取访问。

    在这里插入图片描述在这里插入图片描述

    B. 为了表示将数值 3 送到变量中,可以有两种表达方法:

    • 将 3 直接送到变量 i 所标识的单元中,例如“i = 3”。
    • 将 3 送到变量 i_pointer 所指向的单元(即变量 i 的存储单元),例如“*i_pointer = 3;”,其中 *ipointer 表示 i_pointer 指向的对象。、

    C. 指针,指针变量

    • 指向就是通过地址来体现的,假设 i_pointer 中的值是变量 i 的地址(2000),这样就在 i_pointer 和 变量 i 之间建立起一种联系,即通过 i_pointer 能知道 i 的地址,从而找到变量 i 的内存单元。图 3 中以单箭头表示这种“指向”关系。

    • 由于通过地址能找到所需的变量单元,因此说,地址指向该变量单元(如同说,一个房间号“指向”某房间一样)。将地址形象化地称为**“指针”**。意思是通过它能找到以它为地址地内存单元(如同根据地址 2000 就能找到变量 i 的存储单元一样)。

    • 如果有一个变量专门用来存放另一变量的地址(即指针),则它称为**“指针变量”**。上述的 i_pointer 就是一个指针变量。指针变量就是地址变量,用来存放地址,指针变量的值是地址(即指针)。

    • 注意区分“指针”和“指针变量”这两个概念。例如:可以说变量 i 的指针是 2000,而不能说 i 的指针变量是 2000。指针是一个地址 ,而指针变量是存放地址的变量。

二、指针变量

  1. 使用指针变量的例子

    通过指针变量访问整型变量

    先定义 2 个整型变量,再定义 2 个指针变量,分别指向这两个整型变量,通过访问指针变量,可以找到它们所指向的变量,从而得到这些变量的值。

    #include<stdio.h>
    int main()
    {
        int a = 100, b = 10;  
        int *pointer_1, *pointer_2;  //定义指向整型数据的指针变量 pointer_1,pointer_2
        pointer_1 = &a;				 //把变量 a 的地址赋给指针变量 pointer_1
        pointer_2 = &b;				 //把变量 b 的地址赋给指针变量 pointer_2
        printf("a = %d, b = %d\n", a, b);
        printf("*pointer_1 = %d, *pointer_2 = %d\n", *pointer_1, *pointer_2);
        return 0;
    }
    

    运行结果:

    a = 100, b =10

    *pointer_1 = 100, *pointer_2 = 10

    注意:程序中有两处出现 *pointer_1 和 *pointer_2,二者的含义不同。程序第 5 行的 *pointer_1 和 *pointer_2 表示两个指针变量 pointer_1 和 pointer_2。它们前面的“*”只是表示该变量是指针变量。程序第 9 行 printf 函数中的 *pointer_1 和 *pointer_2 则代表指针变量 pointer_1 和 pointer_2 所指向的变量。

  2. 怎样定义指针变量

    形式:类型名 * 指针变量名;

    说明:既然有基本的数据类型(如:int, char, float),就可以有指向这些类型变量的指针,因此,指针变量是基本数据类型派生出来的类型,它不能离开基本类型而独立存在。指针变量前面的 “*”表示该变量是指针型变量。指针变量名是 pointer_1 和 pointer_2,而不是 *pointer_1 和 *pointer_2。a 的地址是赋给指针变量 pointer_1,而不是赋给 *pointer_1(即变量 a)。

  3. 指针类型

    如何表示指针类型。指向整型数据的指针类型 表示为“int *”,读作“指向 int 的指针”或简称“int 指针”。可以有 int *,char *,float *。

  4. 怎样引用指针变量

    先要熟练掌握两个有关的运算符:

    (1)& 取地址运算符。&a 是变量 a 的地址。

    (2)* 指针运算符(或称“间接访问运算符”),*p 代表指针变量 p 指向的对象

    • 给指针变量赋值。如:

        p = & a;	//把 a 的地址赋给指针变量 P
      

      指针变量 p 的值是变量 a 的地址, p 指向了整型变量 a。

    • 引用指针变量指向的变量

      如果已执行p = &a;,即指针变量 p指向了整型变量 a,则printf("%d", *p);其作用是输出指针变量 p 所指向变量的值,即变量 a 的值。如果有*p = 1;语句,表示将整数 1 赋给 p 当前所指向的变量,如果 p 指向变量 a,则相当于把 1 赋给 a,即“a = 1;”

    • 引用指针变量的值,如:

      printf("%o",p);
      

      作用是以八进制形式输出变量 p 的值,如果 p 指向了 a,就是输出了 a 的地址,即 &a。

    下面是一个指针变量应用的例子。

    输入 a 和 b 两个整数,按先大后小顺序输出 a 和 b。

    解题思路:用指针方法来处理这个问题。不交换整型变量的值,二十交换两个指针变量的值。

    在这里插入代码片
    #include<stdio.h>
    int main()
    {
        int *p1, *p2, *p, a, b;  
        scanf("%d,%d", &a, &b);
        p1 = &a;
        p2 = &b;
        if(a < b){
            p = p1;
            p1 = p2;
            p2 = p;
        }
        printf("a = %d, b = %d\n", a, b);
        printf("max = %d, min = %d\n", *p1, *p2);
        return 0;
    }
    

    运行结果:
    a = 5, b = 9
    max = 9, min = 5

    讲解:a 和 b 的值并未交换,它们仍保持原值,但 p1 和 p2 的值改变了。p1 的值原为 &a,后来变成 &b,p2 的值原为 &b,后来变成 &a。这样在输出 *p1 和 *p2 时,实际上是输出变量 b 和 a 的值,所以先输出 9,然后输出 5。
    在这里插入图片描述
    在这里插入图片描述

  5. 指针变量作为函数参数

    将上节代码用函数处理,而且用指针类型的数据作为函数参数。

    解题思路:上节是直接在主函数内交换指针变量的值,本题是定义一个函数 swap,将指向两个整型变量的指针变量(内放两个变量的地址)作为实参传递给 swap 函数的形参指针变量,在函数中通过指针实现交换两个变量的值。

    #include<stdio.h>
    int main(){
        void swap(int *p1, int *p2);
        int a = 5, b = 9;
        int *pointer_1,*pointer_2;
        pointer_1 = &a;
        pointer_2 = &b;
        if(a < b)	swap(pointer_1, pointer_2);
        printf("max = %d, min = %d\n",a, b);
        return 0;
    }
    void swap(int *p1, int *p2){
        int temp;
        temp = *p1;
        *p1 = *p2;
        *p2 = temp;
    }
    

    运行结果:
    max = 9, min = 5

    程序分析:
    swap 是用户自定义函数,它的作用是交换两个变量(a 和 b)的值。swap 函数的两个形参 p1 和 p2 是指针变量。程序运行时,先执行 main 函数。然后将 a 和 b 的地址分别赋给 int *变量 pointer_1 和 pointer_2,使 pointer_1 指向 a,pointer_2 指向 b,见下图1。接着执行 if 语句,由于 a < b,因此执行 swap 函数。注意实参 pointer_1 和 pointer_2 使指针变量,在函数调用时,将实参变量的值传递给形参变量,采取的仍然是“值传递”方式。因此虚实结合后形参 p1 的值为 &a,p2 的值为 &b,见下图2。接着执行 swap 函数的函数体,使 * p1 和 * p2 的值互换,也就是使 a 和 b的值呼唤,互换后的情况见下图3。函数调用结束后,形参 p1 和 p2 不复存在(已释放),情况如下图4。最后在 main 函数中输出的 a 和 b的值使是已经交换的值(a = 9, b = 5)。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 10
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值