手写简化版printf函数

2019.02.01更新:经同学提醒,myprintf函数应有返回值为输出的字符数。

 

期末的大作业,手写一个myprintf函数,支持如下一些操作。

 

也就是  % -(负号控制左右对齐) 数(控制字段宽). 数(控制精度) ?(字符,控制类型) 

 

我实现的话就是按上面的实现的,说一下这个简化版存在的问题(简化的地方):

1)%d %i %o %x %X %u %c 这些都默认后面输入的是int,所以long long其实没有用。

2)支持最大精度<=30,如果有需要请更改PRECISION

 

myprintf默认四舍五入(rounding_off函数实现)

 

如果发现错误,请指出,谢谢大家啦!

 

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<math.h>
  5 #include<stdarg.h>
  6 
  7 #define N 110
  8 #define eps 1e-16
  9 #define INF 1e9
 10 #define PRECISION 30
 11 
 12 int maxx(int x,int y){return x>y ? x:y;}
 13 void swapp(char *x,char *y){char t;t=*x;*x=*y;*y=t;}
 14 int find_int_type(int int_type,char ch);
 15 void change_int_type_to_char(int x,int int_type,char *s,int *sl,int *minus);
 16 void print_int_regardless_type(char *s,int *sl,int minus,int Justify_type,int min_width,int precision);
 17 void print_int(int x,int Justify_type,int min_width,int precision,int int_type);
 18 void print_string(char *s,int Justify_type,int min_width,int precision);
 19 int is_g_or_G(char double_type){return (double_type == 'g' || double_type=='G');}
 20 void rounding_off(char *s,int *sl,int *ml,int precision);
 21 void print_double_e_or_E(char *s,int sl,int exponent,int minus,int Justify_type,int min_width,int precision,char double_type);
 22 void print_double_f(char *s,int sl,int ml,int minus,int Justify_type,int min_width,int precision);
 23 void print_double(double x,int Justify_type,int min_width,int precision,char double_type);
 24 int myprintf(const char *format,...);
 25 
 26 
 27 int main()
 28 {
 29     // freopen("a.out","w",stdout);
 30     int a=123;
 31     double b=9.9734567;
 32     int count=123456789;
 33     myprintf("%\n");
 34     myprintf("%15e%15e\n",-0.0000123,123.123);printf("%15e%15e\n",-0.0000123,123.123);
 35     myprintf("%f\n",0.0000123);printf("%f\n",0.0000123);
 36     myprintf("%.1E\n",b);printf("%.1E\n",b);
 37     myprintf("%e\n",0.0000123);printf("%e\n",0.0000123);
 38     myprintf("%15.8g\n",0.000012346789);printf("%15.8g\n",0.0000123456789);
 39     myprintf("%5d%10d\n",a,a);printf("%5d%10d\n",a,a);
 40     myprintf("%10.5d%10.5d\n",a,a);printf("%10.5d%10.5d\n",a,a);
 41     myprintf("%15.10hd%15.10ld\n",count,count);printf("%15.10hd%15.10ld\n",count,count);
 42     myprintf("%5o\n",a);printf("%5o\n",a);
 43     myprintf("%f\n",b);printf("%f\n",b);
 44     myprintf("%15f%20.10f\n",-b,-b);printf("%15f%20.10f\n",-b,-b);
 45     myprintf("%15g\n",0.0000123);printf("%15g\n",0.0000123);
 46     myprintf("%15e%15E%15g%15g\n",-b,b,b,0.0000123);printf("%15e%15E%15g%15g\n",-b,b,b,0.0000123);
 47     myprintf("%15g\n",0.0000123);printf("%15g\n",0.0000123);
 48     myprintf("%-15.10x%10.10X\n",count);printf("%-15.10x%10.10X\n",count);
 49     myprintf("%10.5s\n%c\n","asdfghjkl",'a');printf("%10.5s\n%c\n","asdfghjkl",'a');
 50     myprintf("\x41\101 \\ \r\n");printf("\x41\101 \\ \r\n");
 51     unsigned int d = 123456;
 52     myprintf("%.10u\n",d);printf("%.10u\n",d);
 53     int *p;
 54     myprintf("%p\n",p);printf("%p\n",p);
 55     return 0;
 56 }
 57 
 58 int find_int_type(int int_type,char ch)
 59 {
 60     if(ch=='d' || ch=='i') return int_type;
 61     if(ch=='o') return 6;
 62     if(ch=='x') return 7;
 63     if(ch=='X') return 8;
 64     if(ch=='u') return int_type+1;
 65 }
 66 
 67 void change_int_type_to_char(int x,int int_type,char *s,int *sl,int *minus)
 68 {
 69     *sl=0;
 70     switch(int_type)
 71     {
 72         case 0:{//int
 73             int y=(int)x;if(y<0) *minus=1,y=-y;
 74             while(y) s[(*sl)++]=(y%10)+'0',y/=10;
 75             break;
 76         }
 77         case 1:{//unsigned int
 78             unsigned int y=(unsigned int)x;
 79             while(y) s[(*sl)++]=(y%10)+'0',y/=10;
 80             break;
 81         }
 82         case 2:{//short
 83             short int y=(short int)x;if(y<0) *minus=1,y=-y;
 84             while(y) s[(*sl)++]=(y%10)+'0',y/=10;
 85             break;
 86         }
 87         case 3:{//unsigned short
 88             unsigned short int y=(unsigned short int)x;
 89             while(y) s[(*sl)++]=(y%10)+'0',y/=10;
 90             break;
 91         }
 92         case 4:{//long int
 93             long int y=(long int )x;if(y<0) *minus=1,y=-y;
 94             while(y) s[(*sl)++]=(y%10)+'0',y/=10;
 95             break;
 96         }
 97         case 5:{//unsigned long int
 98             unsigned long int y=(unsigned long int)y;
 99             while(y) s[(*sl)++]=(y%10)+'0',y/=10;
100             break;
101         }
102         case 6:{//o
103             int y=(int )x;
104             while(y) s[(*sl)++]=(y%8)+'0',y/=8;
105             break;
106         }
107         case 7:{//x
108             int y=(int)x;
109             while(y) s[(*sl)++]=((y%16)>=10) ? (y%16)-10+'a' : (y%16)+'0',y/=16;
110             break;
111         }
112         case 8:{//X
113             int y=(int)x;
114             while(y) s[(*sl)++]=((y%16)>=10) ? (y%16)-10+'A' : (y%16)+'0',y/=16;
115             break;
116         }
117     }
118 }
119 
120 void print_int_regardless_type(char *s,int *sl,int minus,int Justify_type,int min_width,int precision)
121 {
122     while(precision<INF && *sl<precision) s[(*sl)++]='0';
123     if(minus) s[(*sl)++]='-';
124     int space=min_width-*sl;
125 
126     if(Justify_type==1)//right
127         for(int i=1;i<=space;i++) putchar(' ');
128     for(int i=(*sl)-1;i>=0;i--) putchar(s[i]);
129     if(Justify_type==0)//left
130         for(int i=1;i<=space;i++) putchar(' ');
131 }
132 
133 void print_int(int x,int Justify_type,int min_width,int precision,int int_type)
134 {
135     int minus=(x<0) ? 1:0;
136     char *s=(char *)malloc(N*sizeof(char));
137     int *sl=(int *)malloc(sizeof(int));
138     change_int_type_to_char(x,int_type,s,sl,&minus);
139     print_int_regardless_type(s,sl,minus,Justify_type,min_width,precision);
140     free(s);
141     free(sl);
142 }
143 
144 void print_string(char *s,int Justify_type,int min_width,int precision)
145 {
146     int sl=strlen(s);
147     if(sl > precision) sl=precision;
148     int space=min_width-sl;
149 
150     if(Justify_type==1)//right
151         for(int i=1;i<=space;i++) putchar(' ');
152     for(int i=0;i<sl;i++) putchar(s[i]);
153     if(Justify_type==0)//left
154         for(int i=1;i<=space;i++) putchar(' ');
155 }
156 
157 void rounding_off(char *s,int *sl,int *ml,int precision)//四舍五入
158 {
159     if(s[(*ml)+precision]<='4') return;
160     s[(*ml)+precision-1]++;
161     for(int i=(*ml)+precision-1;i>=1;i--) s[i-1]+=(s[i]-'0')/10,s[i]=(s[i]-'0')%10+'0';
162     if(s[0]>'9')
163     {
164         (*sl)++;(*ml)++;
165         for(int i=(*ml)+precision;i>=1;i--) s[i]=s[i-1];
166         s[0]=(s[1]-'0')/10+'0';
167         s[1]=(s[1]-'0')%10+'0';
168     }
169 }
170 
171 void print_double_e_or_E(char *s,int sl,int exponent,int minus,int Justify_type,int min_width,int precision,char double_type)
172 {
173     int space=min_width-(minus+1+precision+1+1+3);
174     if(precision) space--;//'.'
175 
176     if(Justify_type==1)//right
177         for(int i=1;i<=space;i++) putchar(' ');
178     if(minus) putchar('-');
179     putchar(s[0]);
180     if(precision) putchar('.');
181     for(int i=1;i<=precision;i++) 
182     {
183         if(i>=sl && is_g_or_G(double_type)) break;
184         putchar((i<sl) ? s[i] : '0');
185     }
186     putchar(is_g_or_G(double_type) ? double_type+'e'-'g' : double_type);
187     if(exponent>=0) putchar('+');
188     else putchar('-'),exponent*=-1;
189     putchar(exponent/100+'0');putchar((exponent/10)%10+'0');putchar(exponent%10+'0');
190     if(Justify_type==0)//left
191         for(int i=1;i<=space;i++) putchar(' ');
192 }
193 
194 void print_double_f(char *s,int sl,int ml,int minus,int Justify_type,int min_width,int precision)
195 {
196     int space=min_width-(minus+ml+precision);
197     if(precision) space--;//'.'
198     if(Justify_type==1)//right
199          for(int i=1;i<=space;i++) putchar(' ');
200     if(minus) putchar('-');
201     for(int i=0;i<ml;i++) putchar(s[i]);
202     if(precision) putchar('.'); 
203     for(int i=ml;i<=ml-1+precision;i++) putchar((i<sl) ? s[i]:'0');
204     if(Justify_type==0)//left
205         for(int i=1;i<=space;i++) putchar(' ');
206 }
207 
208 //m.ddddd
209 void print_double(double x,int Justify_type,int min_width,int precision,char double_type)
210 {
211     if(precision==INF) precision=6;
212     int zero=(fabs(x) < eps);
213     int minus=(x<0) ? 1:0;x=fabs(x);
214     char *s=(char *)malloc(N*sizeof(char));
215     int sl=0,ml=0,y=(int)x;x-=y;
216     if(y==0) s[sl++]='0';
217     while(y) s[sl++]=y%10+'0',y/=10;
218     for(int i=0;i<=(sl-1)/2;i++) swapp(&s[i],&s[sl-1-i]);
219     ml=sl;
220     while(sl<=ml+PRECISION) s[sl++]=(int)(x*10)+'0',x=x*10-(int)(x*10);
221     //f
222     if(double_type=='f')
223     {
224         rounding_off(s,&sl,&ml,precision);
225         print_double_f(s,sl,ml,minus,Justify_type,min_width,precision);
226     }
227     else//e E g G
228     {
229         int st=0,ssl=0,exponent=ml-1;
230         char *ss=(char *)malloc(N*sizeof(char));
231         while(!zero && s[st]=='0') st++,exponent--,s[sl++]='0';
232         for(int i=st;i<sl;i++) ss[ssl++]=s[i];
233 
234         if(double_type=='e' || double_type=='E' || 
235           (is_g_or_G(double_type) && (exponent < -4 || exponent >=precision)))
236         {
237             ml=1;
238             if(is_g_or_G(double_type)) 
239             {
240                 if(precision) precision--,ssl--;
241                 while(precision && ss[ml+precision-1]=='0') precision--;
242             }
243             int mml=1;
244             rounding_off(ss,&ssl,&mml,precision);
245             if(mml==2) exponent++;
246             print_double_e_or_E(ss,ssl,exponent,minus,Justify_type,min_width,precision,double_type);
247         }
248         else
249         {
250             precision-=ml;sl-=ml;
251             rounding_off(s,&sl,&ml,precision);
252             while(precision && s[ml+precision-1]=='0') precision--;
253             print_double_f(s,sl,ml,minus,Justify_type,min_width,precision);
254         }
255         free(ss);
256     }
257     free(s);
258 }
259 
260 int myprintf(const char *format,...)
261 {
262     char ch;
263     int arg_int;
264     double arg_double;
265     char *arg_str;
266     void *arg_p;
267     va_list ap;
268     va_start(ap,format);
269     
270     while((ch = *format++)!='\0')
271     {
272         if(ch!='%') {putchar(ch);continue;}
273         //ch = '%'  *format = '\0' 
274         if(*format=='\0' || *format=='%') {putchar('%');continue;}
275 
276         int Justify_type=1,min_width=0,precision=INF,int_type=0,ok=0;
277         if(*format=='-') Justify_type=0,format++;
278         while(*format>='0' && *format<='9') min_width=min_width*10+*format-'0',format++;
279         if(*format=='.')
280         {
281             format++;precision=0;
282             while(*format>='0' && *format<='9') precision=precision*10+*format-'0',format++;
283         }
284         if(*format=='h') int_type=2,format++;
285         if(*format=='l') int_type=4,format++;
286         
287         if(*format=='d' || *format=='i' || *format=='o' || *format=='x' || *format=='X' || *format=='u')
288         {
289             ok=1;arg_int=va_arg(ap,int);
290             print_int(arg_int,Justify_type,min_width,precision,find_int_type(int_type,*format));
291         }
292         if(*format=='c')
293         {
294             ok=1;arg_int=va_arg(ap,int);
295             putchar(arg_int);
296         }
297         if(*format=='s')
298         {
299             ok=1;arg_str=va_arg(ap,char *);
300             print_string(arg_str,Justify_type,min_width,precision);
301         }
302         if(*format=='f' || *format=='e' || *format=='E' || *format=='g' || *format=='G')
303         {
304             ok=1;arg_double=va_arg(ap,double);
305             print_double(arg_double,Justify_type,min_width,precision,*format);
306         }
307         if(*format=='p')
308         {
309             ok=1;arg_p=va_arg(ap,void *);
310             arg_int=(int)arg_p;
311             precision=8;//默认地址为8位,若机器地址不为8位可更改此处。
312             print_int(arg_int,Justify_type,min_width,precision,8);            
313         }
314         if(!ok) {putchar('%');format--;}//ch=='%' 
315         format++;
316     }
317     va_end(ap);
318 }

 

posted @ 2018-12-30 12:42  拦路雨偏似雪花  阅读(821)  评论(0编辑  收藏  举报