可变参数
C语言允许定义的函数带有可变数量的参数,而不是预定义数量的参数。可变参数函数定义如下:
#include<stdarg.h>
//定义一个函数,最后一个参数为省略号,省略号前面可以设置自定义参数。
int func(int num, ... )
{
//在函数定义中创建一个 va_list 类型变量
va_list valist;
int i;
//使用 int 参数和 va_start 宏来初始化 va_list 变量为一个参数列表。
va_start(valist, num);
for (i = 0; i < num; i++)
{
//使用 va_arg 宏和 va_list 变量来访问参数列表中的每个项
sum += va_arg(valist, int);
}
// 使用宏 va_end 来清理赋予 va_list 变量的内存
va_end(valist);
return sum;
}
为了使用这个功能,需要引用 stdarg.h 头文件,该文件提供了实现可变参数功能的函数和宏(va_start,va_list,va_arg,va_end)。
命令行参数
命令行参数是从命令行传值给 C 程序的。特别是需要从外部控制程序,而不是在代码内对这些值进行硬编码时,显得 很重要。命令行参数是使用 main() 函数参数来处理的,其中,argc 是指传入参数的个数,argv[] 是一个指针数组,指向传递给程序的每个参数。
#include <stdio.h>
int main( int argc, char *argv[] )
{
if( argc == 2)printf("提供的%d个参数是 %s\n,",argc-1,argv[1]);
else if(argc > 2) printf("提供2个及以上的参数\n");
else printf("只有程序名称这一个参数\n");
}
不同情况编译如下:
$./a.out testing
提供的1个参数是 %s\n is testing
$./a.out testing1 testing2
提供2个及以上的参数
$./a.out
只有程序名称这一个参数
注意:argv[0] 存储程序的名称,argv[1] 是一个指向第一个命令行参数的指针,argv[n] 是最后一个参数。
如果没有提供任何参数,argc 将为 1,否则,如果自己传递了一个参数,argc 将被设置为 2。
多个命令行参数之间用空格分隔,但是如果参数本身带有空格,那么传递参数的时候应把参数放置在双引号 "" 或单引号 '' 内部(以字符串的形式传递)。
强制类型转换
强制类型转换是把变量从一种类型转换为另一种数据类型。使用强制类型转换运算符来把 值 显式地从一种类型转换为另一种类型:
(type_name) expression
比如:
mean = (double) sum / count;
强制类型转换运算符的优先级大于除法,因此 sum 的值首先被转换为 double 型,然后除以 count,得到一个类型为 double 的值。类型转换也可以是隐式的,由编译器自动执行,但最好还是通过使用强制类型转换运算符来指明类型转换。
整数提升
整数提升是指把小于 int 或 unsigned int 的整数类型(比如char类型和short类型)转换为 int 或 unsigned int 的过程。
常用的算术转换是隐式地把值强制转换为相同的类型。编译器首先执行整数提升,如果操作数类型不同,则它们会被转换为下列层次中出现的最高层次的类型:
也就是说运算符两边的操作数类型不同,先要将低类型其转换为相同的高类型,然后再参加运算,最终结果为最高类型。常用的算术转换不适用于赋值运算符、逻辑运算符 && 和 || 。
错误处理
在发生错误时,大多数的 C 或 UNIX 函数调用会返回 1 或 NULL,errno是全局变量,表示在函数调用期间发生了错误,程序初始化时,应该将 errno 设置为 0 ,errno的各种各样的文本表示形式在头文件errno.h中。
perror() 函数显示您传给它的字符串,后跟一个冒号、一个空格和当前 errno 值的文本表示形式。
strerror() 函数,返回一个指针,指针指向当前 errno 值的文本表示形式。
注意:对于错误的输出,应该使用 stderr 文件流。
#include <stdio.h>
#include <errno.h>
#include <string.h>
extern int errno ;
int main ()
{
FILE * pf;
int errnum;
pf = fopen ("unexist.txt", "rb");
if (pf == NULL)
{
errnum = errno;
fprintf(stderr, "错误号: %d\n", errno);
perror("通过 perror 输出错误");
fprintf(stderr, "打开文件错误: %s\n", strerror( errnum ));
}
else
{
fclose (pf);
}
return 0;
}
被零除的错误
在进行除法运算时,如果不检查除数是否为零,则会导致一个运行时错误。
if( divisor == 0){
fprintf(stderr, "除数为 0 退出运行...\n");
exit(-1);
}
程序退出状态
通常情况下,程序成功执行完一个操作正常退出的时候会带有值 EXIT_SUCCESS。在这里,EXIT_SUCCESS 是宏,它被定义为 0。可以使用exit( ) 函数进行程序退出。
如果程序中存在一种错误情况,当您退出程序时,会带有状态值 EXIT_FAILURE,被定义为 -1。
递归
递归,即一个函数可以调用其自身。与直接的语句(如while循环)相比,递归函数会耗费更多的运行时间,并且要占用大量的栈空间。递归函数每次调用自身时,都需要把它的状态存到栈中,以便在它调用完自身后,程序可以返回到它原来的状态。未经精心设计的递归函数总是会带来麻烦。
以打印斐波那契数列为例,递归方法:
#include <stdio.h>
int fibonaci(int i)
{
if(i == 1)return 1;
if(i == 2)return 1;
return fibonaci(i-1) + fibonaci(i-2);
}
int main()
{
int n;
scanf("%d",&n);
for (int i = 1; i <= n; i++)printf("%d ", fibonaci(i));
return 0;
}
非递归方法:
#include <stdio.h>
int fibonaci(int i)
{
if(i == 1)return 1;
if(i == 2)return 1;
i = i - 2;
int a = 1,b = 1,sum;
for(int j = i;j > 0;j--){
sum = a + b;
a = b;
b = sum;
}
return b;
}
int main()
{
int n;
scanf("%d",&n);
for (int i = 1; i <= n; i++)printf("%d ", fibonaci(i));
return 0;
}