在了解const修饰指针变量之前,我们还要先了解const对变量的具体作用是什么。变量是可以被改变的,但有时候我们想限制这个变量,不想让他被改变,那么这时候const就起作用了,我们可以通过下面这段代码来感受一下:
#include<stdio.h>
int main()
{
int a = 10;
a = 20;
const int b = 20;
b = 30;
return;
}这段代码中,编译的时候会报错,如下图:

根据第一行的报错,我们就可以知道,被const修饰之后的变量b是不能被改变的,此时我们将b称作“常变量”。本质上还是变量,但是在语法上是常量。如果想要强制修改这个常变量,因为b本身上不能被改变,但是我们可以通过指针的方式来实现,绕开b本身:
#include<stdio.h>
int main()
{
/*int a = 10;
a = 20;*/
const int b = 20;
int* pb = &b;
*pb = 30;
printf("%d", b);
return;
}运行结果如下:

这样,b就修改成功了。
需要注意的是,这个操作只能在.c文件下操作。
const修饰指针有两种情况,const可以放在*号的左边,也可以放在*号的右边,意义是不一样的

当我们编写这样的代码并进行编译的时候,编译器会报这样的错误,说明*p这时候是不能被修改的,也就是说,当const在*号的左边时,限制的是通过指针p指向的对象不能被修改,即a不能被修改。这里还是要注意的是,const虽然说限制的是*p,但是是限制通过指针p修改a的这个途径而已,而不是限制a本身不能被修改,即a不能通过指针p修改自己的值,但是可以通过自身来修改值:

运行结果如上图,这样我们就讲清楚了const在*号左边的作用了。

编写如上图代码时,编译器又会报错,这时候就告诉我们,此时指针变量pa存放的地址是不能被修改的,就是pa不能存放其他变量的地址,但是*pa的值可以被修改:

综上:
野指针,顾名思义就是没有被约束的指针,其指向的位置不是不确定的,不属于当前程序。
#include<stdio.h>
int main()
{
int *p; //指针没有初始化,没有具体指向的对象,系分配随机值,这就是野指针
*p = 20;
return 0;
}#include<stdio.h>
int main()
{
int a[10]={0};
int* p = arr;
for(int i=0;i<=11;i++)
{
*(p++) = i; //数组越界访问,超出数组范围,会不受限制,成为野指针
}
return 0;
}3.指针指向的空间被释放
#include<stdio.h>
int* test(int n)
{
int a=20;
return &a;
}
int main()
{
int *p = test();
printf("%d",*p);
return 0;
}在上述代码中,虽然函数中的变量a的地址被指针变量p记录下来了,但是函数执行完之后,里面的变量a会被销毁,也就是说,此时p存放的时a存活时的地址,当函数被销毁时,a就死亡了,就不能同通过指针变量p找到a,那么p就成为了野指针,即没有指向确定的值。
如何规避野指针,可以根据野指针形成的情况来进行解决,这里就简单的带过~
在<assert.h>这个头文件中,定义了宏assert(),用于在确保程序运行时符合括号内的条件,如果不符合,那就终止程序。这个宏常常被称为“断言”。例如:
#include<stdio.h>
#include<assert.h>
int main()
{
int a=10;
assert(a==20);
printf("%d",a);
return 0;
}当我们运行这段代码时,就会出现这样的显示:

这是因为,但运行到assert()语句的时候,assert()会自动判断a是不是真的等于20,如果不是就中止程序,如果是就继续执行。
在Debug环境下,assert是自动打开的,如果想不用assert()语句,只需要在头文件前加上
#define NDEBUG即可。
另外,在Realse版本下assert()是自动关闭掉的。
指针的使用我们从自己写一个strlen函数开始吧
#include<stdio.h>
int my_strlen(char* str)
{
int count = 0;
while (*str != '\0')
{
str++;
count++;
}
return count;
}
int main()
{
char str[] = "hello world";
int count = my_strlen(str);
printf("%d", count); //输出的结果为11
return 0;
}指针可以像数组下标那样来进行使用。
传址调用和传址调用,顾名思义就是,一个传地址,一个传数值。这两者有什么区别呢?我们可以通过下面的代码来了解一下
#include<stdio.h>
void swap1(int x, int y)
{
int temp = x;
x = y;
y = temp;
}
int main()
{
int a = 10;
int b = 20;
swap1(a, b);
printf("交换前:%d %d\n",a, b);
printf("交换后:%d %d\n", a, b);
return 0;
}那么能不能实现交换呢?我们来看看运行结果:

很显然这两个变量的值没有不被交换,那我们就调试一下:

此时我们可以看到,在运行到函数时,x,y都自己创建了一个内存空间,在函数中进行的操作只会影响x和y,不会影响到a,b,说明想要改变实参的值,是不能通过传值的方式来调用函数的,那我们用指针试试看:
#include<stdio.h>
void swap1(int* x, int* y)
{
int temp = *x;
*x = *y;
*y = temp;
}
int main()
{
int a = 10;
int b = 20;
int* pa = &a, * pb = &b;
printf("交换前:%d %d\n",a, b);
swap1(pa, pb);
printf("交换后:%d %d\n", a, b);
return 0;
}这时候的运行结果为:

发现我们通过传地址的方式可以实现两数字的交换
综上所述,当我们想要通过函数计算实参中某个关系的值的时候,可以通过传值的方式来调用函数,但是如果是想通过函数来改变实参的数值,那就要通过指针的方式,来调用函数才能达成目的。
文章是自己写的哈,有啥描述不对的、不恰当的地方,恳请大佬指正,看到后会第一时间修改,感谢您的阅读。