Hatena::Groupcprogramming

C Study Diary

2009-01-09

c5ex2_getfloat.cpp

14:48

Write getfloat, the floating-point analog of getint . What type does getfloat return as its function value? Int

#include <stdio.h>
#include <ctype.h>
#define BUFSIZE 100

char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0; /* next free position in buf */

int getch(void) /* get a (possibly pushed back) character */
{
  return (bufp > 0) ? buf[--bufp] : getchar();
}
 
void ungetch(int c) /* push character back on input */
{
  if(bufp >= BUFSIZE)
    printf("ungetch: too many characters\n");
  else  
    buf[bufp++] = c;  
}


/* getint:  get next integer from input into *pn */
int getfloat(float *pn)
{
	int c, sign, signflag=0;
	float decimal=0.0, rate = 1;
	while (isspace(c = getch())) /* skip white space */
	;
	if (!isdigit(c) && c != EOF && c != '+' && c != '-'&& c != '.') {
		ungetch(c); /* it is not a number */
		return EOF;
	}
	sign = (c == '-') ? -1 : 1;
	if (c == '+' || c == '-') {
		c = getch();
		signflag = 1;
	}	
	/* if sign without number */
	if(!isdigit(c) && c != '.' && c!=EOF) {
		ungetch(c);
		if(signflag) ungetch(((sign==1) ? '+':'-'));
		return EOF;
	}else {	
		for (*pn = 0.0; isdigit(c); c = getch())
			*pn = 10.0 * *pn + (c - '0');
		/* point inputed */
		if(c=='.') {			
			c=getch();
			while(isdigit(c)){
				rate = rate*0.1; 
				decimal = decimal+(c-'0')*rate;
				c=getch();
			}
			*pn +=decimal;
		}	
		*pn *= sign;
		if (c != EOF)
			ungetch(c);
		return c;
	}
}

int main(){
	
	float pa[10]={};
	int	i=0;
	
	while(getfloat(&pa[i])!=EOF) {
		pa[i++];
		printf("input: %f\n\n",pa[i-1]);
	}
	return 0;
}

Run:

$ ./c5ex2_getfloat.exe
2
input: 2.000000

-222
input: -222.000000

2.22
input: 2.220000

-3.335
input: -3.335000

c5ex1_getint.cpp

14:44

As written, getint treats a + or - not followed by a digit as a valid representation of zero. Fix it to push such a character back on the input.

This program is modified on the getint() in book.

#include <stdio.h>
#include <ctype.h>
#define BUFSIZE 100

char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0; /* next free position in buf */

int getch(void) /* get a (possibly pushed back) character */
{
  return (bufp > 0) ? buf[--bufp] : getchar();
}
 
void ungetch(int c) /* push character back on input */
{
  if(bufp >= BUFSIZE)
    printf("ungetch: too many characters\n");
  else  
    buf[bufp++] = c;  
}


/* getint:  get next integer from input into *pn */
int getint(int *pn)
{
	int c, sign, signflag=0;
	while (isspace(c = getch())) /* skip white space */
	;
	if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
		ungetch(c); /* it is not a number */
		return EOF;
	}
	sign = (c == '-') ? -1 : 1;
	if (c == '+' || c == '-') {
		c = getch();
		signflag = 1;
	}	
	/* if sign without number */
	if(!isdigit(c) && c!=EOF) {
		ungetch(c);
		if(signflag) ungetch(((sign==1) ? '+':'-'));
		return EOF;
	}else {	
		for (*pn = 0; isdigit(c); c = getch())
			*pn = 10 * *pn + (c - '0');
		*pn *= sign;
		if (c != EOF)
			ungetch(c);
		return c;
	}
}


int main(){
	
	int pa[10]={}, i=0;
	
	while(getint(&pa[i])!=EOF) {
		pa[i++];
		printf("input: %d\n\n",pa[i-1]);
	}
	printf("char left in buff: %c",getch());
	return 0;
}

Run:

$ ./c5ex1_getint.exe
-23232
input: -23232

+23232
input: 23232

+-232311
char left in buff: +

DannydupDannydup2017/06/25 00:38Attention Required! | Cloudflare
<a href=http://acheterdufrance.com/>More info>>></a>

TimothySydayTimothySyday2017/07/03 08:55301 Moved Permanently
<a href=https://www.viagrapascherfr.com/>301 Moved Permanently!</a>

2008-12-22

c4ex13_reverse_recursive.cpp

17:30

Write a recursive version of the function reverse(s) , which reverses the string s in place.

#include <stdio.h>
#include <stdlib.h>
#include <string.h> 
#include <limits.h> 

#define MAX 500
 
/* reverse string */ 
void reverse(char *s, int sindex, int eindex){
	char temp;
	if(sindex==eindex) {
		return;
	}
	else {
		temp=s[sindex];
		s[sindex]=s[eindex];
		s[eindex]=temp;
		reverse(s,sindex+1,eindex-1);		
	}
}

int main(void){

	char test_str[MAX];
	
	printf("Input string to reverse: \n");
	gets(test_str);
	printf("Test string is : %s\n",test_str);
	reverse(test_str, 0, strlen(test_str)-1);
	printf("After reverse:%s\n",test_str);
	
	return 0;
}

Run:

$ ./c4ex13_reverse_recursive.exe
Input string to reverse:
this is the test string for reverse
Test string is : this is the test string for reverse
After reverse:esrever rof gnirts tset eht si siht

c4ex11_itoa_recursive.cpp

17:30

Adapt the ideas of printd to write a recursive version of itoa ; that is, convert an integer into a string by calling a recursive routine.

Question: it may not be very smart to use an external variable as the string index, but I cannot think of a better way in the recursive routine. Suggestion welcomed!

#include <stdio.h>
#include <stdlib.h>
#include <string.h> 
#include <limits.h> 

#define MAX 20
 
int i;  /* string index */

/* put char to string */ 
void sputchar(char c, char* s){
	
	s[i++]=c;
	s[i]='\0';
}
 
void itoa(long n, char* s){
	
	i=0;
	if(n<0) {
		sputchar('-',s);
		n=-n;
	}	
	if(n/10==0) {
		sputchar(n%10+'0',s);
	}else{
		itoa(n/10,s);
		sputchar(n%10+'0',s);
	}
	
}

int main(void){

	long a = -1122333;
	char *buff;
	
	itoa(a, buff);
	printf("itoa(%d)=%s\n",a,buff);
	a =890556;
	itoa(a, buff);
	printf("itoa(%d)=%s\n",a,buff);

	return 0;
}

Run:

$ ./c4ex11_itoa_recursive.exe
itoa(-1122333)=1122333
itoa(890556)=890556

2008-12-17

c4ex8_ungetch.cpp

17:23

Suppose that there will never be more than one character of pushback. Modify getch and ungetch accordingly.

#include <stdio.h>
#include <string.h>

int save=NULL;

/* Getch: get a ( possibly pushed back) character. */
int getch(void)
{
	int t;
	if(save!=NULL){
		t=save;
		save=NULL;
		return t;
	} 
	else return getchar();
   
}  

/* unGetch: push character back on input. */
void ungetch(int c)
{  
	if(save != NULL)
		printf("ungetch: too many characters\n");
	else  
		save = c;
}

void ungets(char s[])
{
	int c, i=0;
	for(i=strlen(s);i>=0;i--){
	
		ungetch(s[i]);
	
	}
}

int main()
{
	int c, i=0;
	char* s = "h";
	char t;
	
	printf("%s\n",s);		
	ungets(s);	
	printf("%c\n",getch());	
	
	s = "hello";	
	printf("%s\n",s);		
	ungets(s);	
	printf("%c\n",getch());
	
	t = 'A';	
	printf("%c\n",t);		
	ungetch(t);	
	printf("%c\n",getch());
}

Run:

$ ./c4ex8_ungetch.exe
h
h
hello
ungetch: too many characters
ungetch: too many characters
ungetch: too many characters
ungetch: too many characters
o
A
A

c4ex7_ungets.cpp

17:20

Write a routine ungets(s) that will push back an entire string onto the input.


#include <stdio.h>
#include <string.h>

#define BUFSIZE 100

int buf[BUFSIZE];
int bufp = 0;

/* Getch: get a ( possibly pushed back) character. */
int getch(void)
{
   return (bufp > 0) ? buf[--bufp]: getchar();
}

/* unGetch: push character back on input. */
void ungetch(int c)
{
   if(bufp >= BUFSIZE)
      printf("\nUnGetch: too many characters\n");
   else
      buf[bufp++] = c;
}

void ungets(char s[])
{
	int c, i=0;
	for(i=strlen(s);i>=0;i--){
	
		ungetch(s[i]);
	
	}
}

int main()
{
	int c, i=0;
	char s[] = "hello this a test";
	
	printf("%s\n",s);	
	
	ungets(s);
	
	while((c=getch())!='\n'){
		printf("%c",c);
	}
	
}

Run:

$ ./c4ex7_ungets.exe
hello this a test
hello this a test

2008-12-15

c4ex3-6calculator.cpp

19:44

On the previous calculator:

Add commands to print the top element of the stack without popping, to duplicate it, and to swap the top two elements. Add a command to clear the stack.

Add access to library functions like sin , exp , and pow . See <math.h> in Appendix B, Section 4.

Add commands for handling variables. (It's easy to provide twenty-six variables with single-letter names.) Add a variable for the most recently printed value.

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#define MAX 100
#define NUM '#'
#define VAR '@'
#define END '|'
#define UNKNOW '&'

#define ERROR -1
#define NORMAL 0
#define LAST 1

int sp=0, i=0, errflag=NORMAL;
double stack[MAX];
double number=0.0;
char s[MAX];
double v[26]={};
char varname = NULL;

void push(double n){
	
	if(sp==MAX) {
		printf("Error: exceed max stack space!\n");
		errflag = ERROR;
	}else{
		stack[sp++]=n;
	}
}

double pop(){
	
	if(sp>0) return stack[--sp];  /* --sp ! */
	else {
		printf("Error: stack is empty!\n");
		errflag = ERROR;
		return 0.0;
	}	
}

void showtop(){

	if(sp>0) {
		printf("top element is %f\n", stack[sp-1]);
	}	
	else printf("Error: no element in stack. \n");
}

void copytop(){
	
	double temp;
	temp=pop();
	push(temp);
	push(temp);
	
}

void swaptoptwo(){

	double temp1;
	double temp2;
	
	temp1=pop();
	temp2=pop();
	
	push(temp1);
	push(temp2);	
 
}

void clear(){

	sp=0;
}

double atof(char* s){
	
	double number=0.0, ratio=1.0, ten=10.0;
	int i=0, non_num=0, point=-1, sign=1, psign=1, e=0, exp=0, digit=0;

	while(s[i]!='\0'){
		switch(s[i]){
			case ' ': non_num++; break;
			case '.': point=i; break;
			case '-': if(e) psign=-1; else {sign=-1; non_num++;} break;
			case '+': if(e) psign=1; else {sign=1; non_num++;} break;
			case 'e': e=1; break;
			case 'E': e=1; break;
			default: if(e) exp=exp*10+(s[i]-'0'); else { number=number*ten+(s[i]-'0'); digit++; }
		}
		i++;
	}
	/* negtive exp sign or exp =0 => ratio=0.1 ; positive exp sign => ratio = 10.0  */
	if(psign<0 || exp==0) ratio = 1/ten;
	else ratio = ten;
	
	/* if point appears */
	if(point!=-1){
		for(i=0;i<abs(psign*exp-(digit-(point-non_num)));i++)
			number = number * ratio; 
	}
	/* no point */	
	else {
		for(i=0;i<exp;i++)
			number = number * ratio; 
	}

	return number*sign;
	
}

/* process input - Polish notation */
int getinput(){
	
	int c, nc, sign = 1, j, k=0, flag;
	char op[5], value[MAX];
	
	while((c=s[i++])!='\0'){	

		/* - or minus */
		if(c=='-') {
			nc=s[i];
			if(isdigit(nc) || nc=='.'){
				sign=-1;
			}
			else {
				return c;
			}	
		}
		/* var gets value */
		else if(c=='='){
			if(varname!=NULL) {
				
				j=0;
				while(!isdigit(c)&&c!='.'){
					if(c=='-'){
						value[j++]=c;
					}
					c=s[i++];
				}
				while(isdigit(c)||c=='.') {
					value[j++]=c;	
					c=s[i++];
				}		
				i--;				
				value[j]='\0';		
				v[varname-'a'] = atof(value);
				varname=NULL;
			}	
			else printf("error: no variable name before '='. \n");
		}
		/* library functions or var name */
		else if(isalpha(c)){
			/* save characters to op[] */
			j=0;
			while(isalpha(c)){
				op[j++] = c;
				c=s[i++];			
			}
			op[j]='\0';
			i--;
			/* if op is var name */
			if(strlen(op)==1) {
				varname=op[0];
			/* check if there is a '=' afterwards */
				flag=1;
				for(k=i;s[k]!='\0';k++){
					if(s[k]=='=') {
						flag = 0;	 
						break;
					}		
				}
			/* if there isn't a '=' afterwards,  var is using in formular, return VAR */
				if(flag) return VAR;				
			/* library functions */	
			}else if(strcmp(op,"cos")==0){
				return 'c';
			}
			else if(strcmp(op,"sin")==0){
				return 's';
			}
			else if(strcmp(op,"exp")==0){
				return 'e';
			}
			else if(strcmp(op,"pow")==0){
				return 'p';
			} else return UNKNOW;
		}		
		/* number in formular */
		else if(isdigit(c) || c=='.') {
			j=0;
			while(isdigit(c)||c=='.') {
				value[j++]=c;	
				c=s[i++];
			}			
			value[j]='\0';			
			i--;
			number = atof(value)*sign;
			
			return NUM;
		}	
		else if(c==' ' ||c=='\t') 
			;
		else return c;
	}
	return END;

}

void clearstate(){
	number=0.0;
	i=0;
	varname = NULL;
	errflag = NORMAL;
	clear();
}

int main(){
	
	int c;
	double result, t1, t2;
	
		printf("Input formular: (enter ! to quit )\n");
		gets(s);
		
		while(s[0]!='!'){
		/* operation  */
			while((c=getinput())!=END){
				switch(c){
					case '+': 
						t1=pop(); t2=pop(); push(t1+t2); break;
					case '-': 
						t1=pop(); t2=pop(); push(t2-t1); break;
					case '*': 
						t1=pop(); t2=pop(); push(t2*t1); break;
					case '/': 
						t1=pop(); if((t2=pop())!=0) push(t2/t1); else { printf("Error: 0 cannot be divided. \n"); errflag = ERROR; } break;
					case '%': 
						t1=pop(); if((t2=pop())!=0) push((int)t2%(int)t1); else { printf("Error: 0 cannot be divided. \n"); errflag = ERROR; } break;	
					case 'c': 
						t1=pop(); push(cos(t1)); break;
					case 's': 
						t1=pop(); push(sin(t1)); break;
					case 'e': 
						t1=pop(); push(exp(t1)); break;
					case 'p': 
						t1=pop(); t2=pop(); push(pow(t2,t1)); break;	
					case '<': 
						printf("last result = %g\n",result); errflag =LAST; break;	
					case VAR: 
						if(v[varname-'a']!=NULL) { push(v[varname-'a']); } else printf("Error: no variable value found.\n"); break;
					case NUM:  
						push(number); number=0; break;
					default: 
						printf("Error: unkown command! \n"); 	errflag = ERROR;					
				}		
			}
			if(errflag == NORMAL) {
				printf("%s = ",s);
				result = pop();
				printf("%g\n",result);
			}
			if(errflag == ERROR) printf("Not calculate. Input Error.\n");
			/* clear state for new inputs */
			clearstate();				
			printf("\nInput formular: (enter ! to quit )\n");
			gets(s);
		
		}
}	

Run:

$ ./c4ex3-6calculator.exe
Input formular: (enter ! to quit )
90 cos
90 cos = -0.448074

Input formular: (enter ! to quit )
40 cose
Error: unkown command!
Not calculate. Input Error.

Input formular: (enter ! to quit )
a= -.234 b=2.14 a b + 10 *
a= -.234 b=2.14 a b + 10 * = 19.06

Input formular: (enter ! to quit )
!

2008-12-12

c4ex3calculator.cpp

16:30

Given the basic framework, it's straightforward to extend the Polish notation calculator. Add the modulus ( % ) operator and provisions for negative numbers.

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

#define MAX 100
#define NUM '#'

int sp=0, i=0;
double stack[MAX];
double number=0.0;
char s[MAX];

void push(double n){
	
	if(sp==MAX) {
		printf("exceed max stack space!\n");
	}else{
		stack[sp++]=n;
	}
}

double pop(){
	
	if(sp>0) return stack[--sp];  /* --sp ! */
	else {
		printf("stack is empty!\n");
		return 0.0;
	}	
}

/* process input - Polish notation */
int getinput(){
	
	int c, nc;
	int sign = 1;
	double frac = 0.0, p = 1.0;
	while((c=s[i++])!='\0'){	
		/* operator */
		if(c=='+' || c=='*' || c=='/' || c=='%') {
			return c;
		}	
		if(c=='-') {
			if((nc=s[i])!=' '){
				sign=-1;
			}
			else {
				return c;
			}	
		}	
		/* number */
		if(isdigit(c) || c=='.') {
			while(isdigit(c)) {
				number=number*10.0+(c-'0');
				c=s[i++];
			}	
			if(c=='.'){
				c=s[i++];
				while(isdigit(c)) {
					p*=0.1;
					frac+=(c-'0')*p;
					c=s[i++];
				}
			}			
			i--;
			number = (number+frac)*sign;
			return NUM;
		}	
	}
	return EOF;

}

int main(){
	
	int c;
	double result=0, t1, t2;
	
	printf("input formular:\n");
	gets(s);

	/* operation  */
	while((c=getinput())!=EOF){
		switch(c){
			case '+': t1=pop(); t2=pop(); push(t1+t2); break;
			case '-': t1=pop(); t2=pop(); push(t2-t1); break;
			case '*': t1=pop(); t2=pop(); push(t2*t1); break;
			case '/': t1=pop(); t2=pop(); push(t2/t1); break;
			case '%': t1=pop(); if((t2=pop())!=0) push((int)t2%(int)t1); else printf("0 cannot be divided. \n"); break;	
			case NUM:  push(number); number=0; break;
			default: printf("error input! \n"); return -1;						
		}		
	}
	printf("%s = ",s);
	printf("%f\n",pop());
 	
}	

Run:

$ ./c4ex3calculator.exe
input formular:
2 3 + 4.4554 * 56.1 /
2 3 + 4.4554 * 56.1 / = 0.397094

$ ./c4ex3calculator.exe
input formular:
432 100 % 2 * 0+
432 100 % 2 * 0+ = 64.000000

moritamorita2008/12/15 20:29How about wrong inputs? for example, "1++1".
In general, you should be careful to handle user inputs.

annancyannancy2008/12/16 13:01Thanks for the comment. Yeah, this program is weak at wrong input. When error operator inputted, user will get 'stack empty error'. I'll try to improve it in the next version.