2024年最新从main函数参数,printf多参数来了解C语言可变参数函数,2024年最新跟我一起手写EventBus吧

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

main (argc,argv)

C语言还规定argc(第一个形参)必须是整型变量,argv(第二个形参)必须是指向字符串的指针数组。加上形参说明后,main函数的函数头应写为:

int main(int argc, char** argv)
或int main(int argc, char* argv[])

由于main函数不能被其它函数调用,因此不可能在程序内部取得实际值。那么,在何处把实参值赋予main函数的形参呢?实际上,main函数的参数值是从操作系统命令行上获得的。当我们要运行一个可执行文件时,在DOS提示符下键入文件名,再输入实际参数即可把这些实参传送到main的形参中去。

例如有命令行为:
C:>E24 BASIC foxpro FORTRAN
由于文件名E24本身也算一个参数,所以共有4个参数,因此argc取得的值为4。argv参数是字符串指针数组,其各元素值为命令行中各字符串(参数均按字符串处理)的首地址。 指针数组的长度即为参数个数。数组元素初值由系统自动赋予。其表示如图所示:

image-20210728214948116

main(int argc,char *argv){
    while(argc-->1)
        printf("%s\n",*++argv);
}

本例是显示命令行中输入的参数。如果上例的可执行文件名为e24.exe,存放在A驱动器的盘内。因此输入的命令行为:
C:>a:e24 BASIC foxpro FORTRAN
则运行结果为:
BASIC
foxpro
FORTRAN
该行共有4个参数,执行main时,argc的初值即为4。argv的4个元素分为4个字符串的首地址。执行while语句,每循环一次argv值减1,当argv等于1时停止循环,共循环三次,因此共可输出三个参数。在printf函数中,由于打印项*++argv是先加1再打印, 故第一次打印的是argv[1]所指的字符串BASIC。第二、三次循环分别打印后二个字符串。而参数e24是文件名,不必输出。

但是这带来了一个疑问:在C语言中是没有重载的,因此我们在声明定义函数时应该是要确定其有几个函数参数的。那为什么main函数可以不带参数,也可以带两个参数呢?

这个先按下不表,后面一起解答。


C语言中的printf函数应该是我们使用频率最高的库函数了吧?

我们在使用printf函数时,是可以根据需要选择输入参数的。

printf("%d",a);//两个参数
printf("%d %d",a ,b);//三个参数
printf("%d %d %d",a ,b ,c);//四个参数
……

看起来这个函数和我们之前用的函数时不一样的,之前我们用的函数都是必须确定函数参数,那为啥printf函数的参数是可变的呢?

看来这里面应该有一种机制来实现这种函数。先按下不表,我们来看看printf函数的源码实现

int printf
    (
    const char *  fmt,	/* format string to write */
    ...      		/* optional arguments to format string */
    )
    {
    va_list vaList;	/* traverses argument list */
    int nChars;

    va_start (vaList, fmt);
    nChars = fioFormatV (fmt, vaList, printbuf, 1);
    va_end (vaList);

    return (nChars);
    }
    
typedef struct {
	char *a0;	/* pointer to first homed integer argument */
	int offset;	/* byte offset of next parameter */
} va_list;

#define _INTSIZEOF(n)	( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v)	( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t)	( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap)	( ap = (va_list)0 )

/*******************************************************************************
*
* printbuf - printf() support routine: print characters in a buffer
*/

LOCAL STATUS printbuf
    (
    char *buf,
    int nbytes,
    int fd
    )
    {
    return (write (fd, buf, nbytes) == nbytes ? OK : ERROR);
    }
    



C++中有函数重载这种方法,以供我们调用时要可以不确定实参的个数,其实 C 语言也可以,而且更高明!

我们在stdio.h 中可以看到 printf() 函数的原型:

int printf(char * format,…)

事实上,我们如果要写这样的函数也可以类似的写,那么在定义函数时用上这个符号“ … ” ,它叫占位符,喊它 “ 三个点 ” 也可以,只要你愿意!那么我可以这样定义我的函数:

fun(int a,…) { }

且听我介绍3 个小东东:

1、 va_list

2、 va_arg()

3、 va_start()

在学习这3 个小东东之前,我们先回忆一下, C 语言是怎么操作文件时,是怎么样处理内存中的数据的呢?学习文件操作时,我们提到了“流”的概念,我们用指针指向数据所在的内存地址,再一个一个的操作。

学习指针时,我们知道有函数指针这个东东,不是指针函数而是函数打针哦!(呵呵,我的同学如果还记得就当复习一下,不要嫌我啰嗦_ )。我们记得程序在执行时,会将函数存储到内存中去。现在深入的讲一点点,存储函数时,参数传递的过程是怎样实现的呢?所谓的形式参数(局部变量)实质上又是什么呢?把这些问题连起来想想,想通了,你的思维势如破竹!

在调用函数时,程序同样会把实参传入,在函数存储区保存起来,如果有很多参数,将一起保存起来。

这时候就要用到va_list 了,这是个类型定义,我们可以把它理解成一个指针,它指向第一个参数的地址。

如果,我们这样定义: va_list pp ;

则pp 就是这样一种变量,它是指向所有参数中的第一个参数的。它不同于一般的指针变量,它是个复合变量,什么是复合变量啊?结构体类型的嘛,呵呵。如果 a 是第一个参数,能不能写成 pp=a 呢?

假设我定义了char d[]=“ruixin”,e[]=“gelin”; 我要把 e 的值赋给 d ,能不能写成 d=e 呢?得用 strcpy() ,是吧!呵呵,一样的道理,这儿我们也用一个函数来实现,它就是 va_start();

如果这样写:va_start(pp,a);

那么pp 就指向第一个参数 a 了,并且可得到 a 的类型 int 。

这时候如果有下一个参数,就需要使pp 指向下一个参数,并且得到它的类型。同样需要使用函数来实现,这个函数是: va_arg()

可以这样写:va_arg(pp, 类型 ) ,这样 pp 就指向一个参数,并且可以得到那个参数的类型了。

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值