1.主函数
(1)主函数的作用
主函数是程序的入口函数,即所有的程序一定要包含一个主函数,程序总是从这个函数开始执行,如果没有该函数,程序就无法启动。主函数中可以调用其它函数,但其它函数不能反过来调用主函数,主函数也不能调用自己。
(2)主函数的返回值
C语言约定,主函数返回值0表示运行成功,如果返回其它非零整数,就表示运行失败。默认情况下,如果主函数里面省略return 0 这一行,编译器会自动加上,即 main() 的默认返回值为0。但是为了保持统一的代码风格,不建议省略。
(3)主函数的参数
int main(int argc, char *argv[])
{
// 函数体
}
形参argc,全称是argument count,表示传给程序的参数个数,其值至少是1;而argv,全称是argument value,argv[]是一个指针数组
2.作用域
作用域用于确定在代码中某个标识符(如变量、标识符常量、数组等)的可见性和访问范围,它决定了在程序的哪些部分可以引用或访问该标识符。作用域可以分为全局作用域、局部作用域、块级作用域。同一个作用域中不能声明同名的标识符。
2.1全局作用域
在函数和代码块(分支语句、循环语句等)以外定义的变量、标识符常量、数组等具有全局作用域,在程序的任何地方都可以被访问,通常称它们为全局变量、全局常量、全局数组等于全局变量,如果没有显式指定初始值,它们将自动初始化为零值。对于全局数组,如果没有显式初始化它们,它们的元素将自动初始化为零值,字符数组,将初始化为空字符 \0。
#include <stdio.h>
// 定义全局变量不进行初始化赋值
int a; // 自动初始化为0
double b; // 自动初始化为0.0
char c; // 自动初始化为空字符 \0
// 定义全局数组不进行初始化
int arr[5]; // 所有元素自动初始化为0
char msg[6]; // 所有元素自动初始化为空字符 \0
2.2局部作用域
在函数内定义的变量、标识符常量、数组等具有局部作用域,只有在该函数内部才能被访问,通常称它们为局部变量、局部常量、局部数组等。需要注意的是,函数的形参也是局部变量。如果局部作用域中定义了与全局作用域中同名的标识符,优先使用本作用域中定义的数据。与全局变量和全局数组不同,局部变量和局部数组如果没有显式初始化,它们的初始值是机器垃圾值,即系统之前分配给这块空间的值。所以不对局部变量、局部数组初始化是不安全且强烈不建议的。
据,相关代码示例如下:
#include <stdio.h>
// 全局变量
int a = 100;
int b = 200;
void add()
{
int a = 300;
a += 10;
b += 10;
printf("函数 add 内部: a=%d, b=%d \n", a, b);
}
int main()
{
// 调用函数 add
add(); // 函数 add 内部: a=310, b=210
printf("函数 add 外部: a=%d, b=%d \n", a, b); // 函数 add 外部: a=100, b=210
return 0;
}
//输出结果:
//函数 add 内部: a=310, b=210
//函数 add 外部: a=100, b=210
2.3块级作用域
块级作用域是C99标准引入的概念,在代码块(分支语句、循环语句等)中定义的变量、标识符常量、数组等具有块级作用域,只有在该代码块内部才能被访问,代码块通常具有花括号 {} 结构。这些被称为块级变量、块级常量、块级数组等,同时也可以被称为局部变量、局部常量、局部数组,且与函数中的局部变量、局部常量、局部数组具有相同的特性。
{
// 块级变量
int a = 20;
// 块级常量
const double PI = 3.14;
printf("a*PI=%f \n", a * PI);
}
// 循环语句中的标记变量i是块级变量
for (int i = 0; i < 5; i++)
{
printf("%d ", i);
}
3.作用域和内存
3.1栈区域
局部变量、局部数组等通常存储在栈(Stack)区,这些局部数据的内存分配和释放是自动管理的,它们的生命周期受限于其定义的函数或块级作用域,当函数返回或块级作用域结束时,这些变量的内存会被自动释放。函数每调用一次就创建一次局部数据,调用结束就销毁;下次调用再创建新的局部数据。
3.2全局静态区域
全局变量、全局数组等存储在全局静态区,这些全局的数据在程序的整个生命周期内都存在,它们在程序启动时被分配,在程序结束时才被释放。
3.3 static和extern关键字
static关键字可以声明静态变量和静态函数,以控制变量和函数的作用范围和生存周期。使用static关键字修饰的局部变量,称为静态局部变量,静态局部变量与全局变量一样存储在内存中的全局静态区。
静态局部变量有如下特点
(1)静态局部变量只在函数第一次调用时初始化一次并将生命周期延长到整个程序的执行期间。
(2)静态局部变量如果声明时没有初始赋值,系统会自动初始化为零,同全局变量的初始化规则一致。
extern:简单来说就是在多个文件,可以使用一个文件中的变量或者函数等在另一个文件中使用比如
// 外部声明 main.c 中定义的全局变量
extern int num01;
extern const double PI01;
extern char msg01[];
extern void fn01();但是如果是被static修饰过的变量extern是无法在其他文件中声明使用的
4.递归函数(重点但是对我这种学习嵌入式软件开发的来说知道了解就足够了)
#include <stdio.h>
// 递归函数:本质就是函数自己调用自己------【了解即可】
// 递归函数:递归函数务必要有一个趋近于结束的条件
void fun(int num)
{
printf("num1=%d\n", num);
// 条件判断
if (num > 1)
{
fun(num - 1);
}
printf("num2=%d\n", num);
}
int main()
{
fun(3);
return 0;
}
4.1斐波那契数列
#include <stdio.h>
/**
* 斐波那契数列:8->21
*
* 1 1 2 3 5 8 13 21........
*
* feibonaqie(1) = 1
* feibonaqie(2) = 1
*
*
*
* feibonaqie(2) + feibonaqie(1) = 2
*
*/
int feibonaqie(int n)
{
// 趋近于结束的条件
if (n == 1 || n == 2)
{
return 1;
}
else
{
// 从第三位以后开始 前两个之和
return feibonaqie(n - 1) + feibonaqie(n - 2);
}
}
int main()
{
int n;
printf("请您输入要查询的这个斐波那契数字的位置:");
scanf("%d", &n);
int result = feibonaqie(n);
printf("%d位置的斐波那契数列的数字是%d\n", n, result);
return 0;
}
4.2猴子吃桃
有一堆桃子,猴子第一天吃了其中的一半,并多吃一个。以后每天猴子都吃其中的一半,然后再多吃一个。当到第十天时,想再吃时(注意:此时还没吃),发现只有1个桃子了。问:最初共多少个桃子?
#include <stdio.h>
/**
* 第十天: 1
* 第九天: 4
* 第八天: 10
* 第七天: 22
* .......
*/
int peach(int day)
{
// 趋近于结束的条件
if (day == 10)
{
return 1;
}
else
{
return (peach(day + 1) + 1) * 2;
}
}
// peach(10) == 1
// (peach(10) + 1 )* 2
int main()
{
// 用户输入一个天数
int day;
printf("请您输入一下查询的天数:");
scanf("%d", &day);
int result = peach(day);
printf("第几天%d,还有%d个桃子\n", day, result);
return 0;
}
5.常用系统函数
<string.h> 头文件中的函数
标准库的头文件 <string.h> 中,有三个常用的字符串函数:
函数名 | 描述 |
strlen(str) | 返回str的长度,类型是 size_t |
strcpy(str1,str2) | 将str2中的字符串复制到str1中 |
strcat(str1,str2) | 将 str2 中的字符串追加到 str1 后面 |
<stdio.h> 头文件中的函数
标准库的头文件 <stdio.h> 中,也有两个字符串函数:
sprintf(),用于将格式化数据写入字符串。相比于 printf(),多了一个参数,第一个参数是要写入的字符串,后面参数与 printf() 一致。简单地讲,sprintf() 是将内容写入字符串而不是输出。
sscanf(),用于从一个字符串中按照指定的格式提取数据。相比于 scanf(),多了一个参数,第一个参数是要提取数据的字符串,后面参数与 scanf() 一致。简单地讲,sscanf() 是从字符串中提取数据而不是从用户输入提取数据。
日期时间相关函数,头文件 <time.h>
函数名 | 描述 |
time(&变量) | 获取当前日期赋值到变量中,该变量需是 time_t 类型 |
ctime(&时间值) | 将时间值转为字符串并返回,时间值需是 time_t 类型 |
difftime(时间值1,时间值2) | 返回两个时间值的差,返回值是 double 类型,时间值需是 time_t 类型 |
数学相关函数,在头文件 <math.h> 中。
函数名 | 描述 |
sqrt(x) | 计算平方根 |
cbrt(x) | 计算立方根 |
pow(x,y) | 计算x的y次方 |
fabs(x) | 计算x的绝对值 |
ceil(x) | 向上取整 |
floor(x) | 向下取整 |
round(x) | 四舍五入取整 |
trunc(c) | 截断小数部分 |
注意:以上函数的参数与返回值的类型都是 double 类型。