在C语言编程中,变量的生命周期和作用域是我们必须掌握的重要概念。你是否曾经遇到过这样的需求:希望函数中的局部变量能够“记住”上一次调用时的值,而不是每次都被重新初始化?这正是
static关键字的魔力所在!本文将带你深入探索static的奥秘,理解它如何改变变量的存储特性,让局部变量跨越函数调用的界限,保持其值的持久性。无论你是C语言初学者还是有一定经验的开发者,掌握static的用法都将为你的编程技能增添重要的一笔
数组的诞生是为了存放一组数据的(避免啰嗦复杂)


部分初始化(可以调试验证) 初始化多个元素,所以用大括号


全部初始化

一维数组的类型

初始化的时候可以省略[]里面的大小,会自动根据后面的元素来确定个数,如果不初始化,必须要指定大小 验证方式:

一维数组存放数据就是对数据进行操作的,使用下标(类似于编号)来操作




会自动计算元素个数,就算输入太多,超过元素个数后面的也会自动舍弃
将环境改成X86的环境,内存单位为一个字节,%p打印为地址的16进制

有图可以得到:数组是连续存放的 随着下标增长,地址由低(小)变高(大)


二维数组初始跟一维数组一样,可以部分初始化或者全部初始化,初始化可以省略行不能省略列,编译器根据初始化的内容自动初始化行

二维数组存放

由图可以看出数组的存储方式是连续存放的

二维数组中每一行可以理解为一维数组,每一行一维数组名为arr[],从这里可以得到,为啥初始化时可以省略行,不能省略列,因为行取决于内容,不知道列有几个元素,每一行不知道从哪里开始放(比如:第二行放到第一行的后面)

注意:当初始化为0的时候,里面有一个元素,后面输入不能超出1

注意:变长数组不能初始化 变长数组的意思是数组的大小可以用变量来指定,一旦数组创建好后,大小就无法改变 VS上不支持变长数组的语法 变长数组一定是在运行时确定的,一旦确定大小,不能改变




查找库函数相关头文件:https://en.cppreference.com/w/c/header.html
网站:https://legacy.cplusplus.com/reference/clibrary/
举例:sqrt
首先查找sqrt

由于有英文,哪里看不懂,用鼠标选中,右击,选择翻译,就可以看懂 函数原型和介绍:

功能:

头文件在旁边:

参数:

返回值:

有举例:

其他函数(相关的)链接:

实践:
#include<stdio.h>
#include<math.h>
int main()
{
double a = 100;
printf("%lf", sqrt(a));
return 0;
}读一般文档流程:

高内聚低耦合

补充:

#include<stdio.h>
int main()
{
char arr[] = "hellow";//[h e l l o w \0]
int right = sizeof(arr) / sizeof(arr[0]) - 2;
printf("%d", right);
return 0;
}另一种注释
# if 0
#endif格式:


==注意点:==当形参为void,就明确实参不能传参数,当形参里面的参数不写,传参数没关系(最好不要传参数)
形参与实参


当return后面跟表达式,先把表达式算出,再返回值
当函数返回类型为void,return后面可以不接任何表达式(场景:不返回任何值,但是想提前结束)
比如下面场景(函数的功能为打印1~n的值,所以不需要返回,参数用void):
#include<stdio.h>
void test(int n)
{
if (n < 0)
{
return;
}
int i = 0;
int sum = 0;
for (int i = 0; i <= n; i++)
{
sum += i;
}
printf("%d", sum);
}
int main()
{
int n;
while (scanf("%d", &n) != EOF)
{
test(n);
}
return 0;
}当return返回值与函数返回类型不一致,系统自动将返回的值隐式转化为函数的返回类型

想要提前返回,可以使用return语句
当函数里存在像if那样的分支语句,必须每一条路径都有return语句返回

错误原因:

#include<stdio.h>
void set_arr(int arr1[],int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
arr1[i] = -1;
}
}
void print_arr(int arr1[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr1[i]);
}
printf("\n");
}
int main()
{
int arr[10] = { 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
print_arr(arr, sz);
set_arr(arr,sz);
print_arr(arr, sz);
return 0;
}
数组在形参和实参中为同一个数组 验证:


注意:形参中传的是数组名,不要传数组的元素arr[10]

#include<stdio.h>
#include<stdbool.h>
_Bool is_leap(int y)
{
if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
{
return true;
}
else
{
return false;
}
}
int get_day(int y, int m)
{
int days[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (is_leap(y) && m == 2)
{
days[2] += 1;
}
int day = days[m];
return day;
}
int main()
{
int year = 0;
int month = 0;
scanf("%d%d", &year, &month);
int day = get_day(year, month);
printf("%d", day);
return 0;
}函数嵌套调用别人,调用自己叫递归 函数不能定义在函数里面,函数之间互相平等

举例:printf("%d",strlen("abc"));
题目:下面输出结果
#include<stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}注意点:弄清printf()的返回值
在这个网站上搜索printf:
https://legacy.cplusplus.com/reference/clibrary/

结果:

变式:

高内聚: 自己做功能独立、干净 低耦合: 函数不要有太多的功能,既要有要 反例(不方便其他函数调用):函数不够独立

add.h、add.c、test.c,把add.c和add.h当成一整个模块(同一个模块,文件名字相同,后缀不同)#pragma once
int Add(int x, int y);int Add(int x, int y)
{
return x + y;
}#include<stdio.h>
#include"add.h"
int main()
{
int a;
int b;
scanf("%d%d", &a, &b);
int ret = Add(a, b);
printf("%d", ret);
return 0;
}
适当隐藏代码(以add为例)
程序员给公司add.h(只告诉你函数名和参数,所以具体实现不知道),给add.c编译后的产生的文件(不会暴露源代码)
下面是模拟过程实现:
A程序员写的模块:

将配置类型改成静态库

将这两个文件给公司

模拟公司场景:(只有一个调用函数)

将程序员给的两个文件导进去

添加到项目中,引用头文件,运行,但是有报错

解决办法(导入静态库):

如果环境要求不行,改为X86或X64的
补充: 作用域: 通常来说,一段程序代码中所用到的名字并不总是有效(可用)的,而限定这个名字的可用性的代码范围就是这个名字的作用域,作用域通常是在大括号里面

生命周期(与作用域协同的): 指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的一个时间段(类比人的生命周期)

static和extern:

static修饰局部变量
出函数时,并没有销毁,保留了上一次的值,因为上一次创建了n,下一次就不创建了和赋值(变量的存储位置/存储类型发生变化,作用域没变,只能在作用域使用)
对比图

先介绍extern的作用,在引入static
当不同文件变量相互使用时
比如:

解决办法:extern专门用来声明外部符号的(其他文件的符号)
变量跨文件使用方法,满足全局变量的是整个工程(项目),前提要声明才能使用

static修饰全局变量

原因:

extern和static修饰函数
函数不像变量那样在不同文件必须声明,不声明也可以运行,但正常来说最好还是声明(没有警告)

同理,static修饰函数与static修饰全局变量一样有外部链接属性,被static修饰后,变成内部链接属性,只能在本文件内部使用,其他文件无法正常的链接使用了。本质不变

通过本文的学习,我们揭开了static关键字的神秘面纱,了解了它如何让局部变量“记住”上一次的值,以及如何改变全局变量和函数的链接属性。static的巧妙运用不仅能让我们的代码更加灵活高效,还能提升程序的模块化和封装性。记住,static修饰局部变量改变了其生命周期但不改变作用域;修饰全局变量和函数则改变了它们的链接属性,使其仅限于文件内部使用。希望读者能够将这些知识融会贯通,在实际编程中灵活运用,写出更加优雅、高效的C语言代码。编程之路漫漫,让我们继续探索更多C语言的精妙之处