地址与指针
地址:数据在内存中的存储位置编号,是常量
指针:本质是地址
指针变量:存储的数据是地址,占4字节内存
类型* 标识符;
如 int * p=&a; //表示该指针变量p的值等于a的地址
取地址符 &
* 解引用,取内容
指针变量取了谁的地址,就指向谁
int a=10, b=20, c=30;
int *p1, *p2, *p3;
p1=&a;
p2=&b;
p3=&c;
printf(“%d\n”, *p1); // *p1表示取内容,这里输出a的值10//定义指针的时候,要马上给指针变量赋值,防止出现野指针(没有任何指向)
int *k1=NULL;//赋值为空
float *k2=NULL;
doubel *k3=NULL;
printf(“%d\n%d\n%d\n”, sizeof(k1), sizeof(a2), sizeof(a3));
//指针变量占内存都为4个字节,上述显示三个4
可以通过指针变量修改数据的值
int arr[10]={1,2,3,4,5,6,7,8,9,10};
for (int i=0;i<10;i++)
{
\quad print(“%p\n”, &arr[i]); //%p表示输出地址
}
int *p=&arr[0]; //数组首地址
int *p=arr; //数组名本身表示这个数组的首地址
p+=9;//表示指针的偏移,偏移一次所移动的字节数跟类型相关
printf(“%d\n”, *p); //输出的是偏移9位的值,即arr[9]的值 10
常量字符串
char *p1=“hello world”;
printf(“%d\n”, sizeof(p1)); //会输出4
printf(“%d\n”, strlen(p1)); //会输出11
指针函数与函数指针
指针函数:是一个函数,但是这个函数的返回值类型是一个指针
int * fun()
{
\quad int a=10;//a 是一个局部变量
\quad return &a;
}
函数指针:是一个指针,指向的是一个函数
函数指针的定义格式:函数的返回值类型(*函数指针名)(函数的形参列表);
void fun1(int a, int b)
{
\quad printf(“%d\n”, a+b);
}
void (*pFun)(int a, int b);
int main()
{
\quad pFun=fun1; //函数名就是代表其首地址
\quad pFun(1,2);
}
typedef int(*pF)(int,int);//函数指针取别名,别名就是他自己
//并且别名可以当作类型去使用
常量指针与指针常量
常量指针:定义不用初始化,能改变指向,指向的内容不能被修改(保护实参不被函数形参调用修改)
const int *p;
指针常量: 定义的时候必须要初始化,不能改变指向,可以改变指向的内容
int * const p1;
大端存储和小端存储
数据的地址:0x12345678 存于 0x0~0x3这个4字节中
0x0 12
0x1 34
0x2 56
0x4 78
是大端存储;适合人的读取方式(进制的高位存在前)
0x0 78
0x1 56
0x2 34
0x4 12
是小端存储;x86CPU使用小端存储作为数据的存储方式
指针数组与数组指针
指针数组:是一个数组,存储的是指针
数组指针:是一个指针,指向的是一个数组(二维数组起)
int arr[3][3]=
{
1, 2, 3,
4, 5, 6,
7, 8, 9
};
int (*p)[3]=arr; //表示3列 ,定义了一个数组指针
//下面定义指针数组
int a=3, b=2, c=1;
int *p2=&a, *p3=&b, *p4=&c;
int *p1[3]={p2,p3,p4};
int n[3][4]
{
\quad {1, 2, 3, 4},
\quad {8, 7, 6, 5},
\quad {9, 10, 11, 12},
};
int(*pn)[4] = n; //数组指针
int *p[3]={n[1], n[0], n[2]}; //这是一个指针数组
int **pp=p; //二级指针
printf(“%d\n”, *(*(pp+1)+2)); //*(pp+1)=pp[1]即首地址往后移一位,这里变成了n[0],然后继续在n[0]首地址往后移2位,最后输出数字3
printf(“%d\n”, *(pp[2]-3)); // pp[2]是n[2]的首地址解引用得到数字9,然后左移3位,得到的输出为数字7
内存四区
栈区:存储局部变量,系统自动申请释放内存
静态全局区:存储的静态和全局变量数据,内存只会存在一份,只会初始化一次,在程序执行结束时被释放
堆区:手动申请的内存区域,需要我们手动释放存储的是函数
代码区:存储的是函数等等
结构体指针
结构体指针:指向一个结构体变量的指针。一个结构体变量的起始地址就是这个结构体变量的指针
typedef struct nodeDate
{
\quad int a;
\quad char name[20];
}node;
void main()
{
\quad node n;
\quad n.a=10;
\quad node *p=&n; //结构体指针,访问成员通过箭头->
p->a = 20;
}
动态内存分配
从堆区申请内存,自己使用
通过函数malloc, calloc, realloc申请(头文件 stdlib.h)
从堆区申请的内存是通过指针执行管理的
int *p=(int *)malloc(100); //申请100个字节
//赋值的条件是类型相同,因为malloc函数的返回类型不是int,这里用强制转换
*p =10;
*(p+1)=20; //申请的内存用来存数据
free( p);
释放内存用free函数
在释放内存的时候,所填的指针必须要指向内存的首地址
nt *p=(int *)malloc(sizeof(int)*25);
memset(p1,0,sizeof(int)*25); // 逐字节赋值(string.h)
int *p=(int *)realloc(p, sizeof(int)*50); //重分配内存,不会初始化
free§;
p=NULL;
int *p=(int *)calloc(25,sizeof(int)); //申请的内存系统会自动初始化为0