Very complex C infinite loop debugging -
i want color stand alone digits, not preceded alphabetical character , terminated numeric one.
can guess why when use program write existing text file text file, several megabytes in size in seconds? there infinite loop occurring.
char ch; _bool finished = true; void color(); void skip(); int main() { while (finished) { ch = getchar(); if (ch == -1) { finished = false; } if ( (ch >= 'a' && ch <= 'z') || (ch >= 'a' && ch <= 'z') ) { skip(); } else if (ch >= '0' && ch <= '9'){ color(); } else { printf("%c", ch); } } return 0; } void color() // color characters numbers { printf("\e[31m%c\e[0m", ch); } void skip() // skip whole words , still print them { putchar(ch); while ((ch = getchar()) != ' ') { printf("%c", ch); } }
infinite loops
the infinite loop report caused incorrect handling of eof
in posted code. plain char
may signed
or unsigned
, , may not able hold value of eof
, typically -1
.
the skip()
function fails account possibility eof
may encountered. here, if eof
encountered before space, e.g., in last word of file, infinite loop result.
header files
the posted code missing header files. @ least #include <stdio.h>
, #include <stdbool.h>
needed. stdio.h
needed obvious reasons, stdbool.h
needed also, true
, false
macros defined. _bool
type can still used, better use typedef
bool
defined in stdbool.h
.
function declarations
empty parentheses in function prototype indicates unspecified number of arguments. void
must used specify no arguments taken. usage of empty parentheses in function declarators obsolescent feature of language, , should not used anyway.
ansi escape codes
the ability print colors in c dependent upon platform , terminal emulator. tutorials use \e
stand-in escape character, generate character in c should use \x1b
(the ascii hexadecimal value esc character; use \033
, ascii octal value esc). reading of standard \e
not valid character constant, , using generates compiler warning:
warning: non-iso-standard escape sequence, '\e'
but, appear work me in gcc on linux, suspect extension.
logic problems
the skip()
function fails check eof
, fails print spaces when encountered. further, newline character should able precede digit, since signals line-ending. not handling correctly leads failure highlight initial digits on lines following first line of input. these problems can resolved testing eof
, \n
in loop condition, , printing character caused loop terminate if space or newline.
void skip(void) // skip whole words , still print them { putchar(ch); while ((ch = getchar()) != ' ' && ch != '\n' && ch != eof) { printf("%c", ch); } if (ch == ' ' || ch == '\n') { putchar(ch); } }
there similar problem in main()
. when eof
encountered in main loop, final printf()
still executed, printing character when none should printed. 1 solution place statements after eof
test in else
block, though there better solutions.
while (finished) { ch = getchar(); if (ch == eof) { // use eof instead of -1 finished = false; } else { // need avoid printing character eof if ( (ch >= 'a' && ch <= 'z') || (ch >= 'a' && ch <= 'z') ) { skip(); } else if (ch >= '0' && ch <= '9') { color(); } else { printf("%c", ch); } } }
here program far. works expected, far can tell description of expected behavior:
#include <stdio.h> #include <stdbool.h> int ch; bool finished = true; void color(void); void skip(void); int main(void) { while (finished) { ch = getchar(); if (ch == eof) { finished = false; } else { if ( (ch >= 'a' && ch <= 'z') || (ch >= 'a' && ch <= 'z') ) { skip(); } else if (ch >= '0' && ch <= '9') { color(); } else { printf("%c", ch); } } } return 0; } void color(void) // color characters numbers { printf("\x1b[31m%c\x1b[0m", ch); } void skip(void) // skip whole words , still print them { putchar(ch); while ((ch = getchar()) != ' ' && ch != '\n' && ch != eof) { printf("%c", ch); } if (ch == ' ' || ch == '\n') { putchar(ch); } }
improvements
there number of improvements can made code.
there no need bool
@ all. break
statement terminate main loop when eof
encountered. in case, main loop need execute indefinitely, while (1) {}
, or better, for (;;) {}
. better, test ch
in loop condition while ((ch = getchar()) != eof) {}
.
having removed global variable finished
, can make ch
local main()
. may require passing value of ch
both color()
, skip()
, in case function signatures need changed. but, note there no reason pass character skip()
, since character can printed in main()
before calling skip()
. further, there no need color()
function, since one-line function manually inlined.
there no need use printf()
putchar()
do.
it nice #define
couple of escape code macros. easier read, , easier modify.
finally, better use functions in ctype.h
check whether character digit, or alphabetic character, or whitespace character. more portable, , less error-prone, direct comparisons in posted code. using isspace()
in skip()
function, \n
character automatically checked for, avoiding earlier issue forgetting test line-endings. handles other whitespace characters, such \t
. note functions in ctype.h
expect arguments can represented unsigned char
values, cast needed here.
here improved code:
#include <stdio.h> #include <ctype.h> #define red "\x1b[31m" #define reset "\x1b[0m" void skip(void); int main(void) { int ch; while ((ch = getchar()) != eof) { if (isalpha((unsigned char) ch)) { putchar(ch); skip(); } else if (isdigit((unsigned char) ch)) { printf(red "%c" reset, ch); } else { putchar(ch); } } return 0; } void skip(void) // skip whole words , still print them { int c = getchar(); while (!isspace((unsigned char) c) && c != eof) { putchar(c); c = getchar(); } if (isspace((unsigned char) c)) { putchar(c); } }
here sample program output. colors don't show here, have put parentheses around numbers highlighted in red on terminal:
(1) test testing123 (456) test (2) second line test (3) (4) (5) (3)rd line test (4) (5) (6) (789)
Comments
Post a Comment