c - KR exercise 4.7 Ungets function test -


i need write function ungets(s) push entire string onto input. don`t know if implementation of ungets right. have no idea how test it, appreciated.

#include <stdio.h> #include <string.h>  /* implementation */      #define bufsize 100 static char buf[bufsize]; static int bufp = 0;             /* next free position in buf */  int getch(void)           /* (possibly pushed back) character */ {     return (bufp > 0) ? buf[--bufp] : getchar(); }   void ungetch(int c)   /* push character on input  */ {     if (bufp >= bufsize)         printf("ungetch: many characters\n");     else         buf[bufp++] = c; }   void ungets(char *s)   {     int c;      (c = 0; c < strlen(s); c++)          ungetch(c); }    

your getch() , ungetch() code approximately correct (i've not tested them, right). if going report error, better report error on stderr, using similar to:

fprintf(stderr, "ungetch: many characters (could not push %c)\n", c); 

you might think upgrading ungetch() return success/failure indication instead of nothing, , omit printing function; allows calling code decide how report error.

the ungets() function appears pushing counter value, not character. should avoid calling strlen() in loop condition; converts linear algorithm quadratic one.

void ungets(const char *s) {     int c;     while ((c = *s++) != '\0')         ungetch(c); } 

the const assures caller function doesn't modify string passed. code continues pushing until end of string because ungetch() doesn't tell it time stop. pass 20 kib string in, , generate 19.9 kib messages; not idea.


henrik carlqvist makes astute observation:

one more thing consider order in characters in ungets string stored in buffer , in order read out. current getch function reads out characters in reverse order stack want store strings on stack rightmost char first , leftmost char last.

and, of course, henrik right. so, code in ungets() needs upgraded, , needs string length — or @ least has find end of string.

i'm going assume variant of ungetch() function returns int, yielding eof when there's no space in buffer , other value (either 0 or character pushed back, code won't care which) when succeeds, loop can terminated if necessary.

the ungets() function upgraded report eof on error or number of characters pushed back.

int ungets(const char *s) {     int len = strlen(s);     (int = len; > 0; i--)     {         if (ungetch(s[i-1]) == eof)             return eof;     }     return len; } 

i wrote loop shown if change int size_t (an unsigned type), still works correctly. long use signed integer type, can use loop instead:

for (int = len - 1; >= 0; i--) {     if (ungetch(s[i]) == eof)         return eof; } 

or use while loop:

size_t len = strlen(s); while (len > 0) {     if (ungetch(s[--len]) == eof)         return eof; } 

using signed integers simpler, might more prone integer overflow issues if data sizes large enough (2 gib or more). isn't actual problem; if is, aware of issue , code accordingly.


tinky_winky asked:

could provide test case please?

i suppose so. ended with. has more casts in i'd compiles cleanly under default stringent compiling options (source file ugcs.c):

#include <assert.h> #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h>  #define dim(x)  (sizeof(x)/sizeof((x)[0]))  extern int getch(void); extern int ungetch(int c); extern int ungets_0(const char *s); extern int ungets_1(const char *s); extern int ungets_2(const char *s); extern int ungets_3(const char *s); extern int ungets_4(const char *s);  /* implementation */ enum { bufsize = 100 }; static char buf[bufsize]; static int bufp = 0;             /* next free position in buf */  int getch(void)           /* (possibly pushed back) character */ {     assert(bufp >= 0 && bufp <= (int)sizeof(buf));     return (bufp > 0) ? buf[--bufp] : getchar(); }  int ungetch(int c)   /* push character on input  */ {     if (bufp >= (int)sizeof(buf))         return eof;     else         buf[bufp++] = c;     return c; }  static void dump_pushback(void) {     printf("pbb: l = %d: [%.*s]\n", bufp, bufp, buf); }  /* viable quadratic because of repeated strlen() */ /* pushes characters in wrong order */ int ungets_0(const char *s) {     int c;      (c = 0; c < (int)strlen(s); c++)     {         // bogus: if (ungetch(c) == eof)         if (ungetch(s[c]) == eof)         {             fprintf(stderr, "ungetch() failed on %d '%c'\n", c, c);             dump_pushback();             return eof;         }     }     dump_pushback();     return 0; }  /* 1 workable solution */ int ungets_1(const char *s) {     int len = (int)strlen(s);     (int = len; > 0; i--)     {         if (ungetch(s[i - 1]) == eof)         {             fprintf(stderr, "ungetch() failed on %d '%c'\n", s[i-1], s[i-1]);             dump_pushback();             return eof;         }     }     dump_pushback();     return len; }  /* using size_t instead of int */ int ungets_2(const char *s) {     size_t len = strlen(s);     (size_t = len; > 0; i--)     {         if (ungetch(s[i - 1]) == eof)         {             fprintf(stderr, "ungetch() failed on %d '%c'\n", s[i-1], s[i-1]);             dump_pushback();             return eof;         }     }     dump_pushback();     return len; }  /* works signed int */ int ungets_3(const char *s) {     int len = strlen(s);      (int = len - 1; >= 0; i--)     {         if (ungetch(s[i]) == eof)         {             fprintf(stderr, "ungetch() failed on %d '%c'\n", s[len], s[len]);             dump_pushback();             return eof;         }     }     dump_pushback();     return len; }  /* using size_t , while loop */ int ungets_4(const char *s) {     size_t len = strlen(s);     while (len > 0)     {         if (ungetch(s[--len]) == eof)         {             fprintf(stderr, "ungetch() failed on %d '%c'\n", s[len], s[len]);             dump_pushback();             return eof;         }     }     dump_pushback();     return len; }  /* ** ungetters: constant array of pointers functions; each function ** returns int , takes constant char pointer argument.  in theory, ** typedef isn't necessary.  in practice, saves sanity. */ typedef int (*ungetstr)(const char *); static const ungetstr ungetters[] = {     ungets_0, ungets_1, ungets_2,     ungets_3, ungets_4 };  int main(int argc, char **argv) {     ungetstr ungets = ungets_1;     int index;     if (argc > 1 && (index = atoi(argv[1])) >= 0 && index < (int)dim(ungetters))     {         printf("using function ungets_%d\n", index);         ungets = ungetters[index];     }      char buffer[32];     index = 0;     int i;     int c;      (i = 0; < 40; i++)     {         if ((c = getch()) == eof)         {             printf("%d: got eof\n", i);             break;         }         printf("%d: got %3d '%c'\n", i, c, (isprint(c) ? c : '.'));         buffer[index++] = c;         if (i % 3 == 2)         {             printf("%d: ungetting %3d '%c'\n", i, c, (isprint(c) ? c : '.'));             ungetch(c);         }         else if (i % 7 == 6)         {             buffer[index/2] = '\0';             printf("%d: ungetting string [%s]\n", i, buffer);             ungets(buffer);             index = 0;         }     }      while ((c = getch()) != eof)         printf("%d: got %3d '%c'\n", i++, c, (isprint(c) ? c : '.'));      return 0; } 

compilation (using gcc 5.1.0 on mac os x 10.10.5):

$ gcc -o3 -g -std=c11 -wall -wextra -wmissing-prototypes -wstrict-prototypes \ >     -wold-style-definition -werror ugcs.c -o ugc $ 

sample data file (data):

abcdefg abcdefghijkl 

sample output ugcs < data:

0: got  97 'a' 1: got  98 'b' 2: got  99 'c' 2: ungetting  99 'c' 3: got  99 'c' 4: got 100 'd' 5: got 101 'e' 5: ungetting 101 'e' 6: got 101 'e' 6: ungetting string [abc] pbb: l = 3: [cba] 7: got  97 'a' 8: got  98 'b' 8: ungetting  98 'b' 9: got  98 'b' 10: got  99 'c' 11: got 102 'f' 11: ungetting 102 'f' 12: got 102 'f' 13: got 103 'g' 13: ungetting string [abb] pbb: l = 3: [bba] 14: got  97 'a' 14: ungetting  97 'a' 15: got  97 'a' 16: got  98 'b' 17: got  98 'b' 17: ungetting  98 'b' 18: got  98 'b' 19: got  10 '.' 20: got  65 'a' 20: ungetting  65 'a' 21: got  65 'a' 22: got  66 'b' 23: got  67 'c' 23: ungetting  67 'c' 24: got  67 'c' 25: got  68 'd' 26: got  69 'e' 26: ungetting  69 'e' 27: got  69 'e' 27: ungetting string [aabbb a] pbb: l = 7: [a bbbaa] 28: got  97 'a' 29: got  97 'a' 29: ungetting  97 'a' 30: got  97 'a' 31: got  98 'b' 32: got  98 'b' 32: ungetting  98 'b' 33: got  98 'b' 34: got  98 'b' 34: ungetting string [aaa] pbb: l = 5: [a aaa] 35: got  97 'a' 35: ungetting  97 'a' 36: got  97 'a' 37: got  97 'a' 38: got  97 'a' 38: ungetting  97 'a' 39: got  97 'a' 40: got  10 '.' 41: got  65 'a' 42: got  70 'f' 43: got  71 'g' 44: got  72 'h' 45: got  73 'i' 46: got  74 'j' 47: got  75 'k' 48: got  76 'l' 49: got  10 '.' $ 

testing algorithms:

$ in $(seq 0 4); ugcs $i < data > ugcs-$i.out; done $ ls -l ugcs-?.out  -rw-r--r--  1 jleffler  staff  1286 aug 16 14:42 ugcs-0.out -rw-r--r--  1 jleffler  staff  1286 aug 16 14:42 ugcs-1.out -rw-r--r--  1 jleffler  staff  1286 aug 16 14:42 ugcs-2.out -rw-r--r--  1 jleffler  staff  1286 aug 16 14:42 ugcs-3.out -rw-r--r--  1 jleffler  staff  1286 aug 16 14:42 ugcs-4.out $ diff ugcs-1.out ugcs-2.out 1c1 < using function ungets_1 --- > using function ungets_2 $ diff ugcs-1.out ugcs-3.out 1c1 < using function ungets_1 --- > using function ungets_3 $ diff ugcs-1.out ugcs-4.out 1c1 < using function ungets_1 --- > using function ungets_4 $ diff ugcs-0.out ugcs-4.out 1c1 < using function ungets_0 --- > using function ungets_4 12,13c12,13 < pbb: l = 3: [abc] < 7: got  99 'c' --- > pbb: l = 3: [cba] > 7: got  97 'a' 17c17 < 10: got  97 'a' --- > 10: got  99 'c' 22,26c22,26 < 13: ungetting string [cbb] < pbb: l = 3: [cbb] < 14: got  98 'b' < 14: ungetting  98 'b' < 15: got  98 'b' --- > 13: ungetting string [abb] > pbb: l = 3: [bba] > 14: got  97 'a' > 14: ungetting  97 'a' > 15: got  97 'a' 28,30c28,30 < 17: got  99 'c' < 17: ungetting  99 'c' < 18: got  99 'c' --- > 17: got  98 'b' > 17: ungetting  98 'b' > 18: got  98 'b' 43c43 < 27: ungetting string [bbbcc --- > 27: ungetting string [aabbb 45,54c45,54 < pbb: l = 7: [bbbcc < a] < 28: got  65 'a' < 29: got  10 '.' < 29: ungetting  10 '.' < 30: got  10 '.' < 31: got  99 'c' < 32: got  99 'c' < 32: ungetting  99 'c' < 33: got  99 'c' --- > pbb: l = 7: [a > bbbaa] > 28: got  97 'a' > 29: got  97 'a' > 29: ungetting  97 'a' > 30: got  97 'a' > 31: got  98 'b' > 32: got  98 'b' > 32: ungetting  98 'b' > 33: got  98 'b' 56,70c56,67 < 34: ungetting string [a <  < ] < pbb: l = 5: [bba <  < ] < 35: got  10 '.' < 35: ungetting  10 '.' < 36: got  10 '.' < 37: got  10 '.' < 38: got  65 'a' < 38: ungetting  65 'a' < 39: got  65 'a' < 40: got  98 'b' < 41: got  98 'b' --- > 34: ungetting string [aaa] > pbb: l = 5: [a > aaa] > 35: got  97 'a' > 35: ungetting  97 'a' > 36: got  97 'a' > 37: got  97 'a' > 38: got  97 'a' > 38: ungetting  97 'a' > 39: got  97 'a' > 40: got  10 '.' > 41: got  65 'a' $ 

Comments

Popular posts from this blog

dns - How To Use Custom Nameserver On Free Cloudflare? -

python - Pygame screen.blit not working -

c# - Web API response xml language -