C语言初阶指针详解

目录

指针基本概念

        什么是指针

        什么是地址

         地址与内存单元

        变量地址

        什么是指针变量

        总结

指针和指针类型

        指针类型

        指针类型的定义

        指针类型的意义

指针+-整数

指针关系运算

 指针解引用

野指针

        野指针形成原因

        如何规避野指针

指针和数组

二级指针

        什么是二级指针

        多级指针的取值规则

指针数组

本篇文章适用于对c语言有一定了解的同学,文章详细介绍了初阶指针学习的所有知识点,欢迎各位阅读。

指针基本概念

        什么是指针

       1, 指针是内存中一个最小单元的编号,也就是地址。

        2,平时口语中说的指针,通常指的是指针变量,是用来存放地址的变量。

        什么是地址

        1,生活地址

        

         2,内存中的地址

         地址与内存单元

        1,地址如同房间上的门牌号,通过这个门牌号我们可以找到所对应的房间。

        2,内存单元如同房间,房间里面存储的是数据。

        变量地址

        系统分配给"变量"的"内存单元"的起始地址。

int num = 6; // 占用4个字节
//那么变量num的地址为: 0ff06

char c = 'a'; // 占用1个字节
//那么变量c的地址为:0ff05

        什么是指针变量

        1,在C语言中,允许用一个变量来存放其它变量的地址, 这种专门用于存储其它变量地址的变量, 我们称之为指针变量。

int main()
{
    int a = 10;//在内存中开辟一块空间
    int* p = &a;//int占4个字节,这里是将a的4个字节的第一个字节放到
p当中去,而这时的p就是一个指针变量

    return 0;
}

        总结

        1,指针变量是用来存放地址的,地址是唯一标识一个内存单元的。

        2,指针的大小在32位系统是4个字节,在64位系统是8个字节。

指针和指针类型

        指针类型

        1,我们大家都知道变量都是有类型,比如整型,浮点型,字符型,那么指针有没有类型呢?

准确的来说是有的。

比如:我们要把一个整形放在个指针变量当中去,肯定是要用一个整形指针来接收。

int num = 10;
p = #

有以上代码,我们取num的地址放在p中去,p肯定是一个指针,那么他的类型是怎么样呢?

        指针类型的定义

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

我们可以看到指针类型的定义方法是:type+*的方式。

        指针类型的意义

        1,在不同的编译器下,所用指针虽然占用的内存空间一样,但不同的变量类型所占用的字节空间不同。

        2,int占4个字节,char占1个字节,double占8个字节,那我们怎么知道从起始地址开始向后访问多少个字节呢?

        3,指针变量所指向的指针类型,决定了你向后访问一次要走多少个字节,通俗的说也就是步长,比如int是4个字节,你往后走一步,也就是走了4个字节。

指针+-整数

  1. 指针变量的自增自减运算。指针加 1 或减 1 运算,表示指针向前或向后移动一个单元(不同类型的指针,单元长度不同)。这个在数组中非常常用。
  2. 指针变量加上或减去一个整形数。和第一条类似,具体加几就是向前移动几个单元,减几就是向后移动几个单元。
#include <stdio.h>
//演示实例
int main()
{
 int n = 10;
 char *pc = (char*)&n;
 int *pi = &n;
 
 printf("%p\n", &n);
 printf("%p\n", pc);
 printf("%p\n", pc+1);
 printf("%p\n", pi);
 printf("%p\n", pi+1);
 return  0;
}

指针关系运算

        假设有变量px,py

  1. px > py 表示 px 指向的存储地址是否大于 py 指向的地址
  2. px == py 表示 px 和 py 是否指向同一个存储单元
  3. px == 0 和 px != 0 表示 px 是否为空指针
//定义一个数组,数组中相邻元素地址间隔一个单元
int num[2] = {1, 3};

//将数组中第一个元素地址和第二个元素的地址赋值给 px、py
int *px = &num[0], *py = &num[1];
int *pz = &num[0];
int *pn;

//则 py > px
if(py > px){
	printf("py 指向的存储地址大于 px 所指向的存储地址");
}

//pz 和 px 都指向 num[0]
if(pz == px){
	printf("px 和 pz 指向同一个地址");
}

//pn 没有初始化
if(pn == NULL || pn == 0){
	printf("pn 是一个空指针");
}

 指针解引用

        1,指针解引用重点实在内存中去观察它的变化。

int main()
{
 int n = 0x11223344;
 char *pc = (char *)&n;
 int *pi = &n;
 *pc = 0;   
 *pi = 0;  
 return 0;
}

野指针

        概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

        野指针形成原因

        1,没有进行指针初始化

int main()
{
    int *p;
    *p=20;

    return 0;
}

这里的局部变量指针没有初始化,那么它默认的就是随机值,那么他此时就是一个野指针。

        2,指针越界访问

#include <stdio.h>
int main()
{
    int arr[10] = {0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=11; i++)
   {
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
   }
    return 0;
}

这里指针的指向范围超出了数组arr的范围,就是越界访问,而此时指针p的值已经不知道了,所以他是野指针。

        如何规避野指针

        1,指针初始化

        2,小心指针越界

        3,指针指向释放空间,及时置NULL

        4,避免返回局部变量的地址

        5,指针使用之前检查指针的有效性

指针和数组

        1,一个变量有地址,一个数组包含若干元素,每个数组元素也有相应的地址, 指针变量也可以保存数组元素的地址。

        2,只要一个指针保存了数组元素的地址,我们就称之为数组元素指针。

#include <stdio.h>
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9,0};
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    return 0;
}

注意: 可见数组名表示的就是数组首元素的地址。

既然我们可以把数组元素放到指针中去,那么我们也可以通过指针去访问数组元素。

int main()
{
    int arr[] = {1,2,3,4,5,6,7,8,9,0};
    int *p = arr; //指针存放数组首元素的地址
    int sz = sizeof(arr)/sizeof(arr[0]);
    for(i=0; i<sz; i++)
   {
        printf("&arr[%d] = %p   <====> p+%d = %p\n", i, &arr[i], i, p+i);
   }
    return 0;
}

 所以p+i实在计算数组arr小标位i的地址,那么我们就直接可以通过指针来访问数组

int main()
{
 int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 int *p = arr; //指针存放数组首元素的地址
 int sz = sizeof(arr) / sizeof(arr[0]);
 int i = 0;
 for (i = 0; i<sz; i++)
 {
 printf("%d ", *(p + i));
 }
 return 0;
}

二级指针

        什么是二级指针

        1,如果一个指针变量存放的是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量,那我们就称这个为二级指针。

 对于二级指针的运算有:

1,*ppa通过对ppa中的地址解引用,这样找的是pa,*ppa访问的其实就是pa。

int b = 20;
*ppa = &b;//等价于 pa = &b;

2,**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a 。

**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

        多级指针的取值规则

int ***m1;  //取值***m1
int *****m2; //取值*****m2

指针数组

        1,首先我们要明白,指针数组不是指针而是数组。

        2,指针数组里面所有元素都是指针。

 在指针向下访问允许以下运算:

  • 加一个整数(用+或+=),如p+1
  • 减一个整数(用-或-=),如p-1
  • 自加运算,如p++,++p
  • 自减运算,如p–,--p

注意:数组名虽然是首元素地址,但是数组名所保存的数组首地址是不允许随便修改的。

    int x[10];
	x++;  //错误
	int* p = x;
	p++; //正确
  • 结论: 访问数组元素,可用下面两种方法:
    • 下标法, 如a[i]形式
    • 指针法, *(p+i)形式
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值