【C语言】之实现 printf 函数功能

/***********************************************
 * 文件名: myPrintf.c
 * 文件功能: 使用putchar函数模拟printf函数的功能
 * 编辑人: 王廷云
 * 编辑时间: 2017-10-14
 * 修改时间: 2018-1-12
************************************************/

#include <stdio.h>
#include <stdarg.h>

/* 功能函数声明 */
void myPrintf(char *s, ...);				// 需要实现的目标函数
void printNum(unsigned long num, int base); // 通用数字打印函数 
void printDeci(int dec);					// 打印十进制数
void printOct(unsigned oct);				// 打印八进制数
void printHex(unsigned hex);				// 打印十六进制数
void printAddr(unsigned long addr);			// 打印地址
void printStr(char *str);					// 打印字符串
void printFloat(double f);					// 打印浮点数

/*
 * 程序从主函数开始
 * 思路:
 * 	->实现功能类似于printf函数的myPrintf函数
 * 	->支持字符,字符串,十进制整数,八进制整数,
 * 	  十六进制整数,浮点数,地址的打印
*/
int main(int argc, char **argv)
{
	/* 用于测试的变量 */
    unsigned int a = 255;			// 整数
    float f = 10.000;				// 浮点数
    char c = 'z';					// 字符
    char *s = "this is a string";	// 字符串
    int *p = &a;					// 地址

	/* 这是printf函数的结果 */
    printf("printf   >>> 十进制:%d 八进制:%o 十六进制:%x\n", a, a, a);
	printf("printf   >>> 字符:'%c' 字符串:%s 浮点数:%f\n", c, s, f);
	printf("printf   >>> 地址:%p\n\n", p);

    /* 这是myPrintf函数的结果 */
    printf("myPrintf >>> 十进制:%d 八进制:%o 十六进制:%x\n", a, a, a);
	printf("myPrintf >>> 字符:'%c' 字符串:%s 浮点数:%f\n", c, s, f);
	printf("myPrintf >>> 地址:%p\n", p);

    return 0;
}

/*
 * 函数名: myPrintf
 * 函数功能: 打印格式字符串
 * 参数: 1. 包含格式符的字符串地址 2.可变参
 * 返回值: 无
*/
void myPrintf(char *s, ...)
{
    int i = 0;

	/* 可变参第一步 */
    va_list va_ptr;

	/* 可变参第二部 */
    va_start(va_ptr, s);

	/* 循环打印所有格式字符串 */
    while (s[i] != '\0')
    {
		/* 普通字符正常打印 */
		if (s[i] != '%')
		{
    	    putchar(s[i++]);
			continue;
		}
		
		/* 格式字符特殊处理 */
		switch (s[++i])   // i先++是为了取'%'后面的格式字符
		{
		    /* 根据格式字符的不同来调用不同的函数 */
			case 'd': printDeci(va_arg(va_ptr,int));           
			  		  break; 
		    case 'o': printOct(va_arg(va_ptr,unsigned int));  
			  		  break;
		    case 'x': printHex(va_arg(va_ptr,unsigned int));  
			  		  break;
		    case 'c': putchar(va_arg(va_ptr,int));            
			  		  break;
		    case 'p': printAddr(va_arg(va_ptr,unsigned long));
			  		  break;
		    case 'f': printFloat(va_arg(va_ptr,double));      
			  		  break;
		    case 's': printStr(va_arg(va_ptr,char *));
					  break;
			default : break;
		}

		i++; // 下一个字符
    }

	/* 可变参最后一步 */
    va_end(va_ptr);
}

/*
 * 函数名: printNum()
 * 函数功能: 通用数字打印函数可以把整型值打印成
 *           10进制数,8进制数,2进制数,16进制数
 * 参数: 1.需要打印的整数,无符号长整型是为了兼容
 *         地址格式打印; 2.打印的进制
 *  返回值: 无
*/
void printNum(unsigned long num, int base)
{
    /* 递归结束条件 */
	if (num == 0)
    {
        return;
    }
    
    /* 继续递归 */
	printNum(num/base, base);

	/* 逆序打印结果 */
    putchar("0123456789abcdef"[num%base]);
}


/*
 * 函数名: printDeci
 * 函数功能: 打印十进制数
 * 参数: 十进制整数
 * 返回值: 无
*/
void printDeci(int dec)
{
    int num;

    /* 处理有符号整数为负数时的情况 */
	if (dec < 0)
    {
        putchar('-');
		dec = -dec;  	   // 该操作存在溢出风险:最小的负数没有对应的正数
    }

    /* 处理整数为时0的情况 */
    if (dec == 0)
    {
        putchar('0');
		return;
    }
    else
    {
        printNum(dec, 10); // 打印十进制数
    }
}

/*
 * 函数名: printOct
 * 函数功能: 打印八进制整数
 * 参数: 无符号整数
 * 返回值: 无
*/
void printOct(unsigned oct)
{
    if (oct == 0)			// 处理整数为0的情况
    {
		putchar('0');
		return;
    }
    else
    {
        printNum(oct,8);	// 打印8进制数
    }
}

/*
 * 函数名: printHex
 * 函数功能: 打印十六进制整数
 * 参数: 无符号整数
 * 返回值: 无
*/
void printHex(unsigned hex)
{
    if (hex == 0)			// 处理整数为0的情况
    {
        putchar('0');
		return;
    }
    else
    {
        printNum(hex,16);	// 打印十六进制数
    }
}

/*
 * 函数名: printAddr
 * 函数功能: 打印地址
 * 参数: 待打印的地址
 * 返回值: 无
*/
void printAddr(unsigned long addr)
{
    /* 打印前导"0x" */
	putchar('0');
    putchar('x');

	/* 打印地址:格式和十六进制一样 */
    printNum(addr, 16);
}

/*
 * 函数名: printStr
 * 函数功能: 打印字符串
 * 参数: 字符串地址
 * 返回值: 无
*/
void printStr(char *str)
{
    int i = 0;

    while (str[i] != '\0')
    {
        putchar(str[i++]);
    }
}

/*
 * 函数名: printFloat
 * 函数功能: 打印浮点数
 * 参数: 待打印浮点数
 * 返回值: 无
*/
void printFloat(double f)
{
    int temp;

	/* 先打印整数部分 */
    temp = (int)f;
    printNum(temp,10);
	
	/* 分隔点 */
    putchar('.');

	/* 打印小数部分 */
    f -= temp;
    if (f == 0)
    {
		/* 浮点型数据至少六位精度 */
		for (temp = 0; temp < 6; temp++)
		{
		    putchar('0');
		}
		return;
    }
    else
    {
        temp = (int)(f*1000000);
        printNum(temp,10);
    }
}
  • 12
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值