指针的基本意义
在创建变量时 *号和变量名结合,不和类型名结合
编译器在编译时,是从右到左识别的,哪怕在定义时
(int*)p,s;
这样写也是错误的,这样的写法编译器会识别为强转功能,但是p和s并没有初始化,自然也就无法进行强转
强转的写法是:
int a=0x12345678;
int *ip=&a;
char *cp=(char*)&a;
char *p=(char*)&a;
*p='a';
p=p+1;
*p='b';
p=p+1;
*p='c';
p=p+1;
*p='d';
p=p+1;
要明白上面的程序首先我们要明白小端存放的原理
小端存放
通过这个程序我们可以知道不同类型转换时,替换值的过程,建议通过编译调试来看看
这里p=p+1;因为是char*类型,所以只移动了一个字节。而且高位数存放在高地址,低位数存放在低地址,所以从低位数开始改变
ps:p=p+1 相当于p=p+sizeof(char)*1;
*p=‘a’;
*p=‘b’;
*p=‘c’;
*p=‘d’;
我们也不能做这样的操作
int *p;
p=&10;
这样也是不对的,在给p传地址时,我们不能对常量取地址
int p=&a(将a的地址传给p,而不是p)
指针类型的大小是4字节
例如
int a=10;
int b=20;
int *p=NULL
p=&a; 这里我们要注意,这是*p是a,而不是10,a才是*p的指向,只不过a被赋值为10罢了
*p=100;
p=&b;
*p=200;
为了解释指针的值的问题,在这我假设a的地址时0x0012ff28,他存放的是10,b的地址是0x0012ff1e,存放的是20。p的地址是0x0012ff10,存放的是a或b的地址0x0012ff28/0x0012ff1e,这要看程序员将谁的地址给了p。
那么有下面的几个等式
&p=0x0012ff10;
p=0x0012ff28/0x0012ff1e;
*p=a/b
*p=100(相当于给a赋值为100)
另外引入另一个知识,关于数在内存中存放的问题。以及指针识别能力问题
double x=12.32;
int a=10;
char y='a';
由于x86系统采取的是小端存放,所以一般以其地位地址所谓某类型变量的首地址。
我画图来解释。
以此类推,可知++p或者p++或者p+1这些加的都是对应类型的字节数。
那么自然有可能发生
char *p
int *p
double *p
的指针同时都指向了0x0012ff00,虽然都指向了地位的第一个地址,但是代表的意义不同
虽然指针类型的大小是4字节
但是每个类型的指针的识别能力是有限的,比如char型的指针,每次只识别内存中的一个字节来确定char的值,int类型的指针会识别4字节内存来确定int的值。而double会识别8个字节的地址。要注意,不同类型的指针不能相互赋值
还要注意我们在使用指针是切记不能定义野指针
我们需要注意的是,我们需要区分野指针和失效指针,我举个例子来讲解
如int *p;
这是上面的指针p就是野指针,我们为指针p开辟了一个4字节的内存空间,但是我们没有给这个指针添加指向。那么我们无法知道指针p的指向。
而 失效指针
比如
void *fun()
{
int a=100;
return &a;
}
当这个函数使用完毕后,返回的指针变为了失效指针,它依旧指向原来的空间,但是那块空间依旧失效没有了原来的主人。那么即使得到了原来的结果,在实际上也是没有意义的
int *p;//没有对象的指针
解决野指针的方法有
int *p=NULL;//令其为空
int *p=&a//给他一个对象
同时我们还要知道指针的下标操作
比如char *p = “abcdef”;
此时p[2]值 为’c’。而p表示字符串"abcdef"的首地址,*p的值则相当于p[0],值为’a’。
如果我们在函数中要调用指针,在使用前我们必须要进行判空操作
if(p==NULL);
首先要知道指针都是四字节的
下面举一个例子
可以让我们知道指各种类型指针的加一的范围
char a3, a2, a1, a0;
char *p3, *p2, *p1, *p0;
char **s;
//假设 a3, a2, a1, a0和*p3, *p2, *p1, *p0存放的内存空间都是连续的,并且s指向p
//求s+1 =4字节
//*s+1 =4字节
//**s+1 =其本身的数加一
s+1=s+sizeof(type*)*1;//二级指针+1,指的是指针,+1加指针类型的4个字节
*s+1=s+sizeof(type)*1;//一级指针+1,指的是不同的类型变量,+1加的是指向类型的字节数
**s+1=数值加一//就是数值加一
接下来要说明指针变量在和0,NULL比较是的方式
指针变量作为if的判断条件时,同样有三种方式
A:if(p==0) if(p!=0)
B),if(p ) if(!p);
C) ,if(NULL == p); if(NULL != p);
哪一组或是那些组正确呢?我们来分析分析:
A)写法:p 是整型变量?容易引起误会,不好。尽管 NULL 的值和 0 一样,但意义不同。
B)写法:p 是 bool 型变量?容易引起误会,不好。
C)写法:这个写法才是正确的,但样子比较古怪。为什么要这么写呢?是怕漏写一个 “=”号:if(p = NULL),这个表达式编译器当然会认为是正确的
最后介绍一下普通的利用指针识别能力的特质完成数据打包和解析
int main()
{
int a = 3;
int c = 'x';
float f = 3.14f;
char buffer[20];
// 在下面实现打包代码
*((int*)buffer) = a;
*(buffer + sizeof(int)) = c;
*((float*)(buffer + sizeof(int) + sizeof(char))) = f;
// 在下面实现解包代码
printf("a = %d\n", *((int*)buffer));
printf("c = %c\n", *(buffer + sizeof(int)));
printf("f = %f\n", *((float*)(buffer + sizeof(int) + sizeof(char))));
return 0;
}
所以同理也可以这么做
int arr[3] = { 1, 2, 3 };
int x = 10;
*((int*)arr) = x;
它的另一种写法为:
// 在下面实现打包代码
int *pi = (int*)buffer;
*pi = a;
char *pc = (char*)(pi+1);
*pc = c;
float *pf = (float*)(pc+1);
*pf = f;
// 在下面实现解包代码
printf("a = %d\n", *pi);
printf("c = %c\n", *pc);
printf("f = %f\n", *pf);