如何在c语言中不使用库函数而写出名为myprintf的函数,且功能跟库函数printf一样

如何在c语言中不使用库函数而写出名为myprintf的函数,且功能跟库函数printf一样

要实现一个名为myprintf的函数,功能与标准库函数printf类似,我们需要了解一些C语言的基础知识,包括可变参数列表,格式化字符串,字符数组和指针等。

首先,我们需要定义myprintf函数的格式,它的格式应该与printf函数相似。我们可以使用可变参数列表和格式化字符串来实现。函数原型可以这样定义:

int myprintf(const char *format, ...);


在这个原型中,const char *format 表示格式化字符串,... 表示可变参数列表。

接下来,我们需要在函数体内遍历格式化字符串,以获取要输出的信息,然后根据信息输出相应的数据。

一个简单的实现可能如下所示:

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

int myprintf(const char *format, ...)
{
    va_list args;
    int n;

    va_start(args, format);
    n = vprintf(format, args);
    va_end(args);

    return n;
}


在这个实现中,我们首先定义了一个va_list类型的变量args,用于存储可变参数列表。然后,我们调用va_start宏来初始化args,将其指向可变参数列表的第一个参数。接下来,我们调用标准库函数vprintf,使用格式化字符串和可变参数列表输出数据。最后,我们调用va_end宏来释放可变参数列表。

这个实现是简单的,但它可以支持大部分的格式化字符串。当然,我们可以通过一些技巧来扩展它的功能,比如支持更多的格式化字符串和修改输出的方式等。

注意:这个实现仅用于学习目的,实际的项目中,我们应该使用标准库函数来实现输出功能,因为标准库函数在性能和稳定性方面都有很大的优势。
以下是一个简单的实现示例

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

void myprintf(const char *format, ...) {
    va_list args;
    va_start(args, format);
    
    while (*format != '\0') {
        if (*format == '%') {
            format++;
            switch (*format) {
                case 'c':
                    putchar(va_arg(args, int));
                    break;
                case 's':
                    fputs(va_arg(args, char*), stdout);
                    break;
                case 'd':
                    printf("%d", va_arg(args, int));
                    break;
                case 'f':
                    printf("%f", va_arg(args, double));
                    break;
                default:
                    putchar(*format);
                    break;
            }
        }
        else {
            putchar(*format);
        }
        format++;
    }
    va_end(args);
}


这个实现并不完整,因为它只实现了一部分printf函数的功能,只支持%c, %s, %d, %f这几个格式符,并且没有考虑到精度、宽度等格式化参数。不过,这个示例代码可以帮助你理解如何使用可变参数函数实现类似printf的功能。

你不用printf咋输出呢???即使封装一个myprintf,里面也得用printf啊

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 文章:c语言中的输入输出函数之printf函数 中也许有你想要的答案,请看下吧
  • 除此之外, 这篇博客: c语言 不定参数printf的实现中的 上面函数所调用的函数 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:
    /*
     *  value: 要转换的整数,string: 转换后的字符串,radix: 转换进制数,如2,8,10,16 进制等。
     */
    static char* itoa(int num,char* str,int radix)
    {
    	char index[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//索引表
    	unsigned unum;//存放要转换的整数的绝对值,转换的整数可能是负数
    	int i=0,j,k;//i用来指示设置字符串相应位,转换之后i其实就是字符串的长度;转换后顺序是逆序的,有正负的情况,k用来指示调整顺序的开始位置;j用来指示调整顺序时的交换。
     
    	//获取要转换的整数的绝对值
    	if(radix==10&&num<0)//要转换成十进制数并且是负数
    	{
    		unum=(unsigned)-num;//将num的绝对值赋给unum
    		str[i++]='-';//在字符串最前面设置为'-'号,并且索引加1
    	}
    	else unum=(unsigned)num;//若是num为正,直接赋值给unum
     
    	//转换部分,注意转换后是逆序的
    	do
    	{
    		str[i++]=index[unum%(unsigned)radix];//取unum的最后一位,并设置为str对应位,指示索引加1
    		unum/=radix;//unum去掉最后一位
     
    	}while(unum);//直至unum为0退出循环
     
    	str[i]='\0';//在字符串最后添加'\0'字符,c语言字符串以'\0'结束。
     
    	//将顺序调整过来
    	if(str[0]=='-') k=1;//如果是负数,符号不用调整,从符号后面开始调整
    	else k=0;//不是负数,全部都要调整
     
    	char temp;//临时变量,交换两个值时用到
    	for(j=k;j<=(i-1)/2;j++)//头尾一一对称交换,i其实就是字符串的长度,索引最大值比长度少1
    	{
    		temp=str[j];//头部赋值给临时变量
    		str[j]=str[i-1+k-j];//尾部赋值给头部
    		str[i-1+k-j]=temp;//将临时变量的值(其实就是之前的头部值)赋给尾部
    	}
     
    	return str;//返回转换后的字符串
    }
    
    
    /*
     *  str传入的数组基础地址,offset数组的偏移,c传入的字符
     *  返回填入字符后的偏移值
     */
    static uint8_t load_c(char *str,uint8_t offset ,char c)
    {
    	* (str + offset) = c;
    	offset ++;
    	return offset;
    }
    /*
     *  str传入的数组基础地址,offset数组的偏移,data传入的数字
     *  返回填入字符后的偏移值
     */
    static uint8_t load_data(char *str,uint8_t offset ,uint32_t data)
    {
      char datastr[17] = {0};
    	itoa(data,datastr,10);
    	uint8_t len = strlen(datastr);
    	
    	for(uint8_t i = 0 ; i < len ; i ++)
    	{
    		* (str + offset) = datastr[i];
    		offset ++;
    	}
    	return offset;
    }
    /*
     *  str传入的数组基础地址,offset数组的偏移,data传入的数字
     *  返回填入字符后的偏移值
     *  与load_data不同的是,这个函数会吧数字保留一位小数装填
     */
    static uint8_t load_fdata(char *str,uint8_t offset ,uint32_t data)
    {
      char datastr[17] = {0};
    	itoa(data,datastr,10);
    	uint8_t len = strlen(datastr);
    	if(len == 1)
    	{
    		* (str + offset++) = datastr[0]; 
    		* (str + offset++) = '.';
    		* (str + offset++) = '0';
    	}
    	else if(len > 1)
    	{
    			for(uint8_t i = 0 ; i < len ; i ++)
    			{
    				* (str + offset++) = datastr[i];
    				if( i == (len - 2))
    				 * (str + offset++)  = '.';
    			}
    	
    	}
      return offset;
    }
    
    /*
     *  str传入的数组基础地址,offset数组的偏移,addstr传入的字符串
     *  返回填入字符后的偏移值
     */
    static uint8_t load_string(char *str,uint8_t offset ,char *addstr)
    {
    	uint8_t len = strlen(addstr);
    	for(uint8_t i = 0 ; i < len ; i ++)
    	{
    		* (str + offset) = addstr[i];
    		offset ++;
    	}
    	return offset;
    	
    }
    

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^