The C Programming Language

Chapter 5 - Pointers and Arrays 6

mmresult 2009. 3. 27. 14:07


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).

Solution by Gregory Pietsch


/* Gregory Pietsch ex. 5-6 dated 2001-01-29 */

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

/* getline: get line into s, return length */
int getline(char *s, int lim)
{
    char *p;
    int c;

    p = s;
    while (--lim > 0 && (c = getchar()) != EOF && c != '\n')
        *p++ = c;
    if (c == '\n')
        *p++ = c;
    *p = '\0';
    return (int)(p - s);
}

/* atoi: convert s to an integer
 *
 * Here's the easy way:
 * int atoi(char *s){return (int)strtoul(s, NULL, 10);}
 * But I'll behave...
 */
int atoi(char *s)
{
    int n, sign;

    while (isspace(*s))
        s++;
    sign = (*s == '+' || *s == '-') ? ((*s++ == '+') ? 1 : -1) : 1;
    for (n = 0; isdigit(*s); s++)
        n = (n * 10) + (*s - '0');  /* note to language lawyers --
                                     * the digits are in consecutive
                                     * order in the character set
                                     * C90 5.2.1
                                     */
    return sign * n;
}

/* Shamelessly copied from my 4-12 answer

itoa() is non-standard, but defined on p.64 as having this prototype:

void itoa(int n, char s[])

Instead of this, I thought I'd use a different prototype (one I got from

the library manual of one of my compilers) since it includes all of the
above:

char *itoa(int value, char *digits, int base);

Description:  The itoa() function converts an integer value into an
ASCII string of digits.  The base argument specifies the number base for

the conversion.  The base must be a value in the range [2..36], where 2
is binary, 8 is octal, 10 is decimal, and 16 is hexadecimal.  The buffer

pointed to by digits must be large enough to hold the ASCII string of
digits plus a terminating null character.  The maximum amount of buffer
space used is the precision of an int in bits + 2 (one for the sign and
one for the terminating null).

Returns:  digits, or NULL if error.

*/

char *utoa(unsigned value, char *digits, int base)
{
    char *s, *p;

    s = "0123456789abcdefghijklmnopqrstuvwxyz"; /* don't care if s is in

                                                 * read-only memory
                                                 */
    if (base == 0)
        base = 10;
    if (digits == NULL || base < 2 || base > 36)
        return NULL;
    if (value < (unsigned) base) {
        digits[0] = s[value];
        digits[1] = '\0';
    } else {
        for (p = utoa(value / ((unsigned)base), digits, base);
             *p;
             p++);
        utoa( value % ((unsigned)base), p, base);
    }
    return digits;
}

char *itoa(int value, char *digits, int base)
{
    char *d;
    unsigned u; /* assume unsigned is big enough to hold all the
                 * unsigned values -x could possibly be -- don't
                 * know how well this assumption holds on the
                 * DeathStation 9000, so beware of nasal demons
                 */

    d = digits;
    if (base == 0)
        base = 10;
    if (digits == NULL || base < 2 || base > 36)
        return NULL;
    if (value < 0) {
        *d++ = '-';
        u = -((unsigned)value);
    } else
        u = value;
    utoa(u, d, base);
    return digits;
}

/* reverse, shamelessly copied from my 4-13 answer */

static void swap(char *a, char *b, size_t n)
{
    while (n--) {
        *a ^= *b;
        *b ^= *a;
        *a ^= *b;
        a++;
        b++;
    }
}

void my_memrev(char *s, size_t n)
{
    switch (n) {
    case 0:
    case 1:
        break;
    case 2:
    case 3:
        swap(s, s + n - 1, 1);
        break;
    default:
        my_memrev(s, n / 2);
        my_memrev(s + ((n + 1) / 2), n / 2);
        swap(s, s + ((n + 1) / 2), n / 2);
        break;
    }
}

void reverse(char *s)
{
    char *p;

    for (p = s; *p; p++)
        ;
    my_memrev(s, (size_t)(p - s));
}

/* strindex: return index of t in s, -1 if not found */

/* needed strchr(), so here it is: */

static char *strchr(char *s, int c)
{
    char ch = c;

    for ( ; *s != ch; ++s)
        if (*s == '\0')
            return NULL;
    return s;
}

int strindex(char *s, char *t)
{
    char *u, *v, *w;

    if (*t == '\0')
        return 0;
    for (u = s; (u = strchr(u, *t)) != NULL; ++u) {
        for (v = u, w = t; ; )
            if (*++w == '\0')
                return (int)(u - s);
            else if (*++v != *w)
                break;
    }
    return -1;
}

/* getop */

#define NUMBER '0'      /* from Chapter 4 */

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))     /* collect integer part */
        while (isdigit(*++s = c = getch()))
            ;
    if (c == '.')       /* collect fraction part */
        while (isdigit(*++s = c = getch()))
            ;
    *++s = '\0';
    if (c != EOF)
        ungetch(c);
    return NUMBER;
}

/* Is there any more? */

 


 Category 0 Solution by Jesus Alvarez

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

#define STR_MAX  10000
#define BUFSIZE  100
#define NUMBER   '0'

char *my_getline  (char *, int);
char *itoa    (int, char *);
int   atoi        (char *);
char *strrev      (char *);
int   strindex    (char *, char *);
int   getop       (char *);
int   getch       (void);
void  ungetch     (int);

int main(int argc, char *argv[])
{
        int num;
        char ss1[STR_MAX];
        char ss2[STR_MAX];
        char atoi_buf[STR_MAX];
        char itoa_buf[STR_MAX];
        int type;
        char s[BUFSIZE];

        printf (">>> Please enter a number: ");
        my_getline(atoi_buf, STR_MAX);
        num = atoi(atoi_buf);

        printf ("\natoi: str: %s, int: %d\n", atoi_buf, num);
        printf ("itoa: int: %d, str: %s\n\n", num, itoa(num, itoa_buf));

        printf (">>> Enter string 1: ");
        my_getline(ss1,STR_MAX);

        printf (">>> Enter string 2: ");
        my_getline(ss2,STR_MAX);

        printf ("\nThe reverse of string 1: %s\n", strrev(ss1));
        printf ("The reverse of string 2: %s\n", strrev(ss2));

        num = strindex(ss1, ss2);
        if (num == -1) {
                printf("\nThe substring (string 2) was not found in the ");
                printf("base string (string 1).\n\n");
        } else {
                printf("\nThe substring was found in the base string, ");
                printf("starting at position %d.\n\n", num);
        }

        printf (">>> Please enter a simple equation (parsing example using getop()).\n");
        printf (">>> Example: 100+1039.238-acd\n");

        while ((type = getop(s)) != EOF) {
                switch (type) {
                case NUMBER:
                        printf ("Found a number: %s\n", s);
                        break;
                case '+':
                        printf ("Found \'+\'\n");
                        break;
                case '\n':
                        printf ("Found Line Break.\n");
                        break;
                default:
                        printf ("Found something else: %s\n", s);
                        break;
                }
        }

        return 0;
}

char *my_getline(char *str, int str_max)
{
        char c;
        /*
         * A local variable to perform arithmetic on so that 'str' points to
         * the correct location when it is passed back to the caller.
         */
        char *s1 = str;
        while ((c = getchar()) != EOF && c != '\n' && str_max-- > 0 ) {
                *s1++ = c;
        }

        if (*s1 == '\n') {
                *s1++ = c;
        }

        *s1 = '\0';
        return str;
}

char *itoa(int num, char *str)
{
        char *ls = str;
        do
        {
                *ls++ = num % 10 + '0';
        } while ((num /= 10) > 0);
        strrev(str);
        return str;
}

int atoi(char *str)
{
        int n, sign;
        while (isspace(*str)) {
                str++;
        }
        sign = (*str == '-') ? -1 : 1;
        if (*str == '+' || *str == '-') {
                str++;
        }
        for (n = 0; isdigit(*str); str++) {
                n = 10 * n + (*str - '0');
        }
        return n * sign;
}

char *strrev(char *str)
{
        int i;
        char c;
        char *lp1 = str; /* The start of str. */
        char *lp2 = str; /* The end of str, for incrementing.  */
        char *lp3 = str; /* The end of str, for reference. */

        i =  strlen(str)-1;
        lp2 += i;
        lp3 += i;

        do
        {
                c = *lp1;
                *lp1++ = *lp2;
                *lp2-- = c;
        } while ((i -= 2) > 0);

        *++lp3 = '\0';
        return str;
}

int strindex(char *s, char *t)
{
        int i, j;
        char *sb = s;
        char *ss = s;
        char *tb = t;
        for (i = 0; *sb != '\0'; i++, sb++) {
                tb = t;  /* Reset the pointer to the beginning of the string. */
                ss = sb; /* Reset the substring pointer to the base string
                          * pointer. */
                for (j = 0; *tb != '\0' && *ss == *tb; ss++, tb++, j++) {
                        if (*(tb+1) == '\0' && j > 0) {
                                return i;
                        }
                }
        }
        return -1;
}

int getop (char *str)
{
        int c;
        while ((*str++ = c = getch()) == ' ' || c == '\t');

        *str = '\0';
        if (!isdigit(c) && c != '.') {
                return c;
        }

        if (isdigit(c)) {
                while (isdigit(*str++ = c = getch()));
        }

        if (c == '.') {         /* Collect fraction. */
                while (isdigit(*str++ = c = getch()));
        }

        *--str = '\0';          /* Compensate for the extra character. */
        if (c != EOF) {
                ungetch(c);     /* Return extra charater to the stack. */
        }

        return NUMBER;
}

char buf[BUFSIZE];              /* The Stack */
int  bufp = 0;                  /* Top Position on the stack */

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;
        }

}

 

 

menonsahab's:
/**************************** atoi() ********************************/
#include <stdio.h>
#include <ctype.h>
#define SIZE 100
int main()
{
 char str[SIZE];
 scanf("%s", str);
 printf("string = %s, number = %d\n", str, atoi(str));
 return 0;
}

int atoi(char *s)
{
 int sign, n = 0;
 while(isspace(*s))
  s++;
 sign = (*s == '-') ? -1 : 1;
 if(*s == '+' || *s == '-')
  s++;
 while(isdigit(*s))
 {
  n = 10 * n + (*s-'0');
  s++;
 }
 return sign*n;
}
/********************************************************************/

/*************************** itoa() *********************************/
#include <stdio.h>
#define SIZE 100
char *itoa(int n, char *s);
void reverse(char *s);
int main()
{
 int num;
 char str[SIZE];
 scanf("%d", &num);
 printf("num = %d, string = %s\n", num, itoa(num, str));
 return 0;
}

char *itoa(int n, char *s)
{
 int sign;
 char *p = s;
 sign = (n < 0) ? -1 : 1;
 (sign < 0) ? n = -n : 0; // Won't work for n = INT_MIN, store -n in an unsigned variable if required
 while(n > 0)
 {
  *p++ = n%10 + '0';
  n = n / 10;
 }
 (sign == -1) ? (*p++ = '-') : 0;
 *p = '\0';
 reverse(s);
 return s;
}

void reverse(char *s)
{
 char *p;
 int temp;
 p = s;
 while(*p)
  p++;
 p--;
 while(s<=p)
 {
  temp = *s;
  *s = *p;
  *p = temp;
  s++;
  p--;
 }
}
/********************************************************************/

/**************************** reverse() *****************************/
#include <stdio.h>
#define SIZE 100
void reverse(char *s);
int main()
{
 char str[SIZE];
 scanf("%s", str);
 printf("string = %s\n", str);
 reverse(str);
 printf("reversed string = %s\n", str);
 return 0;
}

void reverse(char *s)
{
 char *p;
 int temp;
 p = s;
 while(*p)
  p++;
 p--;
 while(s<=p)
 {
  temp = *s;
  *s = *p;
  *p = temp;
  s++;
  p--;
 }
}
/********************************************************************/

/****************************** strindex() **************************/
#include <stdio.h>
#define SIZE 100
int main()
{
 char s[SIZE], t[SIZE];
 scanf("%s", s);
 scanf("%s", t);
 printf("strindex(%s, %s) = %d\n", s, t, strindex(s, t));
 return 0;
}

int strindex(char *s, char *t)
{
 int tlen, count;
 char *p, *q, *r;
 q = t;
 while(*q++);
 q--;
 tlen = q-t;
 for(p = s; *p ; p++)
 {
  count = 0;
  r = p;
  for(q = t; *q ; q++, r++)
  {
   if(*r == *q)
    count++;
   else
    break;
  }
  if(count == tlen)
   return (int)(p-s);
 }
 return -1;
}
/********************************************************************/

/**************************** getop() *******************************/
#include <stdio.h>
#include <ctype.h>
#define SIZE 100
#define NUMBER '0'
#define BUFSIZE 100
char buf[BUFSIZE];
int bufp = 0;

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;
}

int main()
{
 char str[SIZE];
 int type;
 while((type = getop(str)) != EOF)
  printf("type = %d, str = %s\n", type, str);
 return 0;
}

int getop(char *s)
{
 int c;
 while(isspace(*s = c = getch()));
 *(s+1) = '\0';
 if(!isdigit(c) && c != '.')
  return c;
 if(isdigit(c))
  while(isdigit(*++s = c = getch()));
 if(c == '.')
  while(isdigit(*++s = c = getch()));
 *++s = '\0';
 if(c != EOF)
  ungetch(c);
 return NUMBER;
}
/********************************************************************/