Exercise 5.6 - Find the pattern using pointers¶
Question¶
Rewrite appropriate programs from earlier chapters and exercises with pointers instead of array indexing. Good possibilities include getline (Chapters 1 and 4), atoi, itoa, and their variants (Chapters 2, 3, and 4), reverse (Chapter 3), and strindex and getop (Chapter 4).
/**
*
* pattern matching program
*
**/
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#include<stdlib.h>
#define NUMBER '0' /* signal that a number was found */
#define MAXVAL 100 /* maximum depth of val stack */
#define BUFSIZE 100
#define MAXLINE 1000
#define MAXOP 100
int getch(void);
void ungetch(int);
int getop(char *);
void push(double);
double pop(void);
int mgetline(char *line,int max);
int strindex(char *s,char *t);
int atoiv2(char *);
void itoav2(int n,char *s);
void reverse(char *);
int sp = 0;
int bufp = 0;
double val[MAXVAL];
char buf[BUFSIZE];
char pattern[] = "ould"; /* pattern to search for */
/* find all the matching patterns */
int main(void)
{
char line[MAXLINE];
int found=0;
/* mgetline ends when a newline starts with X */
while((mgetline(line,MAXLINE)) > 0)
if(strindex(line,pattern) >= 0) {
printf("%s\n",line);
found++;
}
char *s="1234";
int ret;
ret=atoiv2(s);
printf("%d\n",ret);
char s1[100];
int i=12345;
itoav2(i,s1);
reverse(s1);
printf("%s\n",s1);
char *s2="This is a line";
char *t="is";
ret=0;
ret=strindex(s2,t);
printf("%d\n",ret);
int type;
double op2;
char s3[MAXOP];
while((type = getop(s3)) != EOF)
{
switch(type)
{
case NUMBER:
push(atof(s3));
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
op2 = pop();
push(pop() - op2);
break;
case '/':
op2 = pop();
if( op2 != 0.0)
push(pop() / op2);
else
printf("error: zero divisor\n");
break;
case '\n':
printf("\t%.8g\n",pop());
break;
default:
printf("error: unknown command %s\n",s);
break;
}
}
return 0;
}
int atoiv2(char *s)
{
int n,sign;
for(;isspace(*s);s++) /* skip white space */
;
sign = ( *s =='-')? -1:1;
if(*s=='+' || *s=='-')
s++;
for(n=0;isdigit(*s);s++)
n = 10 *n + *s - '0';
return sign * n;
}
/* reverse polish calculator */
/* push: push f onto value stack */
void push(double f)
{
if(sp < MAXVAL)
val[sp++] = f;
else
printf("error: stack full,can't push %g\n",f);
}
/* pop: pop and return top value from stack */
double pop(void)
{
if( sp > 0)
return val[--sp];
else
{
printf("error: stack empty \n");
return 0.0;
}
}
/* getop: get next operator or numeric operand pointer version */
/* getop */
int getop(char *s)
{
int c;
while((*s=c=getch()) == ' ' || c == '\t')
;
*(s+1) = '\0';
if(!isdigit(c) && c!='.')
return c; /* not a number */
if(isdigit(c))
while(isdigit(*++s = c = getch()))
;
if(c == '.')
while(isdigit(*++s = c = getch()))
;
*s = '\0';
if(c != EOF)
ungetch(c);
return NUMBER;
}
int getch(void)
{
return (bufp > 0) ? buf[--bufp]:getchar();
}
void ungetch(int c)
{
if(bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++]=c;
}
/* itoa */
void itoav2(int n,char *s)
{
int sign;
char *t=s;
if((sign = n) < 0)
n = -n;
do
{
*s++ = n % 10 + '0';
} while ((n /= 10) > 0);
if(sign < 0)
*s++ = '-';
*s='\0';
}
/* reverse */
void reverse(char *s)
{
int c;
char *t;
for(t=s+(strlen(s)-1);s<t;s++,t--)
{
c=*s;
*s=*t;
*t=c;
}
}
/* mgetline */
int mgetline(char *s,int lim)
{
int c;
char *t=s;
while(--lim > 0 && (c=getchar())!='X' && c!='\n')
*s++=c;
if(c=='\n')
*s++=c;
*s='\0';
return s-t;
}
/* strindex */
int strindex(char *s,char *t)
{
char *b=s;
char *p,*r;
for(;*s!='\0';s++)
{
for(p=s,r=t;*r!='\0' && *p==*r;p++,r++)
;
if(r>t && *r == '\0')
return s-b;
}
return -1;
}
Explanation¶
mgetline takes a string (char *)
and MAXLINE, the maximum length of the line. It
gets one character at a time using getchar() and as long as we are under limit
(less than MAXLINE) and it is not n character. It stores the charaacters in the
line, advancing the pointer for each character.
When it hits n, it adds n and closes the line with 0. mgetline returns the length of the line, subtracting the last address with initial address.
atoi - the gets the sign and then read each read each character using the pointer, checks if it is digit and converts it to integer. The curx of this function is:
for(n=0;isdigit(*s);s++)
n = 10 *n + *s - '0';
itoa - takes the number, converts it into a string, by adding ‘0’ and stores them to a character pointer, advancing the pointer after each assignment. When the assignments are done, it adds a null character to form a valid C string:
do
{
*s++ = n % 10 + '0';
} while ((n /= 10) > 0);
if(sign < 0)
*s++ = '-';
*s='\0';
reverse takes a char *s
as argument and uses a temporary string char *t
, to
swap the characters from the end to the front. It uses another intermediate
character c
to do the swap.
strindex takes two strings char *s
and char *t
and determines the start of
the string t in s. It stores the s position in the base, b and then advances s
and for each advance checks if the substring t is contained in s. If the
substring is contained, it returns the current position - base position, that s
-b
, otherwise it returns -1.
getop works by taking a char *s
as it’s argument. It reads the character and
stores it in s. It skips the whitespaces and then checks if it isdigit.
If it not a digit, it closes the string using 0 and returns the character.
If it is digit, then it reads both real and decimal part, along with dot, closes the string using 0 and the returns that it found a NUMBER.
Since checking of the character, happens after reading, an extra character is read when our condition fails (that is we have completely read the NUMBER) In that case, we do a ungetch, to return the character back to buffer and return that we found a NUMBER.