首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【C语言进阶】指针2

【C语言进阶】指针2

作者头像
良木生香
发布2026-01-09 14:18:15
发布2026-01-09 14:18:15
1410
举报

一、const修饰指针

1.const修饰变量

在了解const修饰指针变量之前,我们还要先了解const对变量的具体作用是什么。变量是可以被改变的,但有时候我们想限制这个变量,不想让他被改变,那么这时候const就起作用了,我们可以通过下面这段代码来感受一下:

代码语言:javascript
复制
#include<stdio.h>
int main()
{
	int a = 10;
	a = 20;
	const int b = 20;
	b = 30;
	return;
}

这段代码中,编译的时候会报错,如下图:

根据第一行的报错,我们就可以知道,被const修饰之后的变量b是不能被改变的,此时我们将b称作“常变量”。本质上还是变量,但是在语法上是常量。如果想要强制修改这个常变量,因为b本身上不能被改变,但是我们可以通过指针的方式来实现,绕开b本身:

代码语言:javascript
复制
#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文件下操作

2.const修饰指针

const修饰指针有两种情况,const可以放在*号的左边,也可以放在*号的右边,意义是不一样的

1.const放在*号的左边:

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

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

2.const放在*号右边

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

综上:

  1. 当cosnt在*号左边时,修饰的是指针指向的内容,保证指针指向的内容不能通过指针变量来改变,内容自身可以进行改变,但是指针变量本身可以被改变,可以存放其他变量的地址
  2. 当const在*号右边时,修饰的是指针变量本身,保证了指针变量的内容不能被改变,但是指针变量指向的内容,可以通过指针变量来进行改变

二、野指针

野指针,顾名思义就是没有被约束的指针,其指向的位置不是不确定的,不属于当前程序。

野指针的成因

1.指针没有初始化
代码语言:javascript
复制
#include<stdio.h>
int main()
{
    int *p;   //指针没有初始化,没有具体指向的对象,系分配随机值,这就是野指针
    *p = 20;
    return 0;
}

2.数组越界访问

代码语言:javascript
复制
#include<stdio.h>
int main()
{
    int a[10]={0};
    int* p = arr;
    for(int i=0;i<=11;i++)
    {
        *(p++) = i;    //数组越界访问,超出数组范围,会不受限制,成为野指针
    }
    return 0;
}

3.指针指向的空间被释放

代码语言:javascript
复制
#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就成为了野指针,即没有指向确定的值。

3.如何规避野指针?

如何规避野指针,可以根据野指针形成的情况来进行解决,这里就简单的带过~

  1. 将指针初始化,如果创建了一个指针变量但是未使用,可以将它赋值为NULL;
  2. 小心指针越界
  3. 避免返回局部变量的地址
  4. 使用之后的指针,若短时间内不再使用,也将它赋值为NULL;

三、assert()断言

在<assert.h>这个头文件中,定义了宏assert(),用于在确保程序运行时符合括号内的条件,如果不符合,那就终止程序。这个宏常常被称为“断言”。例如:

代码语言:javascript
复制
#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()语句,只需要在头文件前加上

代码语言:javascript
复制
#define NDEBUG

即可。

另外,在Realse版本下assert()是自动关闭掉的。

四、指针的使用和传址调用

1.指针的使用

指针的使用我们从自己写一个strlen函数开始吧

代码语言:javascript
复制
#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;
}

指针可以像数组下标那样来进行使用。

2.传址调用和传值调用

传址调用和传址调用,顾名思义就是,一个传地址,一个传数值。这两者有什么区别呢?我们可以通过下面的代码来了解一下

代码语言:javascript
复制
#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,说明想要改变实参的值,是不能通过传值的方式来调用函数的,那我们用指针试试看

代码语言:javascript
复制
#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;
}

这时候的运行结果为:

发现我们通过传地址的方式可以实现两数字的交换

综上所述,当我们想要通过函数计算实参中某个关系的值的时候,可以通过传值的方式来调用函数,但是如果是想通过函数来改变实参的数值,那就要通过指针的方式,来调用函数才能达成目的。

文章是自己写的哈,有啥描述不对的、不恰当的地方,恳请大佬指正,看到后会第一时间修改,感谢您的阅读。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、const修饰指针
    • 1.const修饰变量
    • 2.const修饰指针
      • 1.const放在*号的左边:
      • 2.const放在*号右边
  • 二、野指针
    • 野指针的成因
      • 1.指针没有初始化
    • 2.数组越界访问
    • 3.如何规避野指针?
  • 三、assert()断言
  • 四、指针的使用和传址调用
    • 1.指针的使用
    • 2.传址调用和传值调用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档