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 *s, int lim);
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¶
_getline 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. _getline 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.