指针一.指针基础1.指针指针是一个变量存储的是地址。 地址是一个常量值表示的是地址值 取地址符 变量才能取地址内存分布ps* : 1.堆区内存开辟从低地址向高地址开辟栈区内存从高地址向低地址开辟//栈区intmain(){inta0;intb0;printf(%p,ab?a:b);//会输出a的地址 但Debug会有变量重排会导致输出b的地址}2.指针定义intval0;int*pval;//一级指针 存放val的地址int**qp;//q是二级指针 int*表示p的类型char*p,*q;//p,q 都是指针类型//野指针未初始化的指针 指向随机内存地址//野指针指向无效内存地址如未初始化或已释放的内存解引用会导致未定义行为。//空指针显式赋值为 NULL 或 0通常指向不可访问的地址3.指针运算与步长指针加减运算的步长由数据类型决定int*p;// p1 的偏移量为 sizeof(int)4字节double*q;// q1 的偏移量为 sizeof(double)8字节4.指针与数组的关系指针访问数组的等价形式地址等价性arr[2]⇔ arr2arr[2]⇔*(arr2)⇔*(2arr)⇔2[arr]5.指针解引用与内存解析解引用的内存操作根据指针类型解析内存空间大小double*p...;*p;// 解引用时读取或写入8字节sizeof(double)6.内存存储模式验证大小端模式验证方法“数据在内存中的存储模式”windows:小端存储模式小端字节序7.指针运算前提基于连续内存空间指针1问题能力取决于指针的基类型intarr[]{1,2,3,4,5};int*parr[0];// p指向0x100*(q1)//2//*(q1)等价于 *arr1 等价于arr[1] q[1]二.指针进阶1. 自增与指针的优先级同等优先级 右结合性x*p;//后置 先*p赋值 给x 再p指针移动x*p;//先*p 值再1x*p;//指针先移动 再解引用2.define与constdoublePI3.14;//变量 可修改 可PI#defineSIZE10;//常量 不可SIZEconstdoublePI3.14;//PI不可被修改 但PI是对的常变量constc语言侧重在变const int n10; int arr[n]是错的int a0;a:地址常量值那么a //err定义三个相同类型的指针#define Type char*Type p,q,s; //err相当于char*p,q,s;(只是值替换) qs是cahr类型而不是指针Type p; Type q; Type s;类型重命名typedef char* type;type p,q,s; //是对的3.const 与指针结合const 修饰变量变量被 const 修饰后具有常性特征不可修改其值constdoublePI3.14;PI3.24;// 错误PI 是常量const 修饰指针根据 const 的位置不同分为以下情况1.指向常量的指针指针指向的值不可修改但指针本身可指向其他地址constintval10;constint*pval;*p1;// 错误无法修改指向的值2.保护数据通过 const 防止误修改指针指向的值intnum20;constint*pnnum;if(*pn30){}// 仅读取不修改3.常量指针指针本身不可修改指向固定但可修改指向的值inta0,b0;int*constpa;pb;// 错误p 是常量指针*p1;// 允许修改指向的值4.指向常量的常量指针指针和指向的值均不可修改constint*constpa;*p1;// 错误pb;// 错误4.多级指针与 constintnum0;int*constpnum;// p 指向不可变constint*const*sp;// s 指向 p且不通过 s 修改 num//int * const 是p的类型 在此基础上再添加限定5.字符串常量字符串常量存储在只读数据区需用 const char* 声明constchar*phello;// p[1] a; // 错误只读数据标准库函数如 strlen、strcmp 均使用 const char* 参数保护数据。6.数组与指针指针数组每个元素是指针类型的数组inta,b,c,d;int*arr[]{a,b,c,d};// arr 是指针数组数组指针指针指向整个数组步长为数组总大小intarr[10];int(*p)[10]arr;// p 是数组指针// p 1 的步长为 sizeof(int[10]) 字节普通指针与数组指向数组首元素的指针是普通指针intarr[10];int*parr;// p 指向 arr[0]步长为 sizeof(int)赋值从右向左 权限缩小三.函数指针指针定义类型 * 指针名int * p函数指针函数类型 * 指针名int (*p)(int,int) add;1.函数与指针1.数组传参退化为指针传递不是值传递voidShow(int*arr,intlen){}intmain(){intarr[]{1,2,3,4,5,6,7};intlensizeof(arr)/sizeof(arr[0]);Show(arr,len);}这种方式节省内存防止创建内存副本。2.形参修改影响实参的值通过传指针和解引用。例如交换函数voidSwap(int*pa,int*pb){intt*pa;*pa*pb;*pbt;}3.将函数内数据带出函数外通过参数传递指针并在内部解引用。例如voidOperate(inta,intb,int*pa,int*pb){*paab;*pba*b;}4.返回值类型设计为指针不能返回局部变量的地址。int*Operate(inta,intb){staticintarr[]{ab,a*b};returnarr;}2.函数指针1.函数指针是指向函数的指针。intadd(inta,intb){returnab;}intmul(inta,intb){returna*b;}int(*p)(int,int)add;pmul;p(1,2);// 调用指向的函数3.类型重命名typedef1.数组指针重命名intarr[3];typedefint(*PArrInt3)[3];PArrInt3 parr;2.函数指针重命名typedefint(*PFun)(int,int);PFun padd;p(1,2);动态内存一.动态内存管理核心概念1.栈区与堆区区别栈区存储局部变量Windows默认1MBLinux默认10MB自动分配/释放堆区手动管理内存上限约1.9GBx86架构需显式调用malloc/free2.常见问题场景变长数组编译错误int n10; int arr[n] 不符合C标准大内存导致栈溢出char buff[1024*1024] 可能崩溃二.内存操作函数详解1.malloc基础用法ElemType*p(ElemType*)malloc(n*sizeof(ElemType));if(pNULL)returnERROR_CODE;// 必须检查分配失败// 使用方式p[i] 或 *(pi)free(p);// 释放后立即置空pNULL;malloc 默认返回值为void*2.calloc与malloc对比int*p1(int*)malloc(10*sizeof(int));// 内容未初始化int*p2(int*)calloc(10,sizeof(int));// 内容初始化为03.realloc扩容机制1.原空间后方有足够空间直接扩展2.空间不足时寻找新空间→拷贝数据→释放旧空间3.完全失败时返回NULLint*new_p(int*)realloc(p,new_size*sizeof(int));if(new_pNULL){free(p);// 根据逻辑决定是否保留原数据returnFAILURE;}pnew_p;// 更新指针4.动态内存中free出现崩溃的原因1…对同一份内存连续多次释放原因仅释放其内容而p所存的地址还在但地址中的数据已被释放即地址的空间不是有效空间再次释放则指针崩溃解决释放完内存后将指针置为空 freep pNULL 2.释放的是非堆区空间eg int arr10 free arr3.free括号内需为堆区空间的起始地址