指针(上 - 完结)

张开发
2026/6/29 13:21:11 15 分钟阅读
指针(上 - 完结)
目录一、指针运算1、指针-整数2、指针-指针3、指针的关系运算二、const修饰指针1、 const2、const修饰左边3、const修饰右边三、野指针1、指针未初始化2、指针越界3、指针指向的空间被释放4、如何合理规避野指针的出现4.1、指针初始化4.2、不使用指针时置为NULL4.3、避免返回局部变量的地址四、assert断言1、my_strlen的优化五、传值调用和传址调一、指针运算指针-整数指针-指针指针关系运算1、指针-整数通过下标引用操作符打印数组int a[] {1,2,2,3,4,5}; int sz sizeof(a) / sizeof(a[0]); int i 0; for(i 0;i sz;i) printf(%d ,a[i]);通过指针加整数打印数组nt a[] {1,2,2,3,4,5}; int sz sizeof(a) / sizeof(a[0]); int * i [0]; int j 0; for(j 0;j sz;j) printf(%d ,*i);nt a[] {1,2,2,3,4,5}; int sz sizeof(a) / sizeof(a[0]); int * i [0]; int j 0; for(j 0;j sz;j) printf(%d ,*(i 1));1 2 3 4 5通过指针减整数倒打印数组nt a[] {1,2,2,3,4,5}; int sz sizeof(a) / sizeof(a[0]); int * i [sz-1]; int j 0; for(j 0;j sz;j) printf(%d ,*i--);5 4 3 2 12、指针-指针指针减指针得到的是指针与指针之间的元素个数指针减指针的前提是处于同一块空间内且类型相同即数组int a[] {1,2,3,4,5}; printf(%d,a[4] - a[0]);4strlen的功能是计算字符串的长度统计的是字符串\0之前的字符个数对于strlen函数的简单实现size_t my_stelen(char * p) { int count 0; while(*p ! \0) //等价while(*p) { count; p; } return cpunt; }用指针来实现size_t mu_strlen(char *p) { char * start p; while(*p) { p; } return p - start; }3、指针的关系运算以指针关系判断作为结束条件来打印数组int a[] {1,2,3,4,5}; int *p a; int sz sizeof(a) / sizeof(a[0]); while(p a[sz]) { printf(%d,*p); p; }二、const修饰指针1、 const是常变量具有长属性不变的属性本质是变量2、const修饰左边const int a 0; //等价int const a 0; a; //x int *b a; *b 10; //√不能被直接修改可以用指针间接修改被指向的值指针同理3、const修饰右边const int a 10; int * const b a; int * c b; //x *b 100;该指针的内容不能被修改就是p不能只想去指向其他变量但p所指向的值可以被修改如果两边都被const修饰那么该指针和指向的内容都不能被修改三、野指针没有明确的指向随机的不正确的没限制的1、指针未初始化没有初始化默认就是随机值int * a; *a 20;把b里边的随机值当作地址找了块内存空间存放了20这种现象是非法访问2、指针越界int a[5] {0}; int * b a[0]; int i 0; for(i0;i5;i) { *(b) i; }当指针指向的的范围超出数组的范围是此时b就是野指针3、指针指向的空间被释放int test() { int i 0; printf(%d\n,i); return i } int main() { int * a test(); printf(%d\n,*a); return 0; }当指针a拿到这个指针的时候就是野指针因为此时的指针所指向的内存空间已经还给系统了指针指向的内存空间已经不属于当前的程序是这是就是野指针4、如何合理规避野指针的出现4.1、指针初始化如果知道指针指向哪里就给指针一个值如果不知道指向哪里就给指针赋值NULLint * a NULL;int main() { int * a NULL; //*p 1; if (a ! NULL) *p 1; return 0; }4.2、不使用指针时置为NULLint a[5] {0}; int * i a[0]; int j 0; for(j0;j5;j) { *(i) j; } i NULL;4.3、避免返回局部变量的地址int * test() { int i 0; int * j i; return j; } main() { int * n test(); return 0; }四、assert断言运行时确保程序符合指定条件(即条件为真)如果不符合则终止运行条件为假这个宏称为断言assert(p ! NULL);使用时需包含头文件assert.hassert断言的出现可以减轻程序员代码潜在隐藏报错的风险它可以自动标识文件和出问题的行号且无需更改代码就能开启和关闭assert如果确定了程序没有问题不需要再做断言就在头文件前加一个宏#NDEBUG#define NDEBUG #include assert.h但因引入了额外的检查增加程序运行的时间通常在debug环境下用于程序员排查问题release优化掉了1、my_strlen的优化size_t mu_strlen(const char *p) { char * start p; assert(p ! NULL); while(*p) { p; } return p - start; }五、传值调用和传址调用传值调用当实参向实参传递数据时形参是实参的一份临时拷贝有自己独立的空间修改形参不会形象实参void Swap1(int x,int y) { int z x; x y; y z; } int main() { int a 0; int b 0; scanf(%d %d,a,b); printf(交换前a%d b%d\n,a,b); Swap1(a,b); printf(交换后a%d b%d\n,a,b); return 0; }传址调用实参向形参传递指针让函数和主调函数有了联系使在函数内部可以修改主调函数中的变量void Swap1(int * x,int * y) { int z 0; z *x; *x *y; *y z; } int main() { int a 0; int b 0; scanf(%d %d,a,b); printf(交换前a%d b%d\n,a,b); Swap1(a,b); printf(交换后a%d b%d\n,a,b); return 0; }

更多文章