C语言学习——指针(二)
内存属性:
- 内存操作的大小
- 内存的变化性,可读可写
指针指向内存空间一定要保证合法性,常见的段错误大多数跟指针指向内存的合法性有关。
关键字const
一类:
const char *p
[推荐写法] 以p
为节点,往左看,*
代表p
是指针,char
代表从p
这个地址一次读一个字节,const
代表只能去读,不能写。p可以随便指向哪一个地址,但是不能改变地址上的内容。
char const *p
同上
二类:
char *const p
[推荐写法] 以p
为节点,const
代表p的地址不能变,*
代表p
是指针,char
代表从p这个地址一次读一个字节。多用于硬件资源的定义,p指向的地址不能改变,但是地址上的内容可以改变
char *p const
同上
三类:
const char *const p
[少见] 内容、地址都不变,代表ROM空间
*p
和buf[]
的不同:
void main()
{
char *p = "hello world";
char buf[] = {"hello world"};
char *p2 = buf;
}
对于*p
来说,它只是一个地址,它指向的是一段特殊的常量段中,不在main
函数中,因此*p
是不能够更改的。
而buf[]
是在main
函数中申请了一片空间,并将“hello world”
从常量段中拷贝过来,因此*p2
是能够更改的。
关键字volatile
- 防止优化指向内存地址
volatile
多用于硬件:
volatile char *p
当*p
指向的内容不由软件修改,软件仅负责取值时,可能会被编译器优化掉。
#include<stdio.h>
char *p;
void main()
{
XXXXX
while(*p == 0x10) //*p除了在这里做判断使用,其他地方不做操作
xxxxx
}
在上述情况下,由于*p
没有在函数中使用,编译器可能只会进行一次操作,while
永远是死循环
而如果在*p
定义前加上volatile
,C语言会一直读取*p
上的数据,如果不满足会跳出while
循环。
指针运算符
指针的加法
指针的加/减法实际上加的是一个单位,单位的大小可以使用sizeof(*p)查看
int *p = xxxx; //地址为0x12
p+1 = [0x12 + 1*(sizeof(*p))] //当*p为int类型,则加4字节,为char则加1个字节,以此类推
p++
和p--
更新地址,用法同变量
*p[n]
n:ID,标签
- 可以理解为地址变量的标签访问,取出标签里的值
p[n]即为p+n
不同点:
p+n为地址,p[n]会自动将内容取出
程序中声明变量,是从高地址到低地址存储
int main()
{
int a = 0x12345678;
int b = 0x99999999;
}
在CPU中先定义a变量,后定义b变量,则a地址在b地址的上面。定义int类型的指针*p:
p[a] = p[b+1];
逻辑操作符
指针中,>=、<=用的很少,多用==、!=
1.跟一个特殊值进行比较 0x0:地址无效值,结束标志
if(*p == 0x0)
//0x0 最好用NULL
2.指针必须是同类型的比较才有意义,一般是编译器在编译时进行比较
char * 不能和int *比较
多级指针
int **p;
可以理解为存放地址的地址(存放盒子的盒子)。