C语言-指针

泄露秘密 提交于 2020-02-11 06:53:43

无指针,不自由

 

--1-- 为什么要使用指针
1.1 指针的基本概念
1.2 使用指针的好处
1.3 变量的存储方式
--2-- 指针变量
2.1 指针变量
2.2 定义一个指针变量
2.3 指针变量的初始化方法
2.4 使用*获取指针对应存储区域的内容
--3-- 存储细节
3.1 变量及指针变量
--4-- 常见的应用场景
4.1 指针常见的应用场景
--5-- 多级指针介绍
5.1 二级指针
5.2 多级指针介绍
----------------------------
 
 
 

【写在开头:】

生活中的指针:

没错,就是一个门牌号。

指针是C语言中最重要的内容之一。

为什么要使用指针?

如果你想要查找一篇资料,给你一本厚重的百科全书,而你只需要其中第3001页的内容。

那么,3001页,就是指针。如果没有这个指针...好吧,我去旁边哭会儿...

 

 

--1-- 为什么要使用指针

1.1 指针的基本概念

内存单元的编号也叫做地址,根据内存单元的编号或地址就就可以找到所需的内存单元。

所以通常也把这个地址称为指针

 

1.2 使用指针的好处

1)为函数提供修改调用变量的灵活手段

2)让函数有多个返回值

3)可以改善程序的效率

  在数据传递时,如果数据块较大(比如数据缓冲区或比较大的结构),这时就可以使用指针传递地址而不是实际数据,既提高传输速度,又节省了大量的内存

4)为动态数据结构(如二叉数,链表等)提供支持

 

1.3 变量的存储方式

变量存取的方式有两种:直接存取和间接存取

1)直接存取:变量的赋值和取值

2)间接存取:通过指针(地址)间接操作完成

指针最大的作用之一就是通过地址来操作(存取)变量、数组等

 

 

--2-- 指针变量

2.1 指针变量

在C语言中,允许用一个变量来存放指针,这个变量称为指针变量。

指针变量存放的是一个地址,是一个变量

 

2.2 定义一个指针变量

指针变量的定义包括三个内容:

1)指针类型说明,即定义变量为一个指针变量

2)指针变量名

3)变量值(地址)


一般形式:

类型说明符   *变量名 = 地址;

        int *p;  //定义了一个指针变量,变量名是p int表示p指向的是一个int类型的变量空间
        char *p1;   //变量名是p1 char表示p1指向的是一个char类型的变量空间

其中

  类型说明符表示本指针变量所指向的变量的数据类型

  *表示这是一个指针变量

  变量名即为定义的指针变量名

 注意:

1)在定义指针时,*表示定义的变量是一个指针变量(如果没有*就和普通变量没有区别了)

2)指针变量能用来存放数组或字符之类?-->不能(存储的是地址)

3)一个类型的指针只能指向同类型的变量,不能指向其他类型的变量

4)指针变量,归根结底还是一个变量,也有全局和局部之分

 

2.3 指针变量的初始化方法

指针变量应该用地址初始化

两种初始化的方式:

定义的同时初始化、先定义后初始化

1)定义的同时初始化

    //完全初始化
    int a = 3;
    int b = 4;
    int *P = &a; //用a的地址初始化p这个指针变量(也称为p指向了a))
    int *p1 = &a, *p2 = &a;  //p1,p2都指向了a 

2)先定义后初始化

    //部分初始化
    int *p3 = &b, *p4; //定义了两个指针变量 p3和p4 p4未初始化
    p4 = &b;

 

2.4 使用*获取指针对应存储区域的内容

指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋予其具体的值。

未经赋值的指针变量不能使用,否则将造成系统混乱,甚至死机(野指针)。指针变量的赋值只能赋予地址,不能赋予任何其他的数据,否则将引起错误。

C语言中,变量的地址是由编译系统分配的,对用户完全透明,用户事先并不知道变量的具体地址(但可以知道区域位置)。

两个相关的运算符:

  &:取地址运算符;

  *:指针运算符(或称“间接访问”运算符);

C语言提供了地址运算符"&"来表示变量的地址,一般形式为:&变量名;

获取指针变量指向的存储空间的内容:*指针变量名

*运算符和&运算符恰好相反。&运算符接收一个数据,然后告诉你这个数据保存在哪里;*运算符接收一个地址,然后告诉你这个地址中保存的是什么数据。

因为指针有时也叫引用,所以*运算符也可以描述成对指针进行解引用。

        int a = 3;
        int b = 4;
        int *p1 = &a;
        int *p2 = &b;
        
        //*指针变量  作用:获取指针变量指向的内存空间的内容(值)再赋值给value
        int value = *p1;  //3
        *p1 = 100;   //改变空间的值
        value = *p2;  //4
        printf("*p1 = %d\n", *p1); //100
        printf("value = %d\n",value );   //4

 

思考

定义如下指针

        float *pointer_3;
        char *pointer_4;
        int a,b;
        int *pointer_1 = &a, *pointer_2;

判断下面的操作是否合法?

        *pointer_1 = &a;
        pointer_3 = 2000;
        pointer_3 = &a;
        pointer_1 = &a;
        pointer_2 = pointer_4;

分析:

        *pointer_1 = &a;  //错; *pointer_1是一个解引用,是一个值,而非地址
        pointer_3 = 2000;  //错;pointer_3指针并未初始化,且需赋值的是一个地址
        pointer_3 = &a;  //错; 应该赋值一个float类型的空间地址给pointer_3
        pointer_1 = &a;  //合法
        pointer_2 = pointer_4;   //错; 类型不同

 

 

--3-- 存储细节

3.1 变量及指针变量存储细节

每当声明一个变量,计算机都会在存储器中某个地方为它创建空间。如果在函数(例如main()函数)中声明变量,计算机会把它保存在一个叫栈(Stack)的存储器区段中;如果你在函数以外的地方声明变量,计算机则会把它保存在存储器的全局量段(Globals)。

int y = 1; //位于全局量段 地址:1000 000
int main(int argc, const char * argv[]) {
    @autoreleasepool {

        int x = 4; //位于栈区 地址:4100 000
    }
    return 0;
}

 

 有如下变量

int i = 200;

int *p = &i;

此时p指向了变量i的首地址&i

 

 

--4-- 常见的应用场景

4.1 指针常见的应用场景

这样的一种场景很常见,参数在函数间进行传递时,要通过被调函数改变主调函数中实参变量的值。

如:交换两个变量的函数,如果不使用指针,则一般用的是临时变量等方法。

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        int x = 3, y = 4, temp;
        //临时变量交换两个变量的值
        temp = x;
        x = y;
        y = temp;
        printf("x = %d, y = %d\n", x, y);
    }
    return 0;
} 

但上面这样的写法是不标准的,一般需要将其封装成自定义方法才好(原谅我这里的说法不准确,“封装”是面向对象语言的特性)。

 

那么如果封装(习惯这样叫了...)成自定义方法之后,如果实参传递的是一个变量,那么主调函数中变量的值不会改变,因为形参实际上是又开辟了一个新的内存空间,所以在自定义函数中并不能修改实参的值:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        void swap(int x, int y); //函数声明
        
        int x = 3, y = 4;
        swap(x, y); //变量作为实参并不能修改实参空间中的值
        printf("x = %d, y = %d\n", x, y); //未改变 x = 3, y = 4
    }
    return 0;
}

/**
 *  测试方法,交换变量的值
 *
 *  @param x 变量1
 *  @param y 变量2
 */
void swap(int x, int y){
    //临时变量交换两个变量的值
    int temp = x;
    x = y;
    y = temp;
}

 要实现上面设定情景,就只能传递指针地址:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        void swap(int *x, int *y); //函数声明
        
        int x = 3, y = 4;
        swap(&x, &y); //将地址作为形参就可以交换此处x和y的值
        printf("x = %d, y = %d\n", x, y); //x = 4, y = 3
    }
    return 0;
}

/**
 *  交换两个变量的值
 *
 *  @param x 地址1
 *  @param y 地址2
 */
void swap(int *x, int *y){
    //临时变量交换两个变量的值
    int temp = *x;
    *x = *y;
    *y = temp;
}

 

 

--5-- 多级指针介绍

5.1 二级指针

如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量,也称为“二级指针”。

通过指针访问变量称为间接访问,由于指针变量直接指向变量,所以称为“一级指针”。而如果通过指向指针的指针变量来访问变量则构成了“二级指针”。

        int a = 5;
        int *p = &a;
        printf("%p\n",&a); //a的地址
        printf("%p\n",p); //指针p中存储的是a的地址
        printf("-----\n");
        //****二级指针
        int **p1 = &p; //p1中存储的是一个指针
        printf("p = %p\n", &p); //指针p的地址
        printf("p1 --> %p\n", p1); //p1中存储的地址
        printf("----------------------\n");
        printf("*p = %d\n", *p); //指针p指向的地址中存储的值
        printf("*p1 = %p\n", *p1); //p1指向的地址中存储的指针地址
        printf("**p1 = %d\n", **p1); //p1中存储的指针解引用

 

 5.2 多级指针介绍

同理,定义的时候有多少个*,一般也就称为几级的指针

 

 

【写在结尾:】

『每个人小的时候,都应该会有一个梦想,或者,就称为梦吧』

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!