手写简化版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 }