05 C Function
函数
函数应用
交换变量函数
//错解1:只交换形参的值
void swap(int x, int y)
{
int z;
z = x; x = y; y = z;
}
//错解2:*p无确定指向
void swap(int* p1, int* p2)
{
int *p;
*p = *p1; *p1 = *p2; *p2 = *p;
}
//错解3:只交换形参指向
void swap(int *p1, int *p2)
{
int *p;
p = p1; p1 = p2; p2 = p;
}
//正解:通过形参指针改变实参变量的值
void swap(int* p1, int* p2)
{
int z;
z = *p1;
*p1 = *p2;
*p2 = z;
}
转化二进制函数(递归)
#include <stdio.h>
void to_binary(unsigned long n)
{
int r = n % 2;
if (n >= 2)
to_binary(n / 2);
putchar(r == 0 ? '0' : '1');
return;
}
int main(void)
{
unsigned long number;
printf("Enter an integer (q to quit):\n");
while (scanf("%lu", &number) == 1)
{
printf("Binary equivalent: ");
to_binary(number);
printf("\nEnter an integer (q to quit):\n");
}
printf("Done.\n");
return 0;
}
变量
-
局部变量与全局变量
-
作用域 能够被直接访问的代码范围(空间角度)
生命期 在内存中具有相应的内存空间的时间范围(时间角度)
-
局部变量
-
作用域:从定义处到函数(或复合语句)结束。局部变量只能在这个范围内被直接访问
-
生命期:依赖于存储类别,可能是从函数调用开始到结束,也可能是从程序执行开始到结束
-
-
全局变量
- 作用域:从定义处到源文件结束。全局变量可以在这个可能包含多个函数的范围内被直接访问
- 生命期:从程序执行开始到结束
-
变量定义和声明
- 把建立存储空间的变量声明称为定义,而把不需要建立存储空间的变量声明称为声明
- 外部变量是对变量的声明,除此以外,其它的变量声明都是定义
-
-
变量的存储类别
StorageClass Type Name;- 自动变量(auto)
- 必须是局部变量,若未显式声明存储类别,就为自动变量
- 作用域:从定义处到函数(或复合语句)结束
- 生命期:从函数调用(或复合语句执行)开始到结束。函数调用开始时,系统会给自动变量分配存储空间,调用结束时就自动释放空间
- 外部变量(extern)
- 外部变量可以是局部或全局变量。外部变量并不定义一个新的变量,而是扩展一个全局变量的作用域
- 作用域:对于局部变量,从定义处到函数(或复合语句)结束;对于全局变量,从定义处到文件结束。
- 生命期:从程序执行开始到结束
- 在函数定义前也加 extern 能够将函数的作用域扩展到其它文件中,其它文件可以调用该函数。若未显式声明为 extern ,则默认为外部函数
- 静态变量(static)
- 必须是局部变量
- 作用域:从定义处到函数(或复合语句)结束
- 生命期:从程序执行开始到结束。在函数调用结束后不释放静态变量的内存空间,在下一次再调用该函数时,该静态变量的值就是上一次函数调用结束时的值
- 在全局变量或者函数定义前加 static ,并不定义静态存储,而是将全局变量或函数的作用域限制在本文件中,其它文件即使使用extern外部声明也无法访问或调用如
static int A;static void func();
- 寄存器变量
- 必须是局部变量
- 寄存器变量存放在 CPU 寄存器中
- 作用域和生命期与 auto 变量相同
- 自动变量(auto)
程序的内存布局
- 代码段 text segment 用于存储可执行指令
- 数据段 data segments 用于存储全局变量和静态局部变量。其中,未初始化数据段中的变量将被初始化为0
- 堆 heap 用于动态内存分配,空间从低地址往高增长
- 栈 stack 用于存储函数栈帧,空间从高地址往低增长
- 程序开始执行时给 全局变量和静态局部变量 分配内存空间,默认初始值为0。程序执行完毕时释放空间
- 函数调用开始时给 自动局部变量(包括形参) 分配内存空间,初始值为随机值(内存遗留垃圾)。函数调用结束时释放空间
动态内存分配
在堆中分配指定大小内存空间,包含头文件#include<stdlib.h>
malloc函数
void *malloc(unsigned size);
在内存的堆中分配一个长度为size的连续内存空间。返回所分配空间的首地址(指针类型)。若未能成功执行(例如内存空间不足),则返回空指针(NULL)
int *p;
p = (int *) malloc(100);//应坚持使用强制类型转换
*p = 1;
printf("%d\n", *p);
calloc函数
void *calloc(unsigned n,unsigned size);
分配 n 个长度为 size 的连续内存空间,返回值与 malloc 一样
int* p;
p = (int *) calloc(5, 20);
*p = 1;
printf("%d\n", *p);
free函数
void free(void *p);
动态分配的内存只能增加,必须进行清理
释放指针p所指向的内存空间,使这部分空间能重新被分配使用
int* p;
p = (int *) malloc(100);
*p = 1;
printf("%d\n", *p);
free(p);
p = (int *) calloc(5, 20);
*p = 2;
free(p);
realloc函数
void *realloc(void *p,unsigned size);
若 p 所指向的内存空间是通过 malloc 函数或 calloc 函数分配的,那么将这个内存空间的大小改为 size,返回值与 malloc 一样
int *p, *q;
p = (int *) malloc(100);
*p = 1;
q = (int *) realloc(p, 20);
printf("%p, %p, %d\n", p, q, *q);
free(p);
函数指针
指向函数的起始地址
Type (*Name)([ParameterList]);
例:定义类型为int (*)(int, int)的指针变量 p ,指向一个函数,这个函数的类型为整型且有两个整型形参
#include <stdio.h>
int add(int a, int b)
{return a + b;}
int main()
{
int (*p)(int, int);
int i;
p = add; // right
//p = add(1, 2); wrong
i = (*p)(1, 2);//right
i = p(1, 2);//right
printf("%d\n", i);
return 0;
}
函数指针算术运算无意义,如p+n, p++等

浙公网安备 33010602011771号