如何用putchar函数改写vsprintf函数?

C语言顺序程序设计详解(scanf,printf,getchar,putchar等函数)
一、C语言语句概述:
C语句分为以下五类:
&1&:表达式语句-&表达式语句由表达式加上分号&;&组成。
&2&:函数调用语句-&由函数名、实际参数加上分号&;&组成。
&3&:控制语句-&
条件判断语句:if语句、switch语句;
循环执行语句:do while语句、while语句、for语句;
转向语句:break语句、goto语句、continue语句、return语句。
&4&:复合语句:把多个语句用括号{}括起来组成的一个语句称复合语句
例如:{ x=y+z;
&&&&& a=b+c;
&&&&& printf(&%d%d&,x,a);
&5&:空语句:只有分号&;&组成的语句称为空语句。空语句是什么也不执行的语句。在程序中空语句可用来作空循环体。例如:while(getchar()!='\n');
1、C语言赋值语句详解:
变量=(变量=表达式)
a=b=c=d=e=10&
按照赋值运算符的右结合性,因此实际上等效于:
2、putchar 函数(字符输出函数)
&&&&& putchar 函数是字符输出函数,其功能是在显示器上输出单个字符。
&&&& 其一般形式为:
&&&& putchar(字符变量)
3、getchar函数(键盘输入函数)
&&&&&& getchar函数的功能是从键盘上输入一个字符。
&&&&& 其一般形式为:
&&&&&&& getchar();
&&&&&& 通常把输入的字符赋予一个字符变量,构成赋值语句,如:
&&&&&&& c=getchar();
4、C语言格式输出函数printf()详解
&&&&&& printf函数是一个标准库函数,它的函数原型在头文件&stdio.h&中。但作为一个特例,不要求在使用 printf 函数之前必须包含stdio.h文件。printf函数调用的一般形式为:
&&& printf(&格式控制字符串&,输出表列)
格式字符串
在Turbo C中格式字符串的一般形式为: [标志][输出最小宽度][.精度][长度]类型。其中方括号[]中的项为可选项。
各项的意义介绍如下:
类型:类型字符用以表示输出数据的类型,其格式符和意义如下表所示:
格式字符& 意&&&&&&&&&&& 义
d& 以十进制形式输出带符号整数(正数不输出符号)
o& 以八进制形式输出无符号整数(不输出前缀0)
x,X& 以十六进制形式输出无符号整数(不输出前缀Ox)
u& 以十进制形式输出无符号整数
f& 以小数形式输出单、双精度实数
e,E& 以指数形式输出单、双精度实数
g,G& 以%f或%e中较短的输出宽度输出单、双精度实数
c& 输出单个字符
s& 输出字符串
标志:标志字符为-、+、#、空格四种,其意义下表所示:
标 志& 意&&&&&&&& 义
-& 结果左对齐,右边填空格
+& 输出符号(正号或负号)
空格& 输出值为正时冠以空格,为负时冠以负号
#& 对c,s,d,u类无影响;对o类,在输出时加前缀o;对x类,在输出时加前缀0x;对e,g,f 类当结果有小数时才给出小数点
5、C语言格式输入函数scanf()详解
&&&&& scanf(&格式控制字符串&,地址表列);
&&&& 其中,格式控制字符串的作用与printf函数相同,但不能显示非格式字符串,也就是不能显示提示字符串。地址表列中给出各变量的地址。地址是由地址运算符&&&后跟变量名组成的。
scanf(&%d%d%d&,&a,&b,&c);&
格式字符串的一般形式为:%[*][输入数据宽度][长度]类型
其中有方括号[]的项为任选项。各项的意义如下:
类型:表示输入数据的类型,其格式符和意义如下表所示。
格式& 字符意义
d& 输入十进制整数
o& 输入八进制整数
x& 输入十六进制整数
u& 输入无符号十进制整数
f或e& 输入实型数(用小数形式或指数形式)
c& 输入单个字符
s& 输入字符串
&*&符:用以表示该输入项,读入后不赋予相应的变量,即跳过该输入值。如:scanf(&%d %*d %d&,&a,&b);。当输入为:1&& 2&& 3时,把1赋予a,2被跳过,3赋予b。
宽度:用十进制整数指定输入的宽度(即字符数)。
&&&&&& scanf(&%5d&,&a);
输入只把12345赋予变量a,其余部分被截去。
&&&&&&& scanf(&%4d%4d&,&a,&b);
输入将把1234赋予a,而把5678赋予b。
长度:长度格式符为l和h,l表示输入长整型数据(如%ld) 和双精度浮点数(如%lf)。h表示输入短整型数据。
使用scanf函数还必须注意以下几点:
scanf函数中没有精度控制,如:scanf(&%5.2f&,&a);是非法的。不能企图用此语句输入小数为2位的实数。
scanf中要求给出变量地址,如给出变量名则会出错。如 scanf(&%d&,a);是非法的,应改为scnaf(&%d&,&a);才是合法的。
在输入多个数值数据时,若格式控制串中没有非格式字符作输入数据之间的间隔则可用空格,TAB或回车作间隔。C编译在碰到空格,TAB,回车或非法数据(如对&%d&输入&12A&时,A即为非法数据)时即认为该数据结束。
在输入字符数据时,若格式控制串中无非格式字符,则认为所有输入的字符均为有效字符。
&&&&&&&&&&&&& scanf(&%c%c%c&,&a,&b,&c);
输入 d&& e&& f 则把'd'赋予a, ' ' 赋予b,'e'赋予c。只有当输入为 def 时,才能把'd'赋于a,'e'赋予b,'f'赋予c。
如果在格式控制中加入空格作为间隔,如:
scanf (&%c %c %c&,&a,&b,&c);
则输入时各数据之间可加空格。
作者:grassroots2011
您对本文章有什么意见或着疑问吗?请到您的关注和建议是我们前行的参考和动力&&
您的浏览器不支持嵌入式框架,或者当前配置为不显示嵌入式框架。C语言模拟试题题库
本试题来自:(2010年C语言模拟试题,)一、选择题以下叙述中正确的是______。
A) 调用printf函数时,必须要有输出项
B) 使用putchar函数时,必须在之前包含头文件stdio.h
c)在C语言中,整数可以以十二进制、八进制或十六进制的形式输出
D) 调用getchar函数读入字符时,可以从键盘上输入字符所对应的ASCⅡ码正确答案:有, 或者 答案解析:有,
您可能感兴趣的试题
单项选择题:()下列程序的输出结果是(
)。#include<stdio.h>int fun(int x){
if(x==0||x=1)
return 3;
a=x-fun(x-2);
return a;}void main(){
printf("%d",fun(7));}A.2B.8C.9D.5答案:有,答案解析:有,单项选择题:()已知i、j、k为int型变量,若要从键盘输入2、3、4<CR>,使I、j、k的值分别为2、3、4,下列正确的输入语句是(
)。A.scanf("%3d,%3d,%3d",&i,&j,&;B.scanf("%d,%d,%d",&i,&j,&;C.scanf("%d%d%d",&i,&j,&;D.seanf("i=%d,j=%d,k=%d",&i,&j,&;答案:有,答案解析:有,
C语言模拟试题最新试卷
C语言模拟试题热门试卷不使用man 3 printf的函数,实现一个简单的printf函数_Linux编程_Linux公社-Linux系统门户网站
你好,游客
不使用man 3 printf的函数,实现一个简单的printf函数
来源:Linux社区&
作者:wxyztuv
题目:不使用man printf中的函数,实现一个简易的输出函数myprintf。
函数声明:int myprintf(const char *format,...);
要求该函数可以识别(只需要识别)出format字符串中的%ld,%lf,%c,%s这四个转义字符,并转化成相应的参数。
说明:man printf中的函数即:printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, vsnprintf
实现代码:
#include&&stdio.h& &&
#include&&stdarg.h& &&
#include&&stdlib.h& &&
int&PrintStr(const&char&*format)&&
&&&&const&char&*pos&=&&&
&&&&int&len&=&0;&&
&&&&while(&*pos&)&&
&&&&&&&&putchar(&(int)*(pos++)&);&&
&&&&&&&&len++;&&
&&&&return&&&
int&MyPrintf(const&char&*format,&...)&&
&&&&const&char&*pos&=&&&
&&&&int&len,&&&
&&&&len&=&0;&&
&&&&va_list&&&
&&&&va_start(vlist,&format);&&
&&&&while(&*pos&)&&
&&&&&&&&char&ch&=&*&&
&&&&&&&&if(&ch&!=&'%'&)&&
&&&&&&&&{&&
&&&&&&&&&&&&putchar(&ch&);&&
&&&&&&&&&&&&sublen&=&1;&&
&&&&&&&&&&&&pos++;&&
&&&&&&&&}&&
&&&&&&&&&&
&&&&&&&&else&&
&&&&&&&&{&&
&&&&&&&&&&&&char&nch&=&*(pos+1);&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&if(&'c'&==&nch&)&&
&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&char&tch&=&va_arg(vlist,&char);&&
&&&&&&&&&&&&&&&&putchar(tch);&&
&&&&&&&&&&&&&&&&pos&+=&2;&&
&&&&&&&&&&&&&&&&sublen&=&1;&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&else&if(&'s'&==&nch&)&&
&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&char&*tstr&=&va_arg(vlist,&char*);&&
&&&&&&&&&&&&&&&&sublen&=&PrintStr(tstr);&&
&&&&&&&&&&&&&&&&pos&+=&2;&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&else&if(&'l'&==&nch&)&&
&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&char&nnch&=&*(pos&+&2);&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&if(&'d'&==&nnch&)&&
&&&&&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&&&&&long&tnum&=&va_arg(vlist,&long);&&
&&&&&&&&&&&&&&&&&&&&char&tstr[21];&&
&&&&&&&&&&&&&&&&&&&&_ltoa(tnum,&tstr,&10);&&
&&&&&&&&&&&&&&&&&&&&sublen&=&PrintStr(tstr);&&
&&&&&&&&&&&&&&&&&&&&pos&+=&3;&&
&&&&&&&&&&&&&&&&}&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&else&if(&'f'&==&nnch&)&&
&&&&&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&&&&&double&tnum&=&va_arg(vlist,&double);&&
&&&&&&&&&&&&&&&&&&&&char&tstr[101];&&
&&&&&&&&&&&&&&&&&&&&gcvt(tnum,&10,&tstr);&&
&&&&&&&&&&&&&&&&&&&&sublen&=&PrintStr(tstr);&&
&&&&&&&&&&&&&&&&&&&&pos&+=&3;&&
&&&&&&&&&&&&&&&&}&&
&&&&&&&&&&&&&&&&else&&
&&&&&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&&&&&putchar('l');&&
&&&&&&&&&&&&&&&&&&&&putchar(nnch);&&
&&&&&&&&&&&&&&&&&&&&pos&+=&3;&&
&&&&&&&&&&&&&&&&}&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&else&if(&'%'&==&nch&)&&
&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&putchar('%');&&
&&&&&&&&&&&&&&&&pos&+=&2;&&
&&&&&&&&&&&&&&&&sublen&=&1;&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&else&&
&&&&&&&&&&&&{&&
&&&&&&&&&&&&&&&&pos++;&&
&&&&&&&&&&&&&&&&sublen&=&0;&&
&&&&&&&&&&&&}&&
&&&&&&&&}&&
&&&&&&&&&&
&&&&&&&&len&+=&&&
&&&&va_end(vlist);&&
&&&&return&&&
int&main()&&
&&&&int&rr&=&MyPrintf("%ld,&%lf,&%c,&%s\n",&&&
&&&&&&&&456,&43.34,&'A',&"hello,&world");&&
&&&&printf("%d\n",&rr);&&
&&&&return&0;&&
如果大家发现我这个程序的BUG的话,欢迎提出,大家共同学习。
相关资讯 & & &
& (05月27日)
& (05月15日)
& (05月27日)
& (05月22日)
& (05月15日)
图片资讯 & & &
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款5835人阅读
& & &今天就简单来说说怎么在51单片机中使用&printf&函数:包括使用自带的printf函数和自己动手写一个printf函数,再贴代码之前先介绍几个相关的知识,主要用于自己写printf函数。
①C语言函数:vsprintf,
其原型为int vsprintf(char *string, char *format, va_list param);,作用为将param按格式format写入字符串string中,因此他可以用于将任何格式数据转化为字符串数据,比如把整数97转化为ASCII码的97的程序就像下面这样vsprintf(string,&%d&,97),当然还有一点需要注意:在keil里面使用sprintf需要包含stdio.h这个头文件(当然这里也可以使用sprintf,作用完全差不多,只需要稍加修改即可,不多介绍)。说到这里,再来说说另一个函数itoa吧,其实他比vsprintf更简单,其原型为char
*itoa(int value, char *string, int radix),作用为将value按radix进制写入到string字符串中,使用时需要包含头文件stdlib.h,可是在keil里面却无法使用,头文件里面不包含itoa,即使把VC里面的复制进来貌似还是不行,呵呵,目前不知道原因。
②可变参数函数
具体来说就是stdarg.h里面的这几个函数va_start,va_arg,va_list,va_end,这几个参数用于开辟一段内存区域,可以配合vsprintf使用,但是对内存使用较大,需要单片机具备一定的RAM,否则程序就算能编译通过也是无法运行的,用法见这里
③内部拓展RAM
定义:集成在单片机内部的数据存储器,在物理上是内部,但逻辑上是外部,访问时需要使用MOVX或者xdata访问,具体可以看STC8051手册,如下所示
从这里可以看出,STC12C5A60S2单片机内部含有1024byte=1Kbyte的内部拓展RAM,在访问的时候,使用C语言的时候,需要加上xdata才可以访问,使用汇编的时候需要用MOVX指令访问。
到这里我们先来算一算STC12C5A60S2单片机在不接外部RAM的情况下总的RAM大小,先看一下内部的RAM分布图
:内部RAM(256byte)包括三部分:低128byte,高128byte和特殊功能寄存器区,特别注意和51不同,他的特殊功能寄存器和高128byte地址重叠,但是物理上是分开的,所有内部可用的RAM有256byte,所以到此为止可以得到内部RAM大小总共有:256byte+1024byte=1280byte
说了这么多,下面不多说,直接上程序
《一》直接使用系统自带的printf函数:特别注意需要置位TI=1,否则是无法发送的,程序如下:
//此程序主要用于uart发送(proteus终端不能显示汉字,但串口助手可以),输入换行符\n换行
#include&reg52.h&
//stdio.h,string.h用于printf函数原型
#include&stdio.h&
void delay(unsigned int z);
void uart_init(void);//串行口初始化
int main(void)
char *string=&abde&;
uart_init();
printf(&%d
%p\n&,a,a,(char)a,string,string);
delay(1000);
void uart_init(void)
TMOD=0x20;//即,定时器/计数器1,工作方式2
TH1=0//设置波特率为9600
TR1=1;//启动定时器/计数器1
SCON=0x50; //.串口工作方式1,允许串行控制
PCON=0x00;//设置SMOD=0
IE=0x90; //CPU允许中断,串行允许中断
TI=1;//直接使用printf必须加入此句才能实现发送
void delay(unsigned int z)
unsigned int x,y;
for(x=z;x&0;x--)
for(y=110;y&0;y--);
《二》自己动手写一个类似printf的函数:uart_printf
但是这种情况占用RAM较多,因为需要开辟大数组,所以需要使用拓展型的51单片机,普通的AT89C51和STC89C52之类的会造成内存不够用、堆栈溢出等等问题,所以以下程序都是基于STC12C5A60S2的,因为它含有内部拓展的1024byte的RAM,可以用来存储大数组
//此程序主要用于uart发送(proteus不能仿真,但实际是可以运行的),输入换行符\n换行
#include&reg52.h&
//stdio.h,stdarg.h用于vsprintf函数原型
#include&stdio.h&
#include&stdarg.h&
void delay(unsigned int z);
void uart_init(void);//串行口初始化
void sendbyte(unsigned char c);
void sendstring(unsigned char *string);
void uart_printf(const char *fmt,...);
int main(void)
uart_init();
uart_printf(&10进制:%d
字符格式:%c\n&,a,a,a);
delay(1000);
void uart_init(void)
TMOD=0x20;//即,定时器/计数器1,工作方式2
TH1=0xf3;//设置波特率为2400
TR1=1;//启动定时器/计数器1
SCON=0x50; //.串口工作方式1,允许串行控制
PCON=0x00;//设置SMOD=0
IE=0x00; //由于是查询方式,故需要禁止中断,CPU不允许中断,串行不允许中断
void delay(unsigned int z)
unsigned int x,y;
for(x=z;x&0;x--)
for(y=110;y&0;y--);
void sendbyte(unsigned char c)
if(c=='\n')//如果遇到\n就换行
//发送CR(carriage return)
SBUF=0x0D;
while(!TI);//等待发送完成
//发送 LF(NL line feed,new line)
SBUF=0x0A;
while(!TI);//等待发送完成
while(!TI);//等待发送完成
void sendstring(unsigned char *string)//此处*string相当于数组
while(*string!='\0')//判断是否到字符串末尾
sendbyte(*string);
void uart_printf(const char *fmt,...)
char xdata string[1024];//访问内部拓展RAM,非访问外部RAM,不能超过内部拓展RAM大小(此处为1024)
va_start(ap,fmt);
vsprintf(string,fmt,ap);//此处也可以使用sprintf函数,用法差不多,稍加修改即可,此处略去
sendstring(string);
va_end(ap);
最后简单总结 :其中第一种方法用于中断方式工作会有问题,因为其底层是调用putchar函数实现的,工作方式为中断,但是比较简单,可以通过proteus仿真;第二种方法更完善,不过程序比较复杂,不能使用proteus仿真,但实际是可以工作的。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:39224次
排名:千里之外
原创:12篇
转载:32篇
评论:25条
(2)(5)(1)(2)(1)(1)(3)(6)(4)(1)(2)(1)(5)(2)(3)(3)(2)

我要回帖

更多关于 vsnprintf函数 的文章

 

随机推荐