美文网首页
C语言基础之指针(二)

C语言基础之指针(二)

作者: Eugene_iOS | 来源:发表于2023-03-29 20:14 被阅读0次

    C语言基础之指针(一)
    C语言基础之指针(二)

    11、 数组指针

    回顾

    数组名数组的首地址,也是第0个元素的地址,是个常量,数组名加 1 指向下一个元素。
    所以,在二维数组a中,a + 1指向下一个元素,即下一个一维数组,即下一行。
    🌰例子:
    int a[2][3] = { {1, 2, 3}, {4, 5, 6} };
    a是二维数组的首地址,也是数组中第一个元素一维数组{1, 2, 3}的首地址;
    a+1则表示首地址的下一个元素地址,即二维数组a中的第二个元素{4, 5, 6} 的首地址;

    数组指针

    指向数组的指针;即本身是个指针,指向一个数组,加 1 跳一个数组,即指向下一个数组。数组指针的作用就是可以保存二维数组的首地址
    格式int(* p)[n] = { 0 };// n为要定义的个数

    int a[5] = {1, 2, 3, 4, 5};// 定义并初始化5个int类型的数组
    int (\*p)[5] = &a;// 定义一个指向含有5个int类型数组的指针p(数组指针),并把**a数组的首地址**给了指针p。
    int I;
    for(i = 0; i < 5; I++) {     
        printf("%d\n", *(*p + i));
        //或者 printf("%d\n", (*p)[I]);
    } 
    

    ⚠️⚠️⚠️ 注意:
    为什么不直接用 int (*p)[5] = a; 呢?
    这是因为虽然a和&a的值都是相同的,但它们的意义却是不相同的:
    1、a指的是这个数组的 第一个元素 的首地址。
    2、&a 指的是这 整个数组 的首地址。
    3、a是指针类型,即int *类型;&a是数组指针类型,即int (*)[]类型;

    打印数组中的元素,为什么用*(*p + i)呢?
    1、*p+i 所指的是元素在数组中的位置(地址)
    2、*(*p + i) 就表示相应位置上元素的值
    3、p+1 表示p + 整个数组a的长度
    4、二维数组p[x][y]等价于*(*(p + x) + y),即:p[x][y] <==> *(*(p + x) + y)
    容易混淆的内容
    指针数组:是个数组,有若干个相同类型的指针构成的集合
    🌰:int *p[10]; // 数组p有10个 int*类型的指针变量构成,分别是p[0]~p[9]
    数组指针:是个指针,指向一个数组,加 1 跳一个数组
    🌰:int (*p)[10];// p是个数组指针,p + 1指向下一个数组,跳过10个整型内存空间
    指针的指针:一个二级指针
    🌰:int **p;// p是指针的指针
    int *q;
    p = &q;
    附录:
    【数组指针】 仅此一篇 让你深刻理解数组指针

    12、数组名取地址:变成 数组指针

    一维数组名取地址,变成一维数组指针,即加 1 跳一个一维数组。

    🌰:
    int a[10];
    a指的是这个数组的 第一个元素 的首地址
    a + 1 跳一个整型元素,即为a[1]的地址
    a 和 a + 1 相差一个元素,4个字节

    &a 指的是这 整个数组 的首地址,就变成了一个一维数组指针,是int (*a)[10]类型的。
    &a 和 (&a) + 1相差一个数组,即10个元素,40个字节


    🌰:int a[4][5]; // a + 1跳5个整型,(&a) + 1 跳 4行5列(80个字节)
    总结:c语言规定,数组名取地址,变成数组指针,加 1 跳一个数组。

    13、数组名 和 指针变量的区别

    🌰:int a[10];
    int *p;
    p = a;
    相同点
    a 是数组名,是数组首地址,是a[0]的地址,当p = a时,此时p也保存了a[0]的地址,即a和p都指向a[0],所以在引用数组元素的时候,a和p等价。如:a[1]、*(a+1)、p[1]、*(p+1)都是对数组a中a[1]元素的引用。
    不同点
    1、a是常量、p是变量
    可以给p赋值,但不能给a赋值。
    2、对a、p取地址结果不同
    因为a是数组名字,所以对a取地址结果为数组指针
    p是指针变量,所以对p取地址(&p)结果为指针的指针

    14、指针和函数的关系

    14.1、函数接受的参数:可分为实际参数、形式参数两种。

    实际参数:传递给函数的参数。
    形式参数:函数内使用的参数。

    14.2、函数参数的传递方式:可分为值传递、地址(指针)传递两种。

    值传递:实参和形参是两个对象,内存地址不同,形参是对实参值的复制。
    地址(指针)传递:实参和形参是同一个对象,它们两个指针指向同一内存地址,即实参值的地址,这里形参是对实参值的引用。
    ⚠️注意
    1、想要改变主调函数中变量的值,必须传变量的地址,而且必须是通过 *+地址 去赋值,无论这个变量是什么类型。
    2、如果实参是一个普通变量,地址传递的话就需要形参是一级指针
    3、如果实参是一个一级指针,地址传递的话就需要形参是二级指针
    4、依此类推。

    14.3、函数接受的参数是数组

    将数组作为参数传递给函数,不存在值传递和地址传递,本质都是地址传参;所以在函数内部对数组进行改变,则函数执行完毕后,原本的数组也会改变,因为传递给函数的都是数组的地址。

    14.4、指针函数:指针作为函数的返回值

    一个函数可以返回整型、浮点型、字符型的数据,也可以返回一个指针。
    指针函数本质是一个函数,只不过函数的返回值是个指针。

    14.5、函数指针:指针保存函数的地址

    在程序运行时,会将函数的指令加载到内存代码段,所以函数也有起始地址。

    C语言规定:函数的名字就是函数的首地址(和数组相同),即函数的入口地址;我们可以定义一个指针变量,来存放函数的地址,这个指针变量就是函数指针变量。

    定义方式:返回值类型 (*函数指针变量名)(形参列表)
    int (*p)(int, int); //定义一个函数指针变量p,p指向函数,返回类型为整型,有两个整型参数。
    int method(int x, int y) { }//定义一个函数
    p = method;//此时就可以用函数指针变量p,存放这里函数的地址

    14.6、函数指针数组:本质是一个数组,数组里面的每个元素都是一个函数指针。

    定义方式:返回值类型 (*函数指针变量名 [函数指针的个数] )(形参列表)
    int (*p[10])(int, int);// 定义函数指针数组,有10个元素;每个元素都是函数指针变量,指向的函数,返回类型为整型,有两个整型参数。

    14.7、函数指针最常用的地方

    最常用于将一个函数作为参数传递给另一个函数的时候,这个“将一个函数作为参数传递给另一个函数”,将这个函数称为回调函数

    15、经常容易混淆的指针

    第一组:指针数组、数组指针、指针的指针

    1、int *a[10;] // 指针数组,数组a中有10个整型的指针变量。
    2、int (*a)[10];// 数组指针(一般用于二维数组),它是个指针变量,占4个字节,存地址遍号。它指向一个数组,加1的话表示指向下一个数组。
    3、int **p;// 指针的指针,保存指针变量的地址。

    常见用法1:
    int **p;
    int *q;
    p = &q;

    常见用法2:
    int **p;
    int *q[10];
    // q是指针数组的名字,是指针数组首地址,是q[0]的地址;q[0]是个int*类型的指针;所以q[0]指针变量的地址,即为int **类型。
    p = &q[0]; // 等价于p = q


    第二组:指针函数、函数指针

    1、int *func(void);// 指针函数,注意:*func没有用括号括起来,它是个函数声明,声明这个函数的返回值为int*类型.
    2、int (*func)(void);// 注意:*func用括号括起来了,*修饰func是个指针变量,是个函数指针变量,存放函数地址;它指向的函数,返回值类型为int型,没有参数列表。

    16、特殊指针

    1、void *:通用指针

    对应类型的指针只能存放对应类型的数据地址。
    char *类型的指针指向char型的数据;
    int *类型的指针指向int型的数据;
    float *类型的指针指向float型的数据;
    void *为通用指针,任何类型的指针都可以给void *类型的指针变量赋值。
    eg:int *p; void *q; q = p;//这样是可以行得通的,且不用强制类型转换
    ⚠️注意:void *类型的指针变量,在32位系统下,占4个字节。

    2、NULL:空指针

    char *p = NULL;// p哪都不指向,也可以认为指向内存编号为0的存储单元;在p的四个字节中,存放的是0x00 00 00 00,一般NULL用在给指针初始化。

    main函数传参

    int main(int argc, char *argv[]) { }
    argc:int类型的变量,标识命令终端传入的参数的个数。
    argc:指针数组,用于保存每个终端命令传入的参数。


    写在最后:
    指针的详解与应用
    指针的详解与应用笔记

    相关文章

      网友评论

          本文标题:C语言基础之指针(二)

          本文链接:https://www.haomeiwen.com/subject/pntxddtx.html