11-指针
指针
指针可以直接操作内存和硬件
1. 内存
1.1 内存含义
内存含义:
- 存储器:计算机的组成中,用来存储程序和数据,辅助CPU进行运算处理的重要部分。
- 内存:内部存贮器,暂存程序/数据——掉电丢失 SRAM、DRAM、DDR、DDR2、DDR3。RAM掉电丢失,DDR2,DDR3速率不同
- 外存:外部存储器,长时间保存程序/数据—掉电不丢ROM、ERRROM、FLASH(NAND、NOR)、硬盘、光盘。
内存是沟通CPU与硬盘的桥梁: - 暂存放CPU中的运算数据
- 暂存与硬盘等外部存储器交换的数据
1.2 物理存储器和存储地址空间
有关内存的两个概念:物理存储器和存储地址空间。
物理存储器:实际存在的具体存储器芯片。
- 主板上装插的内存条
- 显示卡上的显示RAM芯片
- 各种适配卡上的RAM芯片和ROM芯片
存储地址空间:对存储器编码的范围。我们在软件上常说的内存是指这一层含义。
- 编码:对每个物理存储单元(一个字节)分配一个号码
- 寻址:可以根据分配的号码找到相应的存储单元,完成数据的读写
1.3 内存地址
启动一个程序,系统在内存上给程序分配一块内存空间,32位操作系统--210*2102^104 -- 4G的内存空间,内存的是由字节组成的,每个字节都会有地址编号,编号从0x00000 0000 - 0xffff ffff
- 将内存抽象成一个很大的一维字符数组。
- 编码就是对内存的每一个字节分配一个32位或64位的编号(与32位或者64位处理器相关)。
- 这个内存编号我们称之为内存地址。
内存中的每一个数据都会分配相应的地址: - char:占一个字节分配一个地址
- int: 占四个字节分配四个地址
- float、struct、函数、数组等
地址:内存编号
2.指针基础知识
2.1 指针与指针变量
地址:内存的编号,我们把这个编号(地址)也叫做指针
- 内存区的每一个字节都有一个编号,这就是“地址”。
- 如果在程序中定义了一个变量,在对程序进行编译或运行时,系统就会给这个变量分配内存单元,并确定它的内存地址(编号)
- 指针的实质就是内存“地址”。指针就是地址,地址就是指针。
- 指针是内存单元的编号,指针变量是存放地址的变量。
- 通常我们叙述时会把指针变量简称为指针,实际他们含义并不一样
指针变量
指针变量存放的是指针地址,所以32位操作系统指针变量大小占4个字节,64位操作系统指针变量占8个字节
2.2 指针变量的定义和初始化
#include <stdio.h>
int main()
{
int a = 10; // a在内存中占4个字节,a在内存中有地址
// 1. *与符号结合表示一个指针变量
// 2. 要保存谁的地址,将他的定义形式放在此处
// 3. 用*p替换掉定义的变量
// 指针变量p的类型,将p涂黑剩下的类型
// 指针变量p保存什么类型的地址,将指针变量p及最近的*一起涂黑,剩下的类型就是指针变量类型
int *p; // *p -- p是一个指针变量,p的类型是int *类型,保存int类型的地址
p = &a;
// 定义指针存储数组地址
int a[10];
int (*p)[10];
int **p; // p的类型是 int \*\* ,保存的是int *类型的地址
}
#include <stdio.h>
int main()
{
int a = 0;
char b = 100;
printf("%p, %p\n", &a, &b); //打印a, b的地址
//int *代表是一种数据类型,int*指针类型,p才是变量名
//定义了一个指针类型的变量,可以指向一个int类型变量的地址
int *p;
p = &a;//将a的地址赋值给变量p,p也是一个变量,值是一个内存地址编号
printf("%d\n", *p);//p指向了a的地址,*p就是a的值
char *p1 = &b;
printf("%c\n", *p1);//*p1指向了b的地址,*p1就是b的值
return 0;
}
2.3 指针变量的使用
指针变量保存谁的地址就指向谁,指针指向谁就可以操作谁
int main()
{
int a = 10;
int *p;
p = &a;
// 在使用的时候,*与p结合,表示取p指针所指向的那块内存空间的内容
*p = 100;
printf("a = %d\n",a); //a = 100
p = 200; // 这个操作是可以的
}
注意:&可以取得一个变量在内存中的地址。但是,不能取寄存器变量,因为寄存器变量不在内存里,而在CPU里面,所以是没有地址的。
2.4 *与取地址
- = 两边的变量要匹配
- 在使用的时候,在一个表达式之前取*,表达式类型减一级*
- 在使用的时候,在一个表达式之前&,表达式类型加一级*
int main()
{
int a = 10;
int *p;
p = &a; // p的类型是 int * -- &a之后a的类型也是int *
// 在使用的时候,*与p结合,表示取p指针所指向的那块内存空间的内容
*p = 100;
printf("a = %d\n",a); //a = 100
p = 200; // 这个操作是可以的,p是变量可以改变
int *p;
int **q;
*q = p; // q -- int * p -- int *
q = &p; // q -- int ** p -- int **
}
2.5 指针变量的大小
- 32位编译器 -- 指针变量大小都是4字节
- 64位编译器 -- 指针变量大小都是8字节
int main()
{
short *p1;
char *p2;
int *p3; // p1 p2 p3 都是4字节
int **p4 // p4 也是4字节
}
2.6 指针的宽度与步长
不同类型的指针变量取指针指向的空间的内容的宽度
- char *p -- 取一个字节
- short *p -- 取二个字节
- int *p -- 取四个字节
- 指针的宽度 = sizeof(将指针变量与指针变量最近的*拖黑剩下的类型)
- int **p -- 指针宽度sizeof(int *) -- 4个字节
- 指针的宽度也叫做步长,就是指针加1跨过的字节
#include <stdio.h>
int main()
{
int num = 0x01020304;
// short *p1 = &num 错误, 左边类型是 short * 右边类型是 int * 所以要进行强转
short *p1 = (short *)#
char *p2 = (char *)#
int *p3 = #
// 通过*取指针变量所指向的空间的内容时,取的内存的宽度和指针变量本身的类型有关
printf("%x\n",*p1); // 304
printf("%x\n",*p2); // 4
printf("%x\n",*p3); // 1020304
return 0;
}
#include <stdio.h>
int main()
{
int num = 0x01020304;
// short *p1 = &num 错误, 左边类型是 short * 右边类型是 int * 所以要进行强转
short *p1 = (short *)#
char *p2 = (char *)#
int *p3 = #
// 通过*取指针变量所指向的空间的内容时,取的内存的宽度和指针变量本身的类型有关
printf("%x\n",*p1); // 304
printf("%x\n",*p2); // 4
printf("%x\n",*p3); // 1020304
return 0;
}