
目录1.const修饰指针2.野指针3.assert断言4.传值调用和传址调用一.const修饰指针例1.const修饰局部变量aa不能够被赋值const修饰局部变量aa 是常变量本质依旧是变量拥有内存空间但是通过变量名 a 不能直接修改里面的值。a 100;尝试直接对 const 常变量赋值。//const int main() { const int a 10;//被const修饰后变成了一个常变量 -具有常属性的变量不能被修改了骨子里还是一个变量 a 100; printf(%d\n, a); return 0; }代码运行结果解说试图修改只读变量a程序无法生成可执行文件跑不起来。例2数组大小里要存放常数不能使用常变量接下来让我们了解两个概念常量与长变量解释常量编译期就确定的值常变量const int n运行时才有内存不属于编译常量int main() { //const修饰变量时不是常量是一个变量 const int n 10;//c99之前这个n不能放在数组的大小指定的位置 int arr[n]; arr[0] 1; return 0; }代码运行结果解说数组长度必须是编译期常量n是常变量编译报错。例3.const 只禁止直接修改变量名没有锁死内存借助指针获取地址可以间接修改局部 const 变量里面的值。int main() { //打破const常变量 const int a 10; int* p a; *p 100; printf(%d\n, a);//输出的是100不是10就好比你进一个房子里有门可以进也有窗户可以进当使用const修饰变量后就相当于把门锁了只能从窗户进去 return 0; }代码运行结果解说不能直接修改 const 修饰的 a但借助指针可以绕开限制间接修改 a 存储的数据这种方式不一定在所有环境都能用。例4.const修饰指针变量1. 放在*的左边const修饰的指针变量指向的内容不能通过指针变量修改它指向的内容但是指针变量的指向是可以修改的2.放在*的右边const修饰的指针变量本身指针变量的指向是不能修改的但是指针指向的内容是可以通过指针来改变int main() { int n 10; const int* p n;// 指向常量的指针*p只读p可以换指向 int m 100; p m;// p里面的值被覆盖成(内存B的地址)p现在指向m printf(%d\n, n);//10 return 0; }int main() { int n 10; int* const p n;// p存放n的地址p从此以后不能再指向别的变量 *p 100;// *p等价于n修改n内存里的值 printf(%d\n, n);//100 return 0; }二.野指针就是指针指向的位置是不可知的随机的不正确的没有明确限制的.造成野指针的有三种情况1.指针未初始化2.指针访问越界3.指针指向的空间释放例5.列举局部变量与全局变量未初始化代码会怎样运行。//全局变量不主动初始化的情况下编译器默认会给初始化0 int g_val; int main() { //局部变量不初始化里边的值是不可预测的可能是随机值如果在初始化前加上static编译器默认会给初始化0 //int n; //printf(%d\n, n);//编译失败 static int n; printf(%d\n, n);//如果没有加static将编译失败加static输出0 printf(%d\n, g_val);//0 return 0; }代码运行结果解说全局变量不加初始化程序加载时默认初始化为 0被 static 修饰的局部静态变量同样默认初始化为 0普通局部变量不初始化里面存放随机垃圾值。例6.指针未初始化//1.指针未初始化 int main() { //int n 10; //int* p n;//指针初始化 int* p; *p 10;//p就是野指针 return 0; }例7.指针越界访问//2.指针越界访问 int main() { int arr[10] { 0 }; int* p arr[0]; int i 0; for (i 0;i 11;i) { *(p) i;//先执行*p,在执行 } return 0; }例8.指针指向的空间释放//3.指针指向的空间释放 int* test() { int n 100; return n; } int main() { int* p test(); printf(%d\n, *p);//*p为野指针 return 0; } int main() { int n 10; int* p n; int* p1 NULL; //NULL专门用来初始化指针变量chushihuaweiNULl的指针变量意味着这个指针没有可以指向有效空间的地址我们暂时不能使用它 return 0; }三.assert断言assert(条件)断言宏。条件为真程序正常运行条件为假程序直接崩溃打印出错文件、行号。#define NDEBUG必须写在#include assert.h前面开启后所有 assert 全部失效。例9//#define NDEBUG #include assert.h //assert断言 int main() { //int* p NULL; int n 10; //int* p n; int* p NULL; assert(p ! NULL); printf(%d\n, *p); return 0; } //strlen #include assert.h size_t my_strlen(const char *p) { int count 0; assert(*p ! NULL); while (*p ! NULL) { count; p; } return count; } int main() { char arr[] abcdef; size_t len my_strlen(arr); printf(%zu\n, len); return 0; }四.传值调用和传址调用例10//传值调用 //实参传递给形参的时候形参是实参的一份临时拷贝 //对形参的修改不影响实参 void swap(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); swap(a, b); printf(交换后a %d b %d\n, a, b); return 0; }例11//传址调用 void swap(int *x, int *y) { int tmp *x; *x *y; *y tmp; } int main() { int a 0; int b 0; scanf(%d %d, a, b); printf(交换前a %d b %d\n, a, b); swap(a, b); printf(交换后a %d b %d\n, a, b); return 0; }