指针指针指针

📅 2026/7/10 23:08:08
指针指针指针
内存和地址内存单元的编号 地址 指针指针p的3个相关值1.p变量p里面放着一个地址p叫做指针变量2.*pp指向的那个对象3.p表示的是p变量的地址指针变量和地址int a 10;printf(%d,a); //是取地址符指针变量怎么声明初始化方法一int * p a; //这里*表示p是指针变量int表示p指向的变量a的类型是intp的类型是int**p 200; // 这里*是解引用操作符间接访问操作符方法二分开写int * p;p a;*p 200;指针变量类型的意义指针变量大小 一个地址存放空间大小1.指针类型决定了解引用的时候访问多大空间2.指针类型决定了在指针进行整数倍的加或减的时候向前或向后偏移多大距离int* pa : pa 1 ----- 1*sizeof(int)pa n ----- n*sizeof(int) 如果是n就是向后偏移n个整型字节void* : 无具体类型的指针泛型指针不能进行解引用操作无法进行指针运算const修饰指针变量被const修饰的变量就成了常变量int m 0;m 10; //可以这样写变量m可以被修改const int n 0;n 5 //错误不能这样写常变量不能被修改int * p;int count * p; //count可以放在*左边或者右边int main(){ int m 10; int n 100; int *p m; *p 20; p n; //以上代码如图 int const * p n; *p 20 //报错const限制* p说明 p指向的对象不能改变 p n; //正确const没有限制 p可以改变 p本身的地址 int * const p n; *p 20 //正确const在*右边没有限制* p p n; //报错限制 p return 0; }指针运算1. 指针 - 整数2. 指针 - 指针3. 指针的关系运算1. 指针 - 整数#define _CRT_SECURE_NO_WARNINGS 1 #include stdio.h int main() { //指针 整数 int arr[5] { 1,2,3,4,5 }; int len sizeof(arr) / sizeof(arr[0]); int* p arr[0]; for (int i 0; i len; i) { printf(%d , *(pi)); } }2.指针 - 指针1. 指针 指针 跟日期日期一样没有意义2. 指针 - 指针 的绝对值 是 指针和指针之间的元素个数指针 - 指针 计算的前提条件是 两个指针指向的是同一个空间示例使用指针 - 指针计算数组长度#include stdio.h int main() { int arr[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // 获取数组首元素地址 int *start arr[0]; // 获取数组末尾元素的下一个位置地址 int *end arr[10]; // 注意arr[10]不存在但arr[10]是合法地址数组末尾之后 // 指针 - 指针 两个指针之间的元素个数 int length end - start; printf(数组长度: %d\n, length); // 输出: 数组长度: 10 // 另一个例子计算中间部分元素个数 int *mid arr[3]; int elements_between end - mid; printf(从arr[3]到数组末尾的元素个数: %d\n, elements_between); // 输出: 7 return 0; }解释start指向数组第一个元素arr[0]end指向数组最后一个元素arr[9]之后的位置即arr[10]的地址虽然这个元素不存在end - start的结果是 10表示两个指针之间有 10 个int类型的元素指针减指针的结果类型是ptrdiff_t有符号整数表示元素个数而不是字节数3.指针的关系运算比较大小#define _CRT_SECURE_NO_WARNINGS 1 #include stdio.h int main() { int arr[10] { 1,2,3,4,5,6,7,8,9,10 }; int sz sizeof(arr) / sizeof(arr[0]); int* p arr[0]; while (p arr[sz]) { printf(%d, *p); p; } return 0; }野指针1.指针未初始化int *p;*p 10; //会报错这里的p叫野指针解引用操作符会形成非法访问2.指针越界访问int arr[10] {0};int *p arr[0];for(int i 0;i 10;i){*p i;p; //这里越界访问了}3.指针指向的空间释放#include stdio.h int main() { int num 42; // 静态分配的整型变量 int *p num; // 指针指向num的地址 printf(指针指向的值: %d\n, *p); // 静态变量无需手动释放此处仅演示指针的“释放”逻辑将指针置为NULL p NULL; // 避免悬垂指针 if (p NULL) { printf(指针已释放置空\n); } return 0; }规避野指针1.指针初始化int *p NULL;2.小心指针越界指针不能超出使用范围3.指针变量不再用的时候要把它置为空值#include stdio.h int main() { int num 10; int *p num; printf(数值: %d\n, *ptr); p NULL; // 使用完毕置空 if(p NULL) { printf(指针已置空\n); } return 0; }assert断言#includeassert.hintint main(){int a 10;int *p NULL;assert( p ! NULL);return 0;}assert里面的表达式为假就报错为真就正常运行如果不想要宏assert那就在assert头文件前面定义一个宏NDEBUG#include NDEBUG注意: VS里的Release版本禁用assert ,不影响用户使用的时候程序的效率Debug版本写利于程序员排错指针的使用和传址调用Strlen的模拟实现strlen求字符串 \0 之前的长度#define _CRT_SECURE_NO_WARNINGS 1 #include stdio.h #includeassert.h //strlen函数的实现 size_t my_strlen(const char* s) { //不想改变数组里的数常变量 size_t count 0; //返回值类型和函数保持一致 assert(s ! NULL); //指针s不能为空 while (*s) { //只要*s不为\0\0的ASCLL码是0就执行循环体 count; s; } return count; } int main() { char arr[] abcdef; size_t len my_strlen(arr); //记录的大小永远为非负整数用size_t printf(%zd, len); //size_t必须用%zd return 0; }传值调用和传址调用传值调用不需要改变原变量只需要读取变量的值来计算传址调用需要修改主函数里原始变量的值 解决问题非指针不可的情况 练习题写一个函数交换两个整型变量的值#define _CRT_SECURE_NO_WARNINGS 1 #include stdio.h void swap1(int a,int b) { //传值调用 int z 0; z a; a b; b z; } int main() { //写一个函数交换两个整型变量的值 int a 9; int b 8; printf(交换前a %d b %d\n, a, b); printf(%d %d\n, a, b); swap1(a, b);//传值调用 printf(交换后a %d b %d\n, a, b); printf(%d %d, a, b); }void swap2(int *pa,int *pb) { //传址调用 int z 0; z *pa; *pa *pb; *pb z; } int main() { //写一个函数交换两个整型变量的值 int a 9; int b 8; printf(交换前a %d b %d\n, a, b); printf(%d %d\n, a, b); swap2(a, b);//传址调用 printf(交换后a %d b %d\n, a, b); printf(%d %d, a, b); }