C语言指针知识点总结

1.指针的使用和本质分析
(1)初学指针使用注意事项
    1)指针一定要初始化,否则容易产生野指针(后面会详细说明);
    2)指针只保存同类型变量的地址,不同类型指针也不要相互赋值;
    3)只有当两个指针指向同一个数组中的元素时,才能进行指针间的运算和比较操作;
    4)指针只能进行减法运算,结果为同一个数组中所指元素的下表差值。
(2)指针的本质分析
    ①指针是变量,指针*的意义:
        1)在声明时,*号表示所声明的变量为指针。
        例如:int n = 1; int* p = &n;
        这里,变量p保存着n的地址,即p<—>&n,*p<—>n
        2)在使用时,*号表示取指针所指向变量的地址值。
        例如:int m = *p;
   ②如果一个函数需要改变实参的值,则需要使用指针作为函数参数(传址调用),如果函数的参数数据类型很复杂,可使用指针代替。
        最常见的就是交换变量函数void swap(int* a, int* b)
   ③指针运算符*和操作运算符的优先级相同
        例如:int m = *p++;
        等价于:int m= *p;  p++;
 
2.指针和数组
(1)指针、数组、数组名
    如果存在一个数组 int m[3] = {1,2,3};
    定义指针变量p,int *p = m(这里m的类型为int*,&a[0]==>int*)
    这里,
    其中,&m为数组的地址,m为数组0元素的地址,两者相等,但意义不同,例如:
    m+1 = (unsigned int)m + sizeof(*m)
    &m+1= (unsigned int)(&m) + sizeof(*&m) 
             = (unsigned int)(&m) + sizeof(m)
    m+1表示数组的第1号元素,&m+1指向数组a的下一个地址,即数组元素“3”之后的地址。
    等价操作:
        m[i]←→*(m+i)←→*(i+m)←→i[m]←→*(p+i)←→p[i]
    实例测试如下:
 1 #include<stdio.h>
 2 
 3 int main()
 4 {
 5     int m[3] = { 1,2,3 };
 6     int *p = m;
 7 
 8     printf(" &m = %p\n", &m);
 9     printf(" m = %p\n", m);
10     printf("\n");
11 
12     printf(" m+1 = %p\n", m + 1);
13     printf(" &m[2] = %p\n", &m[2]);
14     printf(" &m+1 = %p\n", &m + 1);
15     printf("\n");
16 
17     printf(" m[1] = %d\n", m[1]);
18     printf(" *(m+1) = %d\n", *(m + 1));
19     printf(" *(1+m) = %d\n", *(1 + m));
20     printf(" 1[m] = %d\n", 1[m]);
21     printf(" *(p+1) = %d\n", *(p + 1));
22     printf(" p[1] = %d\n", p[1]);
23 
24     return 0;
25 }

 输出结果为:

(2)数组名注意事项

    1)数组名跟数组长度无关;
    2)数组名可以看作一个常量指针; 所以表达式中数组名只能作为右值使用;
    3)在以下情况数组名不能看作常量指针:
            - 数组名作为sizeof操作符的参数
            - 数组名作为&运算符的参数

(3)指针和二维数组

    一维数组的指针类型是 Type*,二维数组的类型的指针类型是Type*[n]

(4)数组指针和指针数组

①数组指针

    1)数组指针是一个指针,用于指向一个对应类型的数组;
    2)数组指针的定义方式如下所示:
         int (*p)[3] = &m;
②指针数组
    1)指针数组是一个数组,该数组里每一个元素为一个指针;
    2)指针数组的定义方式如下所示:
        int* p[5];
 
3.指针和函数
(1)函数指针
      函数的本质是一段内存中的代码,函数的类型有返回类型和参数列表,函数名就是函数代码的起始地址(函数入口地址),通过函数名调用函数,本质为指定具体地址的跳转执行,因此,可定义指针,保存函数入口地址,如下所示:
    int funcname(int a, int b);
    int(*p)(int a, int b) = funcname;
    上式中,函数指针p只能指向类型为int(int,int)的函数
(2)函数指针参数
     对于函数int funcname(int a, int b);
    普通函数调用 int funcname(int, int),只能调用函数int func(int, int)
    函数指针调用 intname(*func)(int,int),可以调用任意int(int,int)类型的函数,从而利用相同代码实现不同功能,
    实例测试如下,假设有两个相同类型的函数func1和func2:
1 int func1(int a, int b, int c)
2 {
3     return a + b + c;
4 }
5 
6 int func2(int a, int b, int c)
7 {
8     return a - b - c;
9 }

    普通函数调用和函数指针调用方式及结果如下所示

 1     printf("普通函数调用\n");
 2     printf("func1 = %d\n", func1(100, 10, 1));
 3     printf("func2 = %d\n", func2(100, 10, 1));
 4     printf("\n");
 5     
 6     printf("函数指针调用\n");
 7     int(*p)(int, int, int) = NULL;
 8     p = func1;
 9     printf("p = %d\n", p(100, 10, 1));
10     p = func2;
11     printf("p = %d\n", p(100, 10, 1));
12     printf("\n");

 

    需要注意的是,数组作为函数参数的时候,会变为函数指针参数,即:

    int funcname( int m[] )<——>int funcname ( int* m );

    调用函数时,传递的是数组名,即

    funcname(m);

(3)回调函数
    利用函数指针,可以实现一种特殊的调用机制——回调函数。回调函数是指把需要调用的函数指针作为参数传递给另一个函数,这个指针会在适当的时机被用来调用其所指向的函数,该函数指针指向的函数可能有多个,这种机制具有非常大的灵活性。
    所谓的回调指的是,上层调用底层,底层又回来调用上层,回调函数的机制:
        1)调用者不知道需要调用的具体函数
        2)被调用的函数不知道何时会被调用
        3)在满足特定条件时,调用者通过函数指针调用被调用的函数
    一个简单的回调函数的例子如下所示:
 1 #include<stdio.h>
 2 
 3 int func1(int a, int b)
 4 {
 5     int num = 2 * a * b;
 6     printf("func1的num = %d\n", num);
 7     return num;
 8 }
 9 
10 int func2(int a, int b)
11 {
12     int num = 4 * a * b;
13     printf("func2的num = %d\n", num);
14     return num;
15 }
16 
17 //回调函数
18 int callback(int(*p)(int, int))
19 {
20     int a = 3, b = 2;
21     return p(a, b);
22 }
23 
24 int main()
25 {
26     callback(func1);
27     callback(func2);
28 }

    运行结果如图所示:

     可以看出,如果不使用函数指针,而使用普通函数调用,则无法使用callback函数来调用func1和func2两个函数。

 
4.指针和常量
int const* p ; (指针p本身是变量,p指向的数据为常量
int* const p;(指针p本身是常量,p指向的数据为变量
const int* p;(指针p本身是变量,p指向的数据为常量
const int* const p;(指针p和p指向的数据都是常量
      
    
 
posted @ 2021-02-04 20:02  烟消00云散  阅读(731)  评论(0编辑  收藏  举报