指针
指针变量通俗的理解就是存放地址的盒子,也就是说指针指向内存空间的地址,但要注意的是指针指向内存空间的低地址。
例如:以下例子是一个字节的方式读地址,输出78
使用一般原则:
C语言使用指针要有有2个疑问?
1、分配一个盒子,盒子要多大?
在32bit系统中。指针就4个字节
2、盒子里存放的地址所指向内存的读取方法是什么?
是int 还是char等等;
另外还要注意的有:
指针读取内存尽量使用无符号指针 ;
操作指针时一定要确定指针指向的类型和指针类型相同;
指针指向的地址一定要保证合法存在;
指针指向字符串不一定有‘\0’结尾,逐一拷贝一定要注意,结束在哪里?一般定义个数拷贝三要素:
源 目的地 拷贝个数
一般使用方法:
Int *p;
P = &a;指针p指向a的地址
Printf(“%d”,*p);取出a的值
指针修饰符
const char *p;
一般指向字符串“hello world”等 表示指针指向的内容是按照一个字节的方式去读,指向的数据为只读数据,指向的地址可以变,内容不可改变和 char const *p
相同;
char * const p;
指向的地址不可以变,内容可以变 一般用于硬件资源
const char * const p
指向的地址不可以是ROM
volatile char *p ;
防止优化指向内存地址,不理解的可以看学习笔记(3)
指针基本运算
+:如果p = 0x12;那么p+1 为[0x12 + 1*(sizeof(*p))]
**- **:与++相反
指针逻辑运算
“==”
“!=”
跟一个特殊值进行比较,其中0x0表示地址的无效值,结束标志,一般来说指针必须是同类型的比较才有意义
如:
if( p == 0x0)
NULL
多级指针
存放地址的地址空间(和一级指针类似)
理解图:
指针数组
int (*p)[5] 定义一个指针p 读内存的方式为 5个int的读 ,也可以理解为指针p指向一个包含五个元素的数组,指针类型为int
int *p[5] 定义数组p包含五个元素,数组p为int * 类型的,即每个元素都是一个指针
读取原则:有(),先读(),没(),先右后左,每遇到()就改变方向:
int *(*(*f)(int)) [10]
先括号里的*f,是一个指针,往右看(int),说明是一个函数指针,碰到()往左看*,返回的是一个指针,又碰到(),往右看,数组,说明是一个指针数组,往左int型的指针数组,即是一个函数指针,参数为int 返回值为一个指向指针数组的指针
数组空间初始化
数组空间赋值一般按照数组标签逐一赋值处理,但如果像变量一样赋值,大的数组空间工作量过大,可以只赋值要初始化的,如:
int a[10] = {1,2,3};
此时a[0] = 1 a[1] = 2 a[2] = 3 其他的会被置为0;
字符数组可以char buf[10] = {'a','b','c'};
不同的是buf当成一个字符串来看,最后会加上一个’\0’或者0,字符串的重要属性,结尾一定有个’\0’;当然也可以这样初始化char buf[10] = {"abc“};
//C语言编译器会在结尾自动加‘\0’,但是不可以直接buf = "123";
这样初始化。
需要注意的是:
指针指向字符串不一定有‘\0’结尾,操作字符串时一定要注意,结束在哪里?弄清楚字符串操作三要素:
1、src 源
2、dest 目的地
3、个数
与数组的联系
相同点:
- 指针数组都可以通过*来访问,也都可以通过[ ]来访问
- 数组做参数时相当于指针 f(int a[10]) 等价于f(int *p)和f(int a[])
区别:
- 指针有自己的地址
- sizeof()检测指针的大小是检测指针变量的大小,不是指针指向变量的大小 与数组不同
- 指针需要间接访问,数组可以直接访问
- 指针主要用于非连续地址,数组是连续的
- 数组的地址就是变量名
int main()
{
int a[10] = { 1 };
int b = 0;
int *p = b;
printf("&p:%p\n",&p);
printf("&b:%p\n", &b);
printf("a : %p\n", a);
printf("a+10 : %p\n", a+10);
printf("&a+1 : %p\n", &a+1);
}
&p:00EFF938
&b:00EFF944
a : 00EFF950
a+10 : 00EFF978
&a+1 : 00EFF978