1.内存的理解
(1)内存访问的最小单位为字节,1个字节是8个bit位,标记为[7 :0]bits。
(2)每个字节的内存地址空间都有一个唯一的编号,这个编号称为地址(指针)。
(3)访问内存的地址空间,本质就是通过地址进行访问。
(4)32位的操作系统,地址的寻址空间为:
0x0000_0000 (0G) ~ 0xFFFF_FFFF (4G)
因此32位的系统地址占4字节的空间。
(5)64位的操作系统,地址的寻址空间为:
0x0000_0000_0000_0000 (0G) ~ 0xFFFF_FFFF_FFFF_FFFF (很大)
因此64位的系统地址占8字节的空间。
2.指针相关的概念
(1)专门用来存放地址的变量称为指针变量
(2)定义指针变量和普通变量的区别
普通变量:普通变量对应的地址空间中存储的是普通的数据。
指针变量:指针变量对应的地址空间中存储的是一个地址(指针)
(3)抽象的概念
指针类型:用来定义指针变量的类型,称为指针类型。
指针变量:专门用来存放地址的变量称为指针变量。
3.指针类型变量的定义及初始化
1. 定义指针变量的格式
数据类型 *指针变量名 = 地址; (常用)
数据类型* 指针变量名 = 地址;
数据类型 * 指针变量名 = 地址;
(数据类型 *) : 整体,表示要定义指针类型的变量
2. 指针变量的初始化
2.1> 定义指针变量的同时进行初始化
数据类型 普通变量名 = 初始值;
数据类型 * 指针变量名 = &普通变量名;
& : 取地址符, 单目运算符,对变量进行取地址运算
2.2> 先定义指针变量,后对指针变量进行初始化
数据类型 普通变量名 = 初始值;
数据类型 * 指针变量名 = NULL;
// 如果定义指针变量如果没有指向一个地址空间时,
// 请将指针变量赋值为NULL, NULL空指针
// 防止野指针的出现
// 野指针: 没有指向一个特定内存空间的指针称为野指针
指针变量名 = &普通变量名;
p=&a;
3. 指针变量的使用:
指针变量名; ---> 指针变量中存储的地址
*指针变量名; ---> 取指针变量指向的地址空间中的值
4. *(取值运算符)和&(取地址符)的含义
& :放到变量名的前边表示取变量在内存中的地址,
使用%p打印地址的值
* : 由两个含义
1> 如果放到数据类型和指针变量名之间,表示定义指针变量
2> 如果放到指针变量名前边,表示取指针变量指向的地址空间的值
#include <stdio.h>
int main(int argc, const char *argv[])
{
// 1. 定义一个指针变量,同时对指针变量进行初始化
int a = 10086;
int *p = &a; // 指针变量p中存放的时变量a的地址
printf("&a = %p\n", &a); // 打印变量a的地址
printf("p = %p\n", p); // 打印指针变量中存储的地址
// 通过变量a访问a变量对应内存空间的值
// 通过指针变量p访问指向的变量a的地址空间的值
printf("a = %d\n", a );
printf("*p = %d\n", *p);
// 通过指针变量修改指向的地址空间中的值
*p = 10010; // 间接修改变量a对应内存空间的值
printf("a = %d\n", a );
printf("*p = %d\n", *p);
// 2. 先定义指针变量,后进行初始化
char ch = 'A';
char *q = NULL;
q = &ch;
printf("*q = %c\n", *q);
return 0;
}
4.指针类型占用内存空间大小
1. 32位的操作系统,地址的寻址空间为:
0x0000_0000(0G) ~ 0xFFFF_FFFF(4G)
因此32位的系统地址占4字节的空间。
#include <stdio.h>
int main(int argc, const char *argv[])
{
printf("int * 指针大小 = %d\n", sizeof(int *));
printf("short * 指针大小 = %d\n", sizeof(short *));
printf("long * 指针大小 = %d\n", sizeof(long *));
printf("long long * 指针大小 = %d\n", sizeof(long long *));
printf("char * 指针大小 = %d\n", sizeof(char *));
return 0;
}
编译生成32位系统的可执行程序,测试完成之后指针类型的地址都占4字节,
根具体的指针的类型无关。
2. 64位的操作系统,地址的寻址空间为:
0x0000_0000_0000_0000(0G) ~ 0xFFFF_FFFF_FFFF_FFFF(很大)
因此64位的系统地址占8字节的空间
#include <stdio.h>
int main(int argc, const char *argv[])
{
printf("int * 指针大小 = %ld\n", sizeof(int *));
printf("short * 指针大小 = %ld\n", sizeof(short *));
printf("long * 指针大小 = %ld\n", sizeof(long *));
printf("long long * 指针大小 = %ld\n", sizeof(long long *));
printf("char * 指针大小 = %ld\n", sizeof(char *));
return 0;
}
编译生成64位系统的可执行程序,测试完成之后指针类型的地址都占8字节,
根具体的指针的类型无关。
5.指针类型变量进行算数运算
地址可以进行算数运算:
算数运算: + -
自增自减运算 : ++ --
赋值运算 : = += -=
关系运算: == > < >= <= !=
指针类型的变量进行算数运算时,偏移地址的大小和数据类型 有关
int *类型的指针变量 + 1 , 偏移4个字节
short *类型的指针变量 + 1 , 偏移2个字节
char *类型的指针变量 + 1 , 偏移1个字节
long *类型的指针变量 + 1 :
32位系统,偏移4个字节
64位系统,偏移8个字节
long long *类型的指针 + 1, 偏移8个字节
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 1000;
int *p = &a;
printf("p = %p\n", p);
printf("p+1 = %p\n", p+1);
// &a : 是一个int *类型的指针
// 需要强制类型转换为short *类型的指针在进行赋值
short *q = (short *)&a;
printf("q = %p\n", q);
printf("q - 1 = %p\n", q-1);
return 0;
}