指针是一块内存地址的首地址,这其中包含两个概念:
1.指针是内存地址;
2.指针还包括内存大小,void指针占用一个指针大小。
比如:int *a指的是内存地址a,大小为int的内存块。
1.普通指针和数组指针
#include
int main()
{
char a[4];
char (*pa)[4],*pb;
pa=&a;
pb=&a[0];
printf("pa占用内存大小是:%d\n",sizeof(*pa));
printf("pb占用内存大小是:%d\n",sizeof(*pb));
printf("pa是:%p\n",pa);
printf("pa+1是:%p\n",pa+1);
printf("pb是:%p\n",pb);
printf("pb+1是:%p\n",pb+1);
return 0;
}
pa占用内存大小是:4
pb占用内存大小是:1
pa是:0x7ff7b425df18
pa+1是:0x7ff7b425df1c
pb是:0x7ff7b425df18
pb+1是:0x7ff7b425df19
在上面的案例中,&a和&a[0]都表示char型数组a的首地址,但是他们的类型并不相同。
&a[0],a先和[0]结合,所以&a[0]是一个元素的大小,在这里是1字节;
&a,本质上是char *(&a)[4],是数组指针,此时&a表示的是char *[4]类型指针,是4字节;
根据开头的原理,指针是内存块,指针的值是内存块的首地址,指针的类型是内存大小。
因此,指针的递增(+1)指的是类型大小的递增。
指针数组和数组指针的概念参考:c语言进阶笔记
2.不同指针间的类型转换
不同类型指针的强制转换会造成内存变化,但首地址不会变。
int main()
{
int a=12345678;
int *pa=&a;
char *pb=(char *)&a;
printf("pa:%p\n",pa);
printf("pa_value:%d\n",*pa);
printf("pb:%p\n",pb);
printf("pb_value:%d\n",*pb);
return 0;
}
pa:0x7ff7b0ebaf18
pa_value:12345678
pb:0x7ff7b0ebaf18
pb_value:78
同时可以发现,这个内存模型是大端对齐。
通过指针定义的字符串形式如下:
char *str="hello";
此时str具有只读属性,不能被修改:
#include
int main()
{
char *a="hello";
*(a+1)='B';
printf("%s\n",a);
return 0;
}
此时编译会成功,但执行会崩溃,因为通过指针定义的字符串在内存中具有只读属性。
如果指针指向的字符串不具有只读属性,那么就可以对其进行修改:
#include
int main()
{
char a[20]="abc";
char *p;
p=a;
*(p+1)='2';
printf("%s\n",p);
return 0;
}