I have written the function.here is the code.
filename ./k\&r7-3.c
/*program does not work if we give a huge float or double*/
/*len,precision and field_width should be initialsed before using*/
/*do field_width and precision functions need to be separated out?*/
/*right allignment or left allignment need to check*/
/*in switch statement some statements are repeated,make them common??*/
/*enable * usage as in printf*/
/*enable exponential power display,hexadecimal and octal number display*/
/*link itoa,roundoff,dotoa*/
#define MAXFIELD 5
#define MAXLEN 30
#define DEFAULT_PRES 6
#include<stdio.h>
#include<ctype.h>
#include<string.h>//for strlen
#include<stdlib.h>//only for atoi,could have as well used my own
#include <stdarg.h>
extern void itoa(int,char*);
extern void print_arr(char*);
extern void roundoff(char*,int);
extern void dotoa(double,char*);
/* minprintf: minimal printf with variable argument list */
void minprintf(char *fmt, ...){
va_list ap; /* points to each unnamed arg in turn */
char *p, *sval;
char field_store[MAXFIELD];
char pres_store[MAXFIELD];//precision also number of digits max kept same as field no of digits
char arguments[MAXLEN];
int ival,field_width,precision,i=0,len;//i is for arguments array,len is for length of number in arguments[]
short int right_allign=1;//by default right alligned
double dval;
va_start(ap, fmt); /* make ap point to 1st unnamed arg */
for (p = fmt; *p; p++) {
if (*p != '%')
putchar(*p);
else{
/*right allign or left allign check and assign right_allign accordingly*/
if((*++p)=='-')
right_allign=0;
else{
right_allign=1;
--p;//'-' not there instead digit there probably
}
/*field_width and precision input*/
/*if it is not explicitly declared then there has*/
/*to be some default value or the previous value will be taken*/
pres_store[0]='\0';
field_store[0]='0';field_store[1]='\0';//field width can be safely initialised to 0
/*because its implementation is same for all*/
if(isdigit(*++p)){
i=0;//for moving along field store array
while(!isalpha(*p) && (*p)!='.')
field_store[i++]=*(p++);
field_store[i]='\0';
i=0;//now for filling pres_store[]
if(*p=='.'){
printf("\nstoring in pres_store:");//testing
while(isdigit(*++p)){
pres_store[i++]=(*p);
printf("%c ",pres_store[i-1]);//testing
}
putchar('\n');//testing
}
pres_store[i]='\0';
printf("\nafter writing in the pres_store array:");//testing
print_arr(pres_store);//testing
i=0;//keeping i in initial condition
}
switch (*p) {//pointer will come till here while checking isnum
case 'd':
ival = va_arg(ap, int);
itoa(ival,arguments);
/*precision manage*//*this is taken before fields this because fields thing only deals with printing*/
/*precision has different meaning for integers*/
precision=atoi(pres_store);
len=strlen(arguments);
if(precision=='\0')//that means it is not specified
precision=0;
if(len<=precision)
;//here we will take precision
else
precision=len;//then we are going to take length
/*fields manage*//*just adds spaces when necessary*/
field_width=atoi(field_store);
if(right_allign==1){
i=1;//initialising before using it
while((i++)<=(field_width-precision))//if field width<len then loop wont start,since precision is number of digits
putchar(' ');
i=1;
while((i++)<=precision-len)
putchar('0');
i=0;//leaving i as it was before,ready for another loop
}
else{/*in this case add spaces to the *array* *///left_allign
i=len;
while(i<=(field_width-precision)){
arguments[i++]=' ';
}
arguments[i]='\0';
i=1;
while((i++)<=(precision-len))
putchar('0');
i=0;
}
print_arr(arguments);
break;
case 'f':
dval = va_arg(ap, double);
dotoa(dval,arguments);
/*precision manage*//*if not given 6 decimal places*/
if(pres_store[0]!='\0'){//array not empty
precision=atoi(pres_store);
printf("\nprinting precision:");//testing
print_arr(pres_store);//testing
}
else//default precision 6
precision=DEFAULT_PRES;
printf("\ndouble precision:%d\n",precision);//testing
roundoff(arguments,precision);/*roundoff to precision number of places*/
/*field manage*/
len=strlen(arguments);//length may have changed after precision
field_width=atoi(field_store);
putchar('\n');//testing
print_arr(arguments);//testing
if(right_allign==1){
i=1;
while((i++)<=(field_width-len))
putchar(' ');
i=0;//leave i in original position
}
else{//left align
int temp=field_width-len;
i=len-1;//pointing at last element
while((temp--)>0)
arguments[i++]=' ';
arguments[i]='\0';
i=0;//assigning i to the initial value
}
print_arr(arguments);
break;
case 's':
for (sval = va_arg(ap, char *),i=0; *sval; sval++)
arguments[i++]=(*sval);
/*precision manage*/
precision=atoi(pres_store);
if(precision=='\0')
precision=MAXLEN;//biggest arguments size that can be
len=strlen(arguments);
if(len<=precision)
precision=len;//precision is number of digits going to be printed
else
arguments[precision]='\0';//eg:if array is a,b,h,y and precision 2 then array[2]='\0'
/*field manage*/
field_width=atoi(field_store);
if(right_allign==1){
i=1;//initialising before using it
while((i++)<=(field_width-precision))//if field width<len then loop wont start,since precision is number of digits
putchar(' ');
i=0;//leaving i as it was before,ready for another loop
}
else{/*in this case add spaces to the *array* *///left_allign
i=len;
while(i<=(field_width-precision)){
arguments[i++]=' ';
}
arguments[i]='\0';
i=0;
}
print_arr(arguments);
break;
case 'c':
putchar(va_arg(ap,int));
break;
default:
putchar(*p);
break;
}
}
}
va_end(ap); /* clean up when done */
}
void print_arr(char array[]){
int i;
for(i=0;array[i]!='\0';++i)
printf("%c",array[i]);
return;
}
the main function for testing the function is as follows.
/*for testing minprintf*/
#include<stdio.h>
extern void minprintf(char*,...);
int main(){
int a=4;
char s[]="dumo";
minprintf("hump %7.3d:%4.3s %2.2f %c\n",a,s,4.195689,'x');
return 0;
}
no warnings or errors while compiling.
but in case 'f',line 113 printing the pres_store array prints the arbitrary value 750 which should have been the precision of the double number.printing the same array before the switch statement is giving the correct value of 2.
I am not able to understand why this is happening.
because the precision value is set to 750 somehow i am not able to roundoff my number to 2 places of decimal.
Command:gcc -Wall ~/todel.c ./k\&r7-3.c ./my_template_func/itoa.c ./my_template_func/roundoff.c ./my_template_func/dotoa.c -o ./k\&r7-3
Output without the testing statements:
hump 004: dum 4.195688999999999779788595333229750 x
Output with testing statements:
hump
storing in pres_store:3
after writing in the pres_store array:3 004:
storing in pres_store:3
after writing in the pres_store array:3 dum
storing in pres_store:2
after writing in the pres_store array:2
printing precision:750
double precision:750
4.1956889999999997797885953332297504.195688999999999779788595333229750 x
Incorrect output is occuring first at line 120 of minprintf function and then at line 123.
i have not included itoa,roundoff,and dotoa(double to array) code here.those codes are mostly correct.if needed tell me.

New Topic/Question
Reply



MultiQuote





|