C语言拾遗——指针

主要讲解指针的概念 ,由于笔记跨越时间长,前后可能不连贯。
指针 地址 数组之间的差别
1.指针是个量,对应着一块内存区域;
2.指针存储的信息是某个内存单元的地址。
int p=(int )300500是一个指针,p存储的是地址,指针有类型,从哪里开始(0x300500),长度是多少(sizeof(int)=4),从哪里结束(0x300504),得知了类型以后,就知道这片内存数据是如何解析;

而数组在内存中线性顺序排列,数组名是数组的首地址,可以看作是一个常量指针,其他元素的地址就等于首地址+sizeof(类型)*下标,因此我们可以通过指针间接引用数组。

使用下标的方法访问数组

 #include <stdio.h>
int main(void) { 
     int a[10];
    int *p=a;
    for(int i=0;i<10;i++)
    {
        p[i]=i;
        printf("%d\n",a[i]);
    }
    return 0;
}

a[i]与*(a+i)等价 &a[i]等价于 a+i;
a是第一个元素的首地址,指向int 类型,每次指针相加,相加指针指向的类型的大小。
*(a+i)等价于根据地址a+I 往前读取四个字节,读取内容。

使用指针变量间接访问

#include <stdio.h>
int main(void) { 
        int a[10];
    int num=0;
    for(int *p=a;p<a+10;p++)
    {
        *p=num;
        num++;
    }
    for(int i=0;i<10;i++)
    {
        printf("%d\n",a[i]);
    }
    return 0;
}

野指针、空指针和空类型指针
指针使用之前必须初始化,如果不初始化,会将内存中的垃圾数据作为地址,对这个地址的访问没有任何意义,甚至程序挂掉。

如果在指针变量声明之初确实不知道该将此指针指向何处,最简单的方式是将其置“0”,C语言中提供了关键字NULL。其基本形式为:类型* 指针变量名;如
int *pNum=NULL;

值为NULL的指针称为空指针,这意味着,指针并不指向任何地址。 在头文件 stdio.h 中,NULL 定义为常量。
void *p 为空类型的指针,可以接受任何类型指针的赋值,可用于保存地址。空类型指针可以转换为任何类型的指针
指向为空的指针为空指针,当释放掉malloc函数分配的内存之后,应该将指针赋值为空,防止反复释放内存出错。

一级指针
一级指针就是最常见的指针,定义为 : 指针类型 *指针变量名=地址,如

int a=0;
int *p=&a;      //p是一个指针变量,p可以是任何变量的地址
*p=10;
printf("a的值为%d",a);

这样就完成了一个最简单的指针应用,通过访问所指向对象的地址,修改数据。
指针类型与指针所指向的类型
所谓指针类型,指的是声明指针变量时位于变量名前的“类型*”,而所谓指针所指向的类型,指的是为指针初始化或赋值的变量类型。指针的类型必须要与指针指向的类型一致,不一致,大小不一样,解析方式不一样。
不是同一类型的指针,不可以任意赋值。

int num;
int *a=&num;
char *b=NULL;
a=b;        //这是不合法的,类型不同
int *c=a;       //这是合法的,同类型指针的赋值

不同的数据类型,大小不一样(如果强制赋值的话,就会少读取或多读取,内存有很多垃圾0,1),就算大小一样,如int和float大小都为4个字节,解析方式不一样,结果也不一样。
a和c指向num的地址,也就是说,两个指针指向同一个内存单元,对num的任何改动都会影响*a和*c的值,反之亦然。

二级指针
指针变量也是变量,占据一定的内存空间,有地址就可以用一个指针指向它,指向指针的指针,称为二级指针。常用在外挂中改变一级指针的指向。

#include <stdio.h>
int main(void) { 
int a=8,b=1;
int* pa=&a;     //pa指向a,*pa值为8
int* pb=&b;     //pb指向b,*pb值为1
int** pp=&pa;       //pp是一个二级指针,指向一级指针pa
*pp=pb; //取pp指向地址的内容,即pa的地址,把pb的地址赋值给pa,
*pb=20;     //pa和pb均指向b
printf("*pa的值为%d",*pa);         //*pa的值为20
    return 0;
}

数组指针
指向数组的指针 假设a为数组名,数组类型为int
1维:int *p= a; //前面有足够的解释,不在介绍
2维:int (*p)[10]= a[10];

则定义了一个名为p的指针变量,它可以指向每行有十个整数(即int型)元素的二维数组。p是指向一维数组的指针变量。这句话的理解是首先(*p)[10]是一个指向一维数组的指针变量,意思就是p这个指针是指向一个含有10个元素的数组的,那么p指针每一次加1就相当于把p中存的地址加20(前提是int类型占2个字节,在VC中是占4个字节)。

举个例子:int a[3][3]; int( *p)[3]; p =a; //p=a的意思是把数组a的首地址存放到p中那么p[1]就是a[1][0]的地址,p[1][0]就等于a[1][0],而p[1][2]就等于a[1][2].

指针数组
指针的数组,一个数组里面存放同类型的指针,如 int *(a[10]); 或省略括号 int *a[10];
表明这是一个有10个元素为int *类型的数组。
注意两者之间的定义差别

int (*p)[10]= NULL;         //数组指针,先有(*p),表明是指针
int *(a[10]);               //指针数组,先有(a[10]),表明是数组

函数指针
如果在程序中定义了一个函数,在编译时,编译系统为函数代码分配一段存储空间,这段存储空间的起始地址,也是函数名,称为这个函数的指针。有地址,就可以定义一个指向函数的指针变量,用来存放某一函数的起始地址,这就意味着此指针变量指向该函数。例如:
int (*p)(int,int);
定义p是指向函数的指针变量,它可以指向类型为整型且有两个整型参数的函数,即int fun(int x,int y) p的类型用int (*)(int,int)表示,当调用这个函数指针时,传入相应的参数,就会执行这个函数。

函数返回值是指针
一个函数可以返回一个整型值、字符值、实型值等,也可以返回指针型的数据,即地址。其概念与以前类似,只是返回值的类型是指针类型而已
定义返回指针值的函数的一般形式为 类型名 *函数名(参数表列);
void * fun(void); //表明fun()的返回值是void*类型
如果程序中需要函数返回地址,就需要用到返回值是指针的函数。

指针运算
指针++就是按照指针类型的大小,前进一个类型的大小,int前进四个字节
指针 ++ 和 – 只有在数组的内部才有意义。

若有p=a(p指向数组a),则:p++(或p+=1),表示p指向下一元素。
*p++*(p++)等价。同样优先级,结合方向为自右向左。
*(p++)*(++p)
前者是先取*p的值,后使p值加1,相当于a[i++];后者是先使p加1,再取*p,相当于a[++i]。

(*p)++表示p所指向的元素值加1,而非指针值加1
p++是先引用,再自增,自增一个sizeof(指针指向的类型)的大小。
++指针在数组内部向前移动一个元素的大小
p=p+1; 指针在数组内部向前移动一个元素的大小

*p++ 等价于 *(p++) , ++是先引用再自增,++优先级高于*
指针在数组内部向前移动一个元素的大小
++p 先自增,再引用
(*p)++ 取出指针指向的内容自增一下
指针的加减法在非数组内部没有任何意义,而且很容易越界报错,因为一个exe不能读写其他exe进程的内存。

指针比较
两个毫无关联的指针比较大小没有意义,因为指针只代表了“位置”这么一个信息, 但是 如果两个指针所指向的元素位于同一个数组(或同一块动态申请的内存中), 指针的大小比较反映了元素在数组中的先后关系。
另外 通过指针是否相等,可以判断是否指向同一地址。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值