首页 > 其他分享 >6.C语言函数(下)

6.C语言函数(下)

时间:2024-11-28 17:30:34浏览次数:10  
标签:arr 函数 int C语言 static 数组 printf

文章目录


六、数组做函数参数

在使用函数解决问题的时候,难免会将数组作为参数传递给函数,在函数内部数组进行操作
比如:写一个函数将一个整型数组的内容,全部置为-1,再写一个函数打印数组的内容。

#include<stdio.h>
{
  int arr[] = {1,2,3,4,5,6,7,8,9,10};
  set_arr();
  printf_arr();
  return 0;
}

set_arr函数要能够对数组内容进行设置,就得把数组作为参数传递给函数,同时函数内部再设置数组每个元素得时候,也得遍历数组,需要知道数组得元素个数。
所以我们需要给set_arr传递2个参数,一个是数组,另外一个是数组得元素个数。

#include<stdio.h>
{
  int arr[] = {1,2,3,4,5,6,7,8,9,10};
  int se = sizeof(arr)/sizeof(arr[0]);
  set_arr(arr,sz);//设置数组内容为-1
  printf_arr(arr,sz);//打印数组内容
  return 0;
}

数组作为参数传递给了set_arr和printf_arr函数了。
这里我们需要知道数组传参得几个重点知识:

  • 函数的形式参数要和函数的实参个数匹配
  • 函数的实参是数组,形参也是可以写成数组形式的
  • 形参如果是一维数组,数组大小可以省略不写
  • 形参如果是二维数组,行可以省略,但是列不能省略
  • 数组传参,形参是不会创建新的数组的
  • 形参操作的数组和实参的数组是同一个数组
void set_arr(int arr[],int sz)
{
  int i = 0;
  for(i = 0;i < sz;i++)
  {
    arr[i] = -1;
  }
}

void printf_arr(int arr[],int sz)
{
  int  i = 0;
  for(i = 0;i <sz;i++)
  {
    printf("%d ",arr[i])
  }
  printf("\n");
}

七、嵌套调用和链式访问

7.1 嵌套调用

嵌套调用就是函数之间的互相调用,每个函数就像一个乐高零件,正式因为多个乐高零件互相无缝的配合才能搭建出精美的乐高玩具,也正是因为函数之间有效的互相调用,最后写出来了相对大型的程序。

假设我们计算某年某月有多少天?如果要函数实现,可以设计2个函数:

  • is_leap_year() :根据年份确定是否闰年
  • get_days_of_month():调用is_leap_year确定是否闰年后,再根据月计算这个月的天数
int is_leap_year(int y)
{
	if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
		return 1;
	else
		return 0;
}

int get_days_of_month(int y, int m)
{
	int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	int d = days[m];
	if(is_leap_year(y)&& m ==2 )//闰年的2月多1天
		d += 1;

    return d;
}

int main()
{
	int year = 0;
	int month = 0;
	scanf("%d %d", &year, &month);
	//计算year年month月的天数 2024年  10 月有多少天?
	int d = get_days_of_month(year, month);
		printf("%d\n", d);
	return 0;
}

这一段代码,完成了一个独立的功能。反应了不少函数的调用:

  • main函数调用scanf、printf、get_days_of_month
  • get_days_of_month函数调用is_leap_year

7.2 链式访问

所谓链式访问就是将一个函数的返回值作为另一个函数的参数 ,像链条一样将函数串起来就是函数的链式访问。

比如:

int main()
{
	size_t len = strlen("abc");  //strlen返回的值是size_t类型的
	printf("%zd\n", len);//打印长度
	return 0;
}

前面的代码完成了写了2条语句,但如果把strlen的返回值直接作为printf函数的参数呢?这样就是就是一个链式访问的例子了。

int main()
{
	printf("%zd\n", strlen("abc"));//链式访问
	return 0;
}

再看一个有趣的代码,下面代码执行的结果是什么呢?

#include<stdio.h>
int main()
{
  printf("%d",printf("%d",printf("%d",43)));
  return 0;
}

这个代码的关键是明白printf函数的返回是啥?

int printf(const char * format,...);

在这里插入图片描述
所以屏幕上最终打印:4321

八、函数的声明和定义

8.1 单个文件

一般我们在使用函数的时候,直接将函数写出来就使用了。
比如:我们要写一个函数判断一年是否是闰年。

#include<stdio.h>
//如果是闰年返回1
//否则返回0
int is_leap_year(int y)
{
	if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
	    return 1;
	else
		return 0;
}
//函数的定义
int main()
{
 int y = 0;
 scanf("%d",&y):
 //判断
 int r = is_leap_year(y);//函数的调用
 if(r == 1);
   printf("闰年\n");
 else
   printf("不是闰年\n");
 return 0;
}
//函数的调用

当我们将两个函数的顺序进行上下调换呢?会发生什么样的结果
在这里插入图片描述
这是因为C语⾔编译器对源代码进⾏编译的时候,从第⼀⾏往下扫描的,当遇到第7⾏的
函数调⽤的时候,并没有发现前⾯有is_leap_year的定义,就报出了上述的警告。

那我们应该如何解决呢?
就是函数调用之前先声明一下,is_leap_year这个函数,声明函数只要交代清楚:函数名,函数的返回类型和函数的参数。

在这里插入图片描述

8.2 多个文件(重要)!!

工程中写代码,我们不止需要一个代码。代码量会比较大,如果我们把所以代码都放在一个文件中,就不合适了
1.不便于协作
2.代码也不够清晰

在工程中,一个工程中会有多个文件
.h 文件
.c 文件

在这里插入图片描述
如果要调用其他的文件,需要在自己头文件中声明的函数,使用" *** ".

add.c

//函数的定义
int add(int x,int y)
{
  return x+y;
}

add.h

//函数的声明
int add(int x,int y);

test.c

#include<stdio.h>
#include "add.h"
int main()
{
  int x = 20;
  int y = 30;
  //函数的调用
  int c = add(a,b);
  printf("%d\n",c);
  return 0;
} 

有了函数声明和函数定义的理解,我们写代码就更加方便了。

8.3 static和extern

staticextern都是c语言中的关键字。
static是静态的意思,可以用来:

  • 修饰局部变量
  • 修饰全局变量
  • 修饰函数

extern是用来声明外部符号的。


在讲解之前我们先了解一下:作用域和生命周期。

  • 作用域:是程序设计概念,通常来说,⼀段程序代码中所⽤到的名字并不总是有效(可⽤)的,⽽限定这个名字的可⽤性的代码范围就是这个名字的作⽤域。
  1. 局部变量的作⽤域是变量所在的局部范围
  2. 全局变量的作⽤域是整个⼯程(项⽬)
  • 生命周期:指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的⼀个时间段。
  1. 局部变量的⽣命周期是:进⼊作⽤域变量创建,⽣命周期开始,出作⽤域⽣命周期结束
  2. 全局变量的⽣命周期是:整个程序的⽣命周期

8.3.1 static 修饰局部变量

下面我们看两端代码:

//代码1
void test()
{
	int n = 5;
	n++;
	printf("%d ", n);
}

int main()
{
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		test();
	}
	return 0;
}
 //输出6 6 6 6 6
//代码2
void test()
{
	static int n = 5;  //static修饰局部变量
	n++;
	printf("%d ", n);
}

int main()
{
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		test();
	}
	return 0;
}
//输出6 7 8 9 10

对比代码1和代码2的效果,我们可以看出static修饰局部变量的意义。

代码1:test函数中的局部变量i是每次进入test函数先创建变量,并赋值为0,然后++,再打印,出函数的时候变量生命周期将要结束(释放内存)。
代码2:我们输出结果来看,i的值有累加的效果。前边加上static修饰,出函数的时候不会销毁重新进入函数不会重新创建变量,直接上次累积的数值继续计算。
结论:static修饰局部变量改变了变量的生命周期,生命周期改变了变量的存储类型
在这里插入图片描述
使用建议:未来一个变量出了函数后,我们还行继续保留值,可以在函数之前使用static来进行修饰。

8.3.2 static修饰全局变量

代码1:
add.c

int g_val = 2018;

test.c

#include<stdio.h>
extern int g_val;
int main()
{
 printf("%d\n",g_val);
 return 0;
}

代码2:
add.c

static int g_val = 2018;

test.c

#include<stdio.h>
extern int g_val;  //extern是用来声明外部符号的
int main()
{
 printf("%d\n",g_val);
 return 0;
}

extern 是用来声明外部符号的,如果一个全局的符号在A文件中定义,在B文件中想使用,就可以使用extern进行声明,然后使用。

代码1正常,代码2在编译的时候会出现链接性错误。(全局变量被static修饰之后,外部链接属性就变成了内部链接属性,只能在文件内部使用了,其他源文件,即使声明了,也是无法正常使用的)

使用建议:如果一个全局变量,只想在所在的源文件内部使用,不想被其他文件发现,就可以使用static修饰。

8.3.3 static修饰函数

在这里插入图片描述
使用建议:⼀个函数只想在所在的源⽂件内部使⽤,不想被其他源⽂件使⽤,就可以使⽤static饰。


完结
2024/11/28 Thursday
有任何疑问可以在此私聊博主>_<!!!

标签:arr,函数,int,C语言,static,数组,printf
From: https://blog.csdn.net/weixin_64957584/article/details/144111165

相关文章

  • 用函数实现模块化的程序设计(四)
    4.对被调用函数的声明和函数原型前言在函数中调用另一个函数(即被调用函数)需要具备以下条件:(1)被调用函数必须是已经定义的函数(库函数或者用户自己定义的函数)(2)如果使用库函数,应在开头用#include指令调用有关库函数所用到的信息包含到文件(3)如果使用用户自己定义的函数,而该......
  • JavaScript中的匿名函数
    JavaScript中的匿名函数是一种没有名称的函数,它们通常用于需要函数对象而不需要引用函数的场合。匿名函数可以在声明时立即调用,也可以作为参数传递给其他函数,或者赋值给变量。如何使用匿名函数1、立即执行函数表达式(IIFE):立即执行函数表达式是一种常见的匿名函数使用方式,它在定......
  • CComboBox的SelectString函数有弊端-m_combo_xxx_.SelectString(0, strTxt); 重复
    CComboBox的SelectString函数有弊端CComboBox中字符串通过AddString添加后,比如天气1、天气2、天气222,天气234 CComboBox调用SelectString(0,_T("天气2"))函数有弊端。可能会选择的是 天气222应该用for循环判断m_comBoText.GetWindowText(strText);if(strText==你要选择......
  • mysql函数
    #字符串函数#拼接两个字符串concat(字符串1,字符串2)selectconcat('123','456');#123456#字符串中所有字符转小写lower(字符串)selectlower('Hello');#hello#字符串中所有字符转大写upper(字符串)selectupper('Hello');#HELLO#字符串向左侧补充长......
  • C语言:运算符1(混合运算和算数运算符)
    各类数值型数据间的混合运算整型、实型、字符型数据间可以进⾏混合运算,如:10-'a'*1.5运算时,参加运算的两个数据如果类型不同,则⾸先将其类型转换成⼀致再运算,转换规则是:将优先级低的类型转换到优先级⾼的类型,被称作自动类型转换(小转大)。⾃动类型转换的形式为:大类型......
  • C语言:运算符2(赋值运算符)
    赋值运算符“=”称之为赋值运算符,其作用是将一个数据赋值给一个变量。如:a=5执行赋值运算的结果,是将右边的数据存入左边变量对应的内存单元中,赋值运算的顺序:由右向左赋值规则如果赋值运算符两侧的类型不一致,则在赋值时要进行类型转换,转换规则为:实型→整型变量:舍弃⼩数部......
  • C语言 九宫格输入法
    假设有九宫格输入法键盘布局如下:[1,.?!][2ABC][3DEF][4GHI][5JKL][6MNO][7PQRS][8TUV][9WXYZ][0空]注意:中括号[]仅为了表示键盘的分隔,不是输入字符。每个中括号中,位于首位的数字字符即是键盘的按键,按一下即可输入该数字字......
  • VScode配置C语言环境
    第一步下载VScode:VisualStudioCode-CodeEditing.Redefined第二步搜索下载VScode插件:​ C/C++Chinese上面两个插件安装完成后会提示重启VScode完成中文语言设置第三步配置C语言编译器:https://wwgn.lanzoul.com/iB4US2gj0ayh密码:8y95下载完成后解压,这里我选择保存......
  • 【QT】使用Qxlsx读取Excel单元格中函数表达式的结果值
    【QT】使用Qxlsx读取Excel单元格中函数表达式的结果值零、起因是这样的,目前朋友托我写一款模板生成软件,任务是先把他写的程序文件复制一份出来,然后再根据Excel中对应位置的单元格的值,修改程序文件副本中的某些文件。对于读Excel的需求,经过测试,最终选择Qxlsx这款开源QT组件来读取......
  • Python中的函数缓存与记忆化技术:提升性能的必备技能
    《PythonOpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门!在软件开发中,性能优化是永恒的主题,而函数缓存与记忆化技术(Memoization)是提升代码性能的常用手段。它们通过存储函数调用的计算结果,避免重复计算,从而显著提高程序运行效率。Python提供了内置工具(如functo......