C语言——指针(五)

📝前言:

上篇文章C语言------指针(四)更加深入的介绍了不同类型指针的特点 ,这篇文章主要想记录一下函数与指针的结合运用 以及const和assert关于指针的用法
1,函数与指针
2,const
3,assert断言

🎬个人简介:努力学习ing

📋个人专栏:C语言入门基础

🎀CSDN主页 愚润求学

🌄每日鸡汤:对待生命,你不妨大胆一点,因为我们最终要失去它

文章目录

一,函数与指针

在上一篇文章中,我们提到了函数指针,函数指针是用来存放函数地址的指针,这篇文章,我们还将继续探究函数与指针。

1,指针变量作为函数参数

像int ,char类型一样,指针类型也可以作为函数的参数类型。

当我们使用指针类型作为函数的参数,实际向函数传递的是储存单元的地址。当我们改变该地址空间的数据后,尽管子程序调用结束,但是数据的改变情况也会被保留下来。

看下面这段代码👇🏻,利用swap函数能实现实参a和b的交换吗?

c 复制代码
void swap(int x,int y)
{
    int t = x;
        x = y;
        y = t;
}

答案是:不能

因为这个函数在传值时:只是把a和b的值传递给了形参,但是形参只是实参的临时拷贝,形参之间值的交换,无法影响到实参,所以也完成不了交换

当我们利用指针变量作为函数参数👇🏻

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//实现交换:
void swap1(int* p1, int* p2)
{
	int t;
	t = *p1;
	*p1 = *p2; 
	*p2 = t;
}
int main()
{
	int* pa, * pb, a = 3, b = 4;
	pa = &a;
	pb = &b;
	swap1(pa, pb); //调用函数,在函数内部交换
	printf("%d %d\n", a,b);
	return 0;
}

输出结果 👇🏻

我们发现🔍

a和b的值在函数内部被交换完以后,尽管函数调用结束,但是a和b是永久的交换了

这也就是传值和传址的区别:传值是对形参进行操作,但是传址是对实参的地址空间进行操作

2,返回指针的函数

我们把返回地址值 (即返回指针值)的函数称之为指针函数,指针函数定义如下:

类型名* 函数名(参数);

如:int * fun(int x, int y); 表示fun是具有两个整型参数且返回整型指针的函数,返回的指针值指向一个整型数据。

使用实例:

返回两个数中大数的地址的函数:

c 复制代码
int* fun(int* x, int* y)
{
	int* z;
	if (*x > *y)
		z = x;
	else
		z = y;
	return z;
}
int main()
{
	int a, b, * p;
	scanf("%d %d", &a, &b);
	p = fun(&a, &b);//用p来接收所返回的地址
	printf("max = %d\n", *p);//打印p所指向的数据
	return 0;
}

运行程序(输入3 8)👇🏻

max = 8,如我们所愿:函数fun返回了b的地址,p接收的就是b的地址👍

二,const

C语言中提供了const关键字,其主要作用是:
限定声明的变量值为常量,在程序运行时值不能改动。

1,const 修饰变量

如下面的代码👇🏻

c 复制代码
#include<stdio.h>
int main()
{
    int m = 0;
    m = 20; //这是我们正常的修改值的方式
    const int n = 0; //n有const修饰
    n = 20; //(错误)n无法修改
    return 0;
}

编译错误如下👇🏻

在上述代码中,n的本质还是变量,只不过被const修饰以后,在语法上加了限制,让我们不能直接修改n(这时,我们也称n为常变量)

2,const 修饰指针变量

下面有两种不同的修饰方式👇🏻

c 复制代码
const int *p; //第一种也等效于(int const *p)
int* const p;//第二种

●第一种,右边离const最近的是*,修饰的是*,意思是:不能通过p来改变p指向的空间的内容

●第二种,右边离const最近的是p,修饰的是p,意思是:不能改变p变量本身的内容

如下面的代码👇🏻

c 复制代码
int main()
{
   int n = 10;
   int m = 20;
   const int *pn = &n;
   *pn = 20;  //(无法执行)
   p = &m;  //(可以执行)
   return 0;
}

在上面的代码中

无法执行是因为:const修饰了*pn,所以pn所指向的内容无法修改

但是p = &m; 可以执行,因为p是变量本身,没有被限制,可以修改

再看下面的代码👇🏻

c 复制代码
int n = 10
int m = 20;
int const * const p = &n;

如果这样写,const既修饰了*,又修饰了p,则:
*p = 20;
p = &m;

都无法执行

三,assert断言

assert.h头文件中定义了宏assert()

1,assert的使用

assert()用于在运行时确保程序符合指定条件,如果不符合,就报错终止运行

如👇🏻

c 复制代码
#include<stdio.h>
#include<assert.h>
int main()
{
	int* p1 = NULL;
	assert(p1 != NULL);
	return 0;
}

一旦我们运行👇🏻

上面的代码:assert(p1!=NULL); 发现表达式不符合条件,于是assert就会终止运行,并且给出错误信息的提示。

assert()宏接受一个表达式作为参数:

●如果表达式为真(返回值非零),assert不会产生任何作用,程序继续执行。

●如果表达式为假(返回值为零),assert() 就会报错,在标准错误流stderr中写入一条错误信息,显示没有通过表达式(包含这个表达式的文件名和行号)

2,assert的禁用

上面谈到了用assert来检查程序,但是程序中使用assert会增加程序的运行时间。当程序没有问题,我们不需要assert的时候,只需在#include<assert.h>的语句前面定义一个宏NDEBUG

例如👇🏻

c 复制代码
#define NDEBUG
#include<assert.h>

这时候再编译程序,编译器就会禁用文件中所有的assert语句。

一般我们在Debug版本中使用assert,在Release中禁用assert

如:在vs这样的集成开发环境,Release版本中,是直接优化掉的;

但是在Linux的Release版本下,assert还起作用,需要我们自行禁用

🌈我的分享也就到此结束啦🌈

要是我的分享也能对你的学习起到帮助,那简直是太酷啦!

若有不足,还请大家多多指正,我们一起学习交流!

📢公主,王子:点赞👍→收藏⭐→关注🔍

感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

相关推荐
bdgtd881784 小时前
动态修补C扩展模块的函数指针有哪些风险?安全的修补方案是什么?
c语言·开发语言·安全
luquinn4 小时前
实现统一门户登录跳转免登录
开发语言·前端·javascript
Forward♞4 小时前
Qt——界面美化 QSS
开发语言·c++·qt
哈基米喜欢哈哈哈6 小时前
Kafka复制机制
笔记·分布式·后端·kafka
麻雀无能为力6 小时前
python自学笔记14 NumPy 线性代数
笔记·python·numpy
初学者_xuan7 小时前
Linux程序与进程和进程程序基础以及程序管理(零基础掌握版)
运维·计算机网络·网络安全·零基础·学习方法·linux程序管理
##学无止境##7 小时前
解锁Java分布式魔法:CAP与BASE的奇幻冒险
java·开发语言·分布式
做一位快乐的码农7 小时前
基于Spring Boot的旅行足迹分享社区的设计与实现/基于java的在线论坛系统
java·开发语言·spring boot
二级小助手7 小时前
C语言二级考试环境配置教程【window篇】
c语言·全国计算机二级·c语言二级·二级c语言·全国计算机二级c语言·c二级
kyle~8 小时前
C/C++---前缀和(Prefix Sum)
c语言·c++·算法