C程序设计语言- 输入与输出-6.1----标准输入与输出、格式化输出(printf)、变长参数表、格式化输入(scanf)、文件访问

前言:继续C系列基础。C系列也快进入尾声了,估计还有俩篇博客。


1.标准输入与输出



2..变长参数表

每一个程序员写的第一个程序大概鼎鼎大名的hello world了,一个简简单单,就那么几行的小程序开启了另一个世界的大门,从此,我们发现了更广阔的世界。而每一个C程序员接触到的第一个函数(除去main函数不算)大概就是printf函数了。这个函数用法很简单灵活,然而里面暗藏玄机,包含了C语言诸多的内容。 
  不知道大家发现没有,printf函数的参数个数是可变的。下面这三个函数都可以完美运行。

  printf("hello,world\n");
  printf("this is a int num %d\n",a);
  printf("this is a string %s,and a num %d\n",s,a);
   
   
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

  上面这三个函数分别有一个、两个、三个参数。而我们学的C语言函数参数的个数都是固定的,比如下面这个swap()函数,必须传入两个int型指针才能运行。

void swap(int *a,int *b)
{
    int tmp=*a;
    *a=*b;
    *b=tmp;
}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

  而且C语言里面没有类似C++当中类似默认构造函数的机制,那么printf函数参数个数可变是怎么实现的呢? 
  printf()函数的声明形式是这样: 
  

int printf(char *fmt,...)
   
   
  • 1
  • 1

  第一个参数是char型指针,第二个参数是”…”???正是这个“…”实现了printf的变长参数表。 
   
  标准头文件stddrg.h当中包含了一组宏定义,它们对如何遍历参数表进行了定义。 
  va_list 类型用于声明一个变量,该变量将依次引用各参数。我们将该变量称为ap,意思是“参数指针”。宏va_start将ap初始化为指向第一个无名参数的指针。在使用ap 之前,该宏必须被调用一次。参数表必须至少包括一个有名参数,va_start将最后一个有名参数作为起点。 
  每次调用va_arg,该函数都将返回一个参数,并将ap 指向下一个参数。va_arg 使用一个类型名来决定返回的对象类型、指针移动的步长。最后,必须在函数返回之前调用va_end,以完成一些必要的清理工作。

下面使用变长参数表实现printf的两个简单功能,打印整数和字符串。

//main.c文件内容
#include<stdio.h>
#include "print_dec.h"
#include<stdarg.h>
void print(char *fmt,...);
int main()
{
    int i;
    char s[100];
    scanf("%d",&i);
    scanf("%s",s);
    print("this is a int: %d\n",i);
    print("this is a string:\n%s\n",s);
    return 0;
}
void print(char *fmt,...)
{
    int i;
    char *m;
    va_list p;
    va_start(p,fmt);
    //将有名参数fmt作为起点,p此时指向第一个无名参数
    char *tmp;

    for(tmp = fmt;*tmp;tmp++)
    {
        if(*tmp!='%')
        {
            putchar(*tmp);
            continue;
        }
        switch(*++tmp)
        {
            case 'd':
                i = va_arg(p,int);
                //获得一个无名参数,同时p指向下一个无名参数
                print_dec(i);//打印数字i
                break;
            case 's':
                m = va_arg(p,char *);
                //获得一个无名参数,同时p指向下一个无名参数
                for(;*m;m++)
                    putchar(*m);
        }   
    }
    va_end(p);//结束时的清理工作
}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
//print_dec.c文件内容
#include<stdio.h>
void print_dec_(int i)//这个函数可以实现打印正整数
{
    if(i == 0)
        putchar(i);
    else 
    {
        print_dec_(i/10);
        int m = i%10 + '0';
        putchar(m);
    }
}
void print_dec(int i)//实现打印0和正整数
{
    if(i==0)
        putchar('0');
    else
        print_dec_(i);
}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
//print_dec.h文件内容
void print_dec(int i);
void print_dec_(int i);
   
   
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
//makefile文件内容
TAG=print.out
SRC=main.c print_dec.c print_dec.h
${TAG}:${SRC}
    gcc -o ${TAG} ${SRC}
clean:
    rm -rf *.out
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

程序执行效果: 
这里写图片描述



3.文件访问



#include <stdio.h>
/* cat: concatenate files, version 1 */
main(int argc, char *argv[])
{
	FILE *fp;
	void filecopy(FILE *, FILE *)
		if (argc == 1) /* no args; copy standard input */
			filecopy(stdin, stdout);
		else
			while(--argc > 0)
				if ((fp = fopen(*++argv, "r")) == NULL) {
					printf("cat: can't open %s\n, *argv);
						return 1;
				} else {

					filecopy(fp, stdout);
					fclose(fp);
				}
				return 0;
}
/* filecopy: copy file ifp to file ofp */
void filecopy(FILE *ifp, FILE *ofp)
{
	int c;
	while ((c = getc(ifp)) != EOF)
		putc(c, ofp);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值