指针是C语言里最强大的类型,合理的使用指针能够使程序灵活简洁又高小,但是使用不合理的话又会给程序带来灾难性的后果,因此,理解并掌握指针的用法能够使我们的程序又快速又健壮,写出大神级别的代码。
要想了解指针,我们分成下面两个部分:
1、指针本身的类型。
2、指针指向的类型。
一、指针本身的类型
指针的初始化是由指针类型和指针变量组成。
国际惯例,直接上代码:
# include
# include
int main() {
size_t size = sizeof(long);
printf("长整型(long)的长度 %ld \n", sizeof(long));
long* ptr = malloc(size);
*ptr = (long) 1024;
printf("指针指向的实际地址 %p \n", ptr);
printf("指针转成无符号长整型 %lu \n", (long unsigned)ptr);
printf("指针转成无符号十六进制 %lx \n", (long unsigned)ptr);
printf("指针值 %ld \n", *ptr);
printf("指针的长度 %ld \n", sizeof(ptr));
ptr += 1;
printf("加1后的指针: %p \n", (ptr));
printf("加1后指针转成无符号长整型 %lu \n", (long unsigned)ptr);
printf("加1后指针转成无符号长十六进制 %lx \n", (long unsigned)ptr);
return 0;
}
其中这句就是指针的初始化并赋值:
long* ptr = malloc(size)
ptr是就是指针变量名,这里的ptr是一个长整型指针(long*),既然是一个变量,就要有对应的值
printf("指针指向的实际地址 %p \n", ptr);
打印出来的结果就是:
指针指向的实际地址 0x55976c0e4670
看到这里大家想必就明白了吧,变量ptr里面存储的实际上是一个内存地址,他指向的是我们malloc申请的内存块的首地址,也就是申请内存块的起始地址。
到这里我们就应该明白了吧,long* ptr 可以拆分成两部分看待:
long* 指定了这个指针的类型是长整型指针,以后对这个指针进行操作的时候都会根据这个类型来进行相应的操作。
ptr 里面存储了一块内存的起始地址,是一个无符号长整型(long unsigned),每次对这个指针进行加1操作的时候,并非对这个无符号长整型进行加1,而是对这个无符号长整型进行加sizeof(long)操作。也就是,指针加1,内存地址偏移sizeof(long)。
↑↑↑↑↑↑↑↑↑↑↑↑ 上面这个是重点,需要注意哦!
二、指针指向的类型
还是刚才这句:
long* ptr = malloc(size)
去掉指针名称ptr和指针运算符*,就剩下一个long了。
OK!就是这个long,就是这个long,就是这个long!
我是不是有点过于激动了,这个long就是指针指向的内容的类型。
好了好了,有点乱,我们梳理一下哈,首先,我们知道获取或者赋值指针类型的内容时,要使用指针运算符,例如这一句:
*ptr = (long) 1024;
当我们给指针指向的内存赋值的时候,我们使用了long型的强制转换,这下明白了吧,*ptr里面存储的是一个long型的数据,也就是我们定义ptr的时候最前面的那个long。
下面是总结时间了
因为我刚刚看了看我自己写的这些东西,ooh my god!我自己也不确定我自己能不能看懂,所以还是总结一下的好。
国际惯例,上代码:
long* ptr;
这一句我们定义了一个long*型的指针;
这个指针的名字叫做ptr;
这个ptr里面存储了一个无符号整形;
这个无符号整形是一块内存的起始地址,通过这个地址就能找到这块内存存储的内容;
但是怎么向这块内容赋值和取值呢?
通过指针运算符*,
*ptr = (long) 1024;
long value = *ptr;
printf("%l", value);
而我们怎么确定这个指针指向的内容是什么类型的呢?
把long* ptr 的指针变量名ptr和指针运算符*都删掉,剩下的long就是ptr指向的内容的类型了,通过指针取值和赋值时都会根据这个long进行类型检查。
指针运算不等于内存地址的运算,指针变量的加减是指针地址根据指针类型的长度进行偏移,例如long型指针ptr做加1运算时,实际ptr地址进行了(内存地址 + sizeof(long))的偏移运算。