4. 指针

在定义时:* 只是一个标识,标识是指针变量

在使用时:p 指针变量--->地址

                 *p 取出地址中的数据

一、指针的概念

1.1 指针变量的定义:数据类型 * 变量名;

        char *p;//sizeof(p) = 8;

        int *q;//sizeof(q) = 8;

        float *w;sizeof(w) = 8;

指针指向空间类型:

        char *p; //p指向的空间类型:char

        int *q;  //q指向的空间类型:int

        float *w; //w指向的空间类型:float

① 一级指针

int *p = NULL;

        指针大小:sizeof(p) =  8字节

        变量名:p;

        p的类型:int *;(除去变量名,剩下的就是变量类型)

        类型含义:该数据类型,用来定义指针变量,指针变量,用来存储地址。

        类型大小:规定,指针大小,在我们64位系统下,固定为8字节

                         (64位的二进制数,占8个字节(1字节=8位,64位,就是8字节))

        p指向的空间:int类型;

        指针偏移:指针+1,地址偏移指针指向空间的大小

        p+1;//地址偏移4字节

② 二级指针

含义:指针指向的空间,存放的内容仍然是一个地址。

定义方式:数据类型 **变量名;

int **q = NULL;

        指针大小:sizeof(q) =  8字节

        变量名:q;

        q的类型:int **;

        q指向的空间:int *类型;(int *类型8字节)

        q+1;//地址偏移 8 字节

1.2 指针初始化

1》int *p = NULL; //NULL就是0号地址

2》int a = 200; int *p = &a;

int *p = NULL;p = &a//&a:int *

3》野指针:int *p ;//只定义,不赋值,p是随机数        (要避免野指针的出现)(不赋值,容易出现占用内存的情况

*p = 200;//错误的    //p是存放地址的一个空间,然后解指针,又将200赋值给一个不知地址在哪的空间中

解指针:通过地址,操作地址所对应的空间(来得到或者改变该地址所对应的空间的值)

              *p:得到 p 所指向的空间内容

举例:

        int num;

        int *p = #

        操作*p等价于操作num;

4》一般用法

int a = 0;//定义一个普通变量a

int *p = &a;//定义一个指针变量 p,p 中存放的是 a 的地址,也就是 p 指向的是 a;

                    另外 &a 的类型:a为 int 类型,&a 就为 int * 类型

关于 & 和 * 运算符的进一步说明:

        * &:优先级同为2级, 结合性:从右向左。

        * & a:先进行&a得a的地址,再对a的地址进行* 运算

        & * a:先*a得a的值,在取地址 <-> &a

1.3 指针数组偏移

指针+1,地址偏移指针指向空间的大小(与指针指向的空间类型有关)

int a;

int *p = &a;

p++;//p = p+1;//int型地址偏移4字节

指针和指针的减法(使用不多)

两个指针变量在一定条件下, 可进行减法运算。设 p, q 指向同一数组, 则 p-q 的绝对值表示 p 所指对象与 q 所指对象之间的元素个数

指针 和指针的加法:指针不能和指针相加。

① int num[5] = {1,2,3,4,5};

        num+1;  //以元素为单位偏移,偏移4字节

        如果想要得到2,如何得到?     *(num+1)

        //num表示首元素地址:num[0];

        //num[0]:int类型;

        //&num[0]:int *类型;

② char buf[5] = “1234”;

        buf+1; //以元素为单位偏移,偏移1字节

        如果想要得到’2’,如何得到?  *(buf+1)

③ char buf[5] = {‘a’,’b’,’c’,’d’,’e’};

        &buf+1; //以整个数组为单位偏移,偏移5个字节,偏移到e的后边

        char buf[5] = {‘a’,’b’,’c’,’d’,’e’}; 数组取元素:buf[1],*(buf+1)

int num[5];   //num:变量名,数组名

两个性质:

  • 是数组的首元素地址
  • 是整个数组的首地址

把数组名当作地址的时候,以上两个性质有区别:

指针偏移:

num:  //num表示首元素地址,以元素为单位偏移

num+1;偏移一个元素的大小

&num: //&num表示整个数组的首地址,偏移整个数组的大小

&num+1:偏移整个数组大小:

1.4 指针指向一维数组

char buf[5] = {‘a’,’b’,’c’,’d’,’e’};

char *p = buf;

//buf表示首元素地址,

//首元素:buf[0] -- char

//首元素地址:&buf[0] -- char *

取元素:buf[2],*(buf+2),*(p+2),p[2];

1.5 指针指向二维数组

① int num[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

num   

//表示数组首元素地址,偏移:以元素为单位偏移

//首元素:num[0]            int [4]  

//首元素地址:&num[0]          int (*)[4]

num + 1    //指向 num[1];

*(num+1)  //得到 num[1];

num[1]:表示一维数组,不加&,以元素为单位偏移,元素:num[1][0]:int ,&num[1][0]:int *

取元素:num[i][j], *(*(num+i)+j)

&num:&num+1//加整个数组的大小:4 *3*4

② int num[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

int (*p)[4] = NULL;

p = num;//表示首元素地址

//首元素:num[0]   --  int [4]

//首元素地址:&num[0] -- int (*) [4]

取元素:p+1//偏移4 * 4字节

取元素:*(*(p+i)+j),p[i][j],num[i][j],*(*(num+i)+j),*(p[i]+j)

二维数组取元素:注解

int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};

int (*p)[4] = num;

num[1][2];

*(*(num+1) +2)

解释:num不加&,指针偏移以元素为单位,二维数组的元素大小为int [4],num+1,,偏移就是16字节,就指向了二维数组的第二个元素的首地址,依旧是地址,通过解指针可以得到地址中的内容,即*(num+1)可以得到num[1],*(num+1)等价于num[1],但是num[1]依旧是一个数组,此时num[1]就是一个一维数组,num[1]为数组名,数组名不加&,偏移以元素为单位,num[1]的元素为int 类型,因此偏移以int为单位,num[1]+2能得到上面黄色的7的地址,再解指针,*(*(num+1) +2)就能得到7这个值!

1.6 指针数组

int num[5];    //num:变量名,数组名

两个性质:

  1. 是数组的首元素地址
  2. 是整个数组的首地址

把数组名当作地址的时候,以上两个性质有区别:

指针偏移:

        num://num表示首元素地址,以元素为单位偏移

        num+1;偏移一个元素的大小

        &num://&num表示整个数组的首地址,偏移整个数组的大小

        &num+1:偏移整个数组大小

1.7 C语言的五大区

  1. 堆区:预留给开发人员的,必须手动开辟,用函数开辟空间,malloc,手动释放free;
  2. 栈区:由编译器自动开辟的,自动回收 -- 局部变量,函数形参
  3. 全局区/静态区:全局变量,由static修饰的变量(成为静态变量)
  4. 常量区:不能改变,只读
  5. 代码段:存放二进制代码

指针指向常量区:

        char *p1 = “123456”;

        char *p2 = “asdf”;

        char *p3 = “qwe”;

        char *arr[3] = {“123456”,“asdf”,“qwe”};

*p 打印出来是1;

*(p+3) 打印出来是4;

*p = 30;//错误的,常量区不能被改变

1.8 const:修饰变量,使其只读

1》修饰普通变量:

const int num = 100;

num = 200;

2》修饰指针(在*p的前边,不能改变内容,在p前边,不能改变指向)

①const int *p:修饰*p:不能通过p改变p指向空间的内容

②int * const p:修饰p:p的指向不能改变

③int const *p:修饰*p:不能通过p改变p指向空间的内容

④const int *const p:修饰p和*p:p的指向不能改变,不能通过p改变p指向空间的内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值