C语言学习系列:参数、类型转换、错误处理、递归

可变参数

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;
}
发布了161 篇原创文章 · 获赞 90 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_42415326/article/details/104027531
今日推荐