1. const关键字的基本用法
#include<stdio.h>
int main()
{
const int n = 0; // const将n变成是一个常量,不能被修改
n = 100; // error; 尝试修改常量n会报错
}
2. 通过指针修改const变量
int main()
{
const int n = 0;
int* p = &n;
*p = 100; // 这样可以将n的值修改为100,因为p是一个指向int的指针
printf("%d\n", n);
}
3. const修饰指针(const在*左边)
int main()
{
const int n = 0;
// const 放在*左边约束*p
int const* p = &n; // 这样就将*p变成了一个常变量
// *p = 100; 无法修改了;
int b = 100;
p = &b; // *p不能改,但是可以改p的地址,进而指向其他变量
printf("%d\n", *p); // 输出100
}
4. const修饰指针(const在*右边)
int main()
{
const int n = 0;
int* const p = &n; // p是一个常量指针
*p = 100; // *p是可以改的
int b = 1000;
p = &n; // p是不能改的,指针p的地址不能被修改
}
5. 野指针问题
int main()
{
int* p;
*p = 10; // 这里的*p就是一个野指针,指向一个未定义的内存地址
printf("%d", *p);
}
6. 指针正确遍历数组
int main() // 正确打印
{
int arr1[10] = {0,1,2,3,4,5};
int i = 0;
int* p = &arr1[0];
for (i = 0; i <= 9; i++)
{
*p = i;
printf("%d ", arr1[i]);
p++;
}
}
7. 指针越界访问问题
int main() // 野指针越界访问错误打印
{
int arr1[10] = { 0,1,2,3,4,5 };
int i = 0;
int* p = &arr1[0];
for (i = 0; i <= 9; i++)
{
*(p++) = i;
printf("%d ", *p); // 这里的*p就是野指针,而且前面p++把这里搞错位了
}
}
8. 返回局部变量指针的问题
int* test()
{
int a = 10; // 但如果前面加static修饰a,则a的生命周期变成了整个程序运行期间
return &a; // 返回局部变量的地址,a在函数结束后会被销毁
}
int main()
{
int* p = test(); // a只有在test函数内才是有效的,*p变成了野指针
printf("%d\n", *p); // 这里会导致未定义行为,因为p指向的内存地址已经无效了
}
9. assert宏的使用
#define NDEBUG // 定义NDEBUG宏可以禁用assert宏的功能
#include<assert.h>
int main()
{
int* p = NULL;
assert(p != NULL); // assert宏用于调试,检查条件是否为真
printf("%d", a);
}
10. 使用异或运算交换值
void swap(int* pa, int* pb)
{
*pa = *pa ^ *pb; // 异或运算交换值
*pb = *pa ^ *pb;
*pa = *pa ^ *pb;
}
int main()
{
int a = 10;
int b = 20;
printf("a=%d,b=%d\n", a, b);
swap(&a, &b); // 传地址调用swap函数交换a和b的值
printf("a=%d,b=%d\n", a, b);
}