• 23.1 指针的基本概念


    23.1 指针的基本概念

    第一种指针:堆栈有栈顶指针,队列有头指针和尾指针,这些概念中的“指针”本质是一个整数,是数组的索引,通过指针访问数组中的某个元素。
    第二种指针:把一个变量所在的内存单元的地址保存在另外一个内存单元中,保存地址的这个内存单元称为指针,访问变量要通过指针间接寻址,这种指针在C语言中可以用一个指针类型的变量表示。

    int i;
    int *pi = &i;
    char c;
    char *pc =&c;
    
    • 1
    • 2
    • 3
    • 4

    (1)&是取地址运算符,&i表示取变量i的地址;int *pi = &i;表示定义一个指向int型的指针变量pi,并用i的地址来初始化pi。
    (2)定义字符型变量c和一个指向c的字符型指针pc。

    如果要让pi指向另一个整型变量j,可以重新读pi赋值:

    pi =&j;
    
    • 1

    现在要通过指针pi间接寻址到变量j,把变量j的值增加10,可以写成:

    *pi = *pi +10;
    
    • 1

    [ ]在声明和表达式中有不同的含义,[ ]用在声明中表示一个数组;用在表达式中提取下标运算符。同理,*用在声明中表示一个指针类型,用在表达式中是间接寻址运算符。

    *和&互为逆运算。如果表达式E可以做左值,则*&E和E等价;如果表达式E是指针类型,则&*E和E等价。

    指针之间相互赋值,用一个指针初始化另一个指针:

    int *ptri = pi;
    
    • 1

    或者

    int *ptri;
    prti = pi;
    
    • 1
    • 2

    上述代码表示pi指向哪就让prti也指向哪,本质上就是把变量pi所保存的地址赋值给变量prti。

    强制类型转换。 两个指针必须同一类型,才能用一个指针给另一个指针赋值。不同类型,先强制转换再赋值,如pi是int *型,pc是char *型,不可以pi = pc,应该如下操作

    pi =int *)pc;
    
    • 1

    在这里插入图片描述

    **定义一个指针类型的局部变量需要初始化。**错误情况如下:

    int main(void)
    {
    	int *p;
    	...
    	*p =0;
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    解析:栈上分配的变量初始值是不确定的,也就是说指针p所指向的内存地址是不确定的,后面用*p访问不确定的地址会导致不确定的后果,可能引发段错误,也可能以外改写了数据而导致程序在随后的运行中出错。像这种指向不确定地址的指针称为野指针,为避免野指针,在定义指针变量时就应该明确地给它赋值,或把它初始化为NULL:

    int main(void)
    {
    	int *p = NULL;
    	...
    	*p =0;
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    NULL在C标准库的头文件stddef.h中定义:

    #define NULL ((void *) 0)
    
    • 1

    指针也是一种标量类型,可以用()运算符做强制类型转换,其他标量类型也可以转换成指针类型,指针类型也可以转换成其他标量类型,比如在上面的定义中把整形的0强制转成void *指针,这个指针指向0地址,称为空指针

    空指针的特殊之处在于,操作系统不会把任何数据保存在地址0及其附近,也不会把地址0~0xfff的页面映射到物理内存,所以任何对地址0的访问都会立刻导致段错误。*p = 0;会导致段错误,就像放在眼前的炸弹一样很容易找到,相比之下,野指针的错误就像埋下地雷一样,更难发现和排除,这次走过去没事,下次走过去就有事。

    **void *类型。**在编程时经常需要一种通用指针,可以转换为任意其它类型的指针,任意其它类型的指针也可以转换为通用指针。ANSI在将C语言标准化时引入了void *类型,void *指针与其它类型的指针之间可以隐式转换,而不必用类型转换运算符。

    void func(void *pv)
    {
    	/* *pv = 'A' is illegal */
    	char *pchar = pv;
    	*pchar = 'A';
    }
    
    int main(void)
    {
    	char c;
    	func(&c);
    	printf("%c\n", c);
    ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    介绍Vue router的history模式以及如何配置history模式
    由GEE生成逐月MODIS的NDVI影像
    【LeetCode】【剑指offer】【数组中的逆序对】
    51单片机STC89C52RC——5.1 LCD1602液晶显示屏
    2023-09-16 LeetCode每日一题(打家劫舍)
    iTransformer
    数据库系统执行模型
    SSM+家装管理系统 毕业设计-附源码191452
    Nodejs+vue汽车保养美容管理系统vscode前后端分离项目
    电商大促就靠RPA,摆脱重复劳动,急速提效
  • 原文地址:https://blog.csdn.net/qianniuwei321/article/details/126947414