其他
聊聊指针
指针是什么?
指针和其他的int, float等类似, 是一种类型. 有类型就有相应类型的变量和常量. 本文主要讨论变量的情况.
指针变量就是一种变量, 和其他种类的变量类似, 但指针和其他变量又有区别.
首先C语言作为一种类型语言, 每个变量都会有几个属性.
变量名称. 变量类型. 变量的值.
指针变量的名称. 指针变量的类型, 即指针类型. 指针变量的值, 即一个地址. 指针变量的值所指向的内存里的数据类型. 本文称做"指向类型".
int a = 3; int *b = &a;
类型
char * const * (*next)()
, next是一个指针, 那么其指向类型是什么? 这个声明/定义比较复杂, 日常编程可能就会碰到比较 复杂的情况, 所以要搞清楚指针首先要懂得怎么看一个声明/定义的变量的类型.<<c专家编程>>
这本书中有一部分内容专门讲解怎么分析 一个变量的类型, 值得参考.从变量名称开始读取, 然后依照优先级按顺序处理. 优先级从高到低 a. 括号内优先级高. b. 后缀操作符, ()表示一个函数, []表示一个数组. c. 前缀操作符, *
表示"指向...的指针"如果const, volatile后面为类型(int, long等), 那么作用于类型, 其他情况下作用于const, volatile左边的指针 *
.
char * const * (*next)()
括号内的优先级最高, 即首先看 (*next)
next左边为 *
, 因此next是一个指针类型然后后缀()的优先级更高, 因此next是一个指针, 指向一个函数. 接着是const右边的 *
, 表示next是一个指针, 指向一个函数, 该函数返回值类型为一个指针.char * const
看作一个整体为指向字符的常量指针.
<<c专家编程>>
类型有什么用?
int a = 3
, 那么在内存中会存储一个数据3, 那么对于int类型具体来说.这个数据3会占用4字节(常见32位机器与64位机器上int类型占用4字节). 实际上是有4字节的内存, 内容是0×00000003. 因此int类型就规定了占用的内存大小. 对于int类型就可以进行+,-,*,/等操作, 但是不能进行取指针值(*a)的操作. 能够进行什么操作, 也是由类型规定的.
sizeof
int *a;
double *b;
sizeof(a) == sizeof(b);
sizeof(*a) != sizeof(*b);
指针类型的操作
+
操作.double a[3] = {1, 2, 3};
double *b = a;
printf("b: %p, content: %f\n", b, *b);
printf("b+1: %p, content: %f\n", b+1, *(b+1));
int c[3] = {1, 2, 3};
int *d = d;
printf("d: %p, content: %d\n", d, *d);
printf("d+1: %p, content: %d\n", d+1, *(d+1));
b: 0x7fff5f9ec7e0, content: 1.000000
b+1: 0x7fff5f9ec7e8, content: 2.000000
d: 0x7fff5f9ec7d0, content: 1
d+1: 0x7fff5f9ec7d4, content: 2
数组类型
int a[10] = {0};
int *b = a;
int (*d)[10]= &a;
int c;
c = a[1];
c = b[1];
a[1]
和b[1]
的区别就在于数组是一个常量, 而不是变量(变量本身需要占用内存).c = a[1]
是直接从a表示的内存地址偏移4字节的内存中取数据. 仅包含一次内存读操作.c = b[1]
是首先从内存中取出变量b的值, 然后将变量b的值偏移4字节, 然后从这个地址的内存中取数据. 包含2次内存读操作. 第一次是读取变量b的值.数组名称相当于地址常量, 那么这个地址指向一段内存, 因此这个地址本身会有指向类型, 其指向类型就是数组的元素类型. 例如 int a[10]
, 那么a的指向类型就是int
, 因此a+1结果实际上指向a[1].sizeof(a)
是计算整个数组的类型.sizeof(*a)
是计算其指向类型的大小.可以对数组名进行 &a
操作(取地址), 实际上&a
的指针值和a的指针值一样, 而且也是个地址常量, 但是&a
的指向类型 是int [10]
, 即指向一个包含10个int元素的数组, 所以sizeof(*&a)
, 计算&a的指向类型的占用内存大小就是40.数组作为函数参数传递后, 在函数内使用等价于指针. 因为函数传参是进行值传递, 相当于有一个指针变量记录数组的地址值.
函数指针
int foo(int a)
{
return a;
}
int (*p_foo)(int a) = foo;
printf("%d, %d, %d\n", sizeof(foo), sizeof(*foo), sizeof(&foo));
printf("%d, %d\n", sizeof(p_foo), sizeof(*p_foo));
1, 1, 8
8, 1
对函数名本身计算类型占用内存大小, 其值为1, 对于函数名的指向类型计算内存占用大小其值也为1. foo, *foo, &foo的类型相同, 但是sizeof(&foo)结果为8. 函数指针可以进行多次解引用, *****p_foo == *p_foo = p_foo
.函数指针可以进行调用, p_foo(3)
;
强制类型转换
double a = 23.456;
int *b = (int *) &a;
小结
指针名称 指针类型 指针内容: 指向什么地方. 指向类型: 指向内存的数据类型是什么.
猜你喜欢