zoukankan      html  css  js  c++  java
  • C学习笔记-指针

    指针的概念

    指针也是一个变量,指针变量的值是另一个变量的地址
    换句话说就是,指针存放的是一个内存地址,该地址指向另一块内存空间

    指针变量的定义

    指向一个变量的变量

    int *p = NULL;
    p = &i;
    
    int *p = &i;
    

    int *p; //表示定义一个指针变量
    p = &i; //表示指针变量p指向i的地址
    *p; //代表指针所指内存的实际数据
    指针赋值的时候,一定要类型兼容(sizeof获取到的大小相同)
    32位系统下,指针变量占4个字节,64位系统下,指针变量占8个字节。
    *代表取值,即为指针指向内存的值
    指针变量只能存放地址!!!

    NULL的含义

    一个指向NULL的指针,称之为空指针
    这个指针不指向任何一个变量
    野指针:没有赋初始值的指针

    无类型指针

    定义一个指针变量,但不指定它指向具体哪种数据类型
    可以通过强制转化将void *转化为其他类型指针
    可以用(void *)将其他类型指针强制转化为void类型指针

    int i = 10;
    void *p;
    p = &i;
    printf("*p = %d
    ", *(int *)p);
    

    在C语言当中,可以将任何一种地址赋值给void *指针
    无类型指针不能参与运算,原因是不知道其大小,无法知道偏移单位

    指针与数组的关系

    int arr[10];代表开辟了十个连续的int存储空间,arr代表了数组的首地址。其值和&arr[0]相同。
    int *p = arr;代表指针指向数组的首地址
    在C语言当中数组的名称代表数组的首地址,如果取数组名称的地址,C语言认为就是取数组的首地址

    指针操作数组

    指针的运算代表的是指针的移动

    int arr[10] = {0,1,2,3,4,5,6,7,8,9};
    int *p = arr;
    

    若存在以上定义,那么p+1代表了&arr[1]
    在C语言中,数组名是一个常量,不可以参与运算
    为何不能出现arr++?a++的意思是指向下一个内存空间,一旦这样做以后,会造成栈内存的回收问题,故编译器做了处理
    *[]的本质其实是一样的
    arr[i] ==> arr[0+i] ==> *(arr+i)
    此时有p[i]等同于*(p + i)

    *p++ == *(p++)
    

    如果存在以下表达式

    printf("%d",*(char *)p);
    

    那么此时输出结果是什么呢?
    分析:此时指针为char *类型,移动3位,int为四个字节,即移动到int字节末尾,如果是小端对其,那么输出0,如果是大端对其,那么输出1。

    指针数组

    char *p[5];
    

    其本质是数组,代表有5个指针类型的数组,每个元素都是指针。总共有5个int *
    此时取sizeof§得到的是4 * 5 = 20
    此时p相当于是一个数组名,不可使用指针运算

    数组指针

    char (*p)[5];
    

    定义了一个指针,指向int[5]这种数据类型的指针
    其实质是一个二级指针
    其本质是一个指针,指向5个int元素的指针,一般常用在数组,此时指向的数组其数据类型必须是相同的,其大小也必须相同。
    此时取sixeof§得到的是4
    此时p++的话偏移位置是sizeof(char) * 5
    e.g.

    char buff[5];
    char (*p)[5];
    p = buff;
    

    二级指针

    也就是指针的指针

    int i = 10;
    int *p1 = &i;
    int **p2 = &p1;
    printf("%d
    ", **p2);
    

    以上为二级指针的定义,此时有*p2代表p1的地址,**p2等于*p1又等于i
    由此推出多级指针的概念

    指向常量的指针与指针常量

    const关键字

    保护数组内容
    如果将一个数组做为函数的形参传递,那么数组内容可以在被调用函数内部修改,有时候不希望这样的事情发生,所以要对形参采用const参数

    func(const int array[])
    

    指向常量的指针

    可以限制指针修改变量的值,即不可通过*p来修改地址所存储的值
    但可以更改指向的位置

    const char *p;
    

    指针常量

    一旦初始化之后其内容不可改
    p只能指向某个地址,不可修改指向的地址

    char *const p;
    

    指针中的const

    看const修饰的是指针变量,还是修饰所指向的内存空间变量

    void main(void)
    {
        const int a;
        int const b;
        const char *c;
        char *const d;
        const char *const e;
        return;
    }
    
    1. 前两个意思相同,代表一个常整型数
    2. 第三个:c是一个指向常整型数的指针(所指向的内存空间数据不能修改,但本身可以修改)
    3. 第四个:d是常指针(指针常量不能被修改,但是它所指向的内存空间可以被修改)
    4. 第五个:e是一个指向常整型的常指针(指针和它指向的内存空间均不能被修改)
      合理的利用const,尤其是指针做函数参数的时候,可以提高代码的可读性

    指针运算

    赋值:int *p = &a;
    求值:int I = *p;
    取指针地址:int **pp = &p;
    将一个整数加(减)给指针:p + 3; p – 3;
    增加(减少)指针值: p++,p--
    求差值:p1 – p2,通常用于同一个数组内求两个元素之间的距离
    比较p1 == p2:通常用来比较两个指针是否指向同一个位置

    指针变量做函数参数

    C语言中,函数的参数都是值传递,只能把实参的值传递给形参,而不可以把形参的值传递给实参
    函数的参数可以是指针类型,它的作用是将一个变量的地址传送给另一个函数

    一维数组名作为函数参数

    当函数名作为参数时,C语言将函数名解释为指针
    当数组名作为函数参数传递给被调用函数时,被调用函数是不知道数组有多少元素

    int func(int arr[10];
    int func(int arr[]);
    int func(int *p);
    

    以上函数定义等价
    此时等价于地址传递,可以通过其地址改变实参的值

    二维数组名作为函数参数

    二维数组的指针操作使用int (*p)[5] = arr,做出如上定义以后,可以使用*(*(p + n) + m)来操作数组,也可以直接简写为p[n][m]来操作数组。

    arr 二维数组名称,数组首地址
    arr[0], *(arr + 0), *arr 0行,0列元素地址
    arr + 1 第1行首地址
    arr[1], *(arr + 1) 第1行,0列元素地址
    arr[1] + 2, *(arr + 1) + 2, &arr[1][2] 第1行,2列元素地址
    *(arr[1] + 2), *(*(arr + 1) + 2), arr[1][2] 第1行,2列元素的值

    二维数组和一维数组一样可以作为函数参数,在二维数组做函数参数时可以不指定第一个下标

    int func(int arr[][5]);
    int func(int (*p)[5]);
    

    指针做为函数的返回值

    char *func()//返回值为char *类型的函数
    {
        return "test";//实际上返回的是test字符串的首地址,但这句话存在问题
    }
    

    指向函数的指针

    指针可以指向变量,数组,也可以指向一个函数。
    一个函数在编译的时候会分配一个入口地址,这个入口地址就是函数的指针,函数名称就代表函数的入口地址。
    函数指针的定义方式:

    int (*p)(int);
    

    定义了一个指向int func(int n)类型函数地址的指针。

    1. 定义函数指针变量的形式为:函数返回类型(*指针变量名称)(参数列表)
    2. 函数可以通过函数指针调用
    3. int( * P)()代表指向一个函数,但不是固定哪一个函数
      e.g.
    void func(int n)
    {
        printf("n = %d", n);
    }
    
    int main()
    {
        void(*p)(int);//定义了一个指针,指向一个有一个int参数,同时返回值为void的指向函数的指针
        p = func;//让p指向func3函数的入口地址
        p(5);
    }
    

    把指向函数的指针做为函数的参数

    将函数指针做为另一个函数的参数称为回调函数

    指针小结

    定义 说明
    int i 定义整形变量
    int *p 定义一个指向int的指针变量
    int a[10] 定义一个int数组
    int *p[10] 定义一个指针数组,其中每个数组元素指向一个int型变量的地址
    int func() 定义一个函数,返回值为int型
    int *func() 定义一个函数,返回值为int *型
    int (*p)() 定义一个指向函数的指针,函数的原型为无参数,返回值为int
    int **p 定义一个指向int的指针的指针,二级指针

    指针和字符串

    在C语言中,字符串其实就是char数组,所以其操作一般就是数组的操作,也就是指针的操作

    char s[] = "hello word";
    char *p = s;
    p[0] = 'a';
    
  • 相关阅读:
    python学习之路01
    面向对象(2)__继承多态1
    面向对象(1)____私有公有 访问限制
    property
    yield理解
    列表推导式
    Django序列化1_基本的序列化和反序列化
    一些滑动操作
    装饰器
    django模板
  • 原文地址:https://www.cnblogs.com/cj5785/p/10664793.html
Copyright © 2011-2022 走看看