c - How to use getc() instead of fgets() in my program -
so writing supposed example
info supposed flipped code. empty line above one. would become
to supposed info flipped code. one. above line empty now have function told professor read character character , process line once hit new line. continue onto next line after until eof.
i on other hand have fgets , load whole input/file. deal inside function. on other hand if line longer 80 chars shouldn't process it.
here working code how can convert uses getc() instead of fgets? thanks
void reverser(file *input){ char c[82]; //character size limited per line if(outputflag) fp = freopen(filename, "a+", stdout); while (fgets(c, sizeof c, input)!=null){ int counter =0; int x = 0; while(*(c+x)=='\t' || *(c+x)==space) x++; if(*(c+x) == '\n') continue; char *pcar[80]; int i, n = 0; char *tok = strtok(c, " \t\n"); while (tok != null && n < 80){ *(pcar+n++) = tok; tok = strtok(null, " \t\n"); } for(i = n-1; i>=0; --i){ //counting char length of lines counter+=(int)strlen(*(pcar+i)); if(i) counter++; } if(counter>80){ //throw error if character length > 80 fprintf(stderr, "line long\n"); returnval = 1; continue; } for(i = n-1; i>=0; --i){ printf("%s", *(pcar+i)); if(i) putchar(' '); } printf("\n"); } fclose(input); } i love hints.
this code seems work me, more or less.
source file z.c
#include <stdio.h> #include <string.h> char *read_line(char *buffer, size_t buflen, file *fp); void reverser(file *input); char *read_line(char *buffer, size_t buflen, file *fp) { int c; char *data = buffer; char *end = buffer + buflen - 1; while (data < end && (c = getc(fp)) != '\n') { if (c == eof) { *data = '\0'; return (data == buffer) ? null : buffer; } *data++ = c; } if (data < end) { *data++ = c; *data = '\0'; } else { // overlong line - report error, read , discard eol // or eof, , return empty string (not newline). fprintf(stderr, "line long: discarded!\n"); while ((c = getc(fp)) != eof && c != '\n') ; *buffer = '\0'; } return buffer; } void reverser(file *input) { char c[82]; while (read_line(c, sizeof c, input) != null) { int x = 0; while (c[x] == '\t' || c[x] == ' ') x++; if (c[x] == '\n' || c[x] == '\0') continue; char *pcar[80]; int i, n = 0; char *tok = strtok(c, " \t\n"); while (tok != null && n < 80) { *(pcar + n++) = tok; tok = strtok(null, " \t\n"); } (i = n - 1; >= 0; --i) { printf("%s", *(pcar + i)); if (i) putchar(' '); } printf("\n"); } // fclose(input); // don't close didn't open! } int main(void) { reverser(stdin); return 0; } i made minimal changes in reverser(), removing no longer relevant code, using c[x] in place of *(c + x) because easier type , read, replacing space ' ', removing code reopen standard output, etc.
the program compiles cleanly using:
gcc -wall -wextra -werror z.c -o z (tested on ubuntu 14.04 derivative gcc 5.1.0.)
sample output:$ ./z pedagogical anti-orthodoxy grammatically correct infelicitous nonsense munged catatonic isotopes of prejudice , grunge lead positive recognition of abusive memes in genetic diversity of alphabets. line long: discarded! pedagogical anti-orthodoxy grammatically correct infelicitous nonsense nonsense infelicitous correct grammatically anti-orthodoxy pedagogical munged catatonic isotopes of prejudice , grunge lead lead grunge , prejudice of isotopes catatonic munged positive recognition of abusive memes in genetic diversity of alphabets. alphabets. of diversity genetic in memes abusive of recognition positive $ context answer
originally, there lot of comments associated question, seeking , obtaining elucidation of problem , outlining solutions. comments removed — see mso question. fortunately, browser on developed answer retained comments question overnight. make no claim comments great; make no claim question is/was great; make no claim answer great. agree many of comments jq143 should have been made edits question. assert comments provided necessary context answer , should not have been deleted wholesale.
the comments below not verbatim copies of there; have been curated. couple of comments wildplasser have been omitted.
jonathan leffler commented:
there similar questions on already. why want use
getc()instead offgets()? need process whole lines, reading whole lines makes lot of sense. 1 easy way around write own function, maybechar *read_line(char *buffer, size_t buflen, file *fp)usesgetc()simulatesfgets(). more likely, has in mind you'll usegetc()read characters first word, second, ..., , when hit eol (newline), print out saved words in reverse order, 0 things, , repeat.
i note bluepixy's answer substantially implements "use getc() read word @ time" version of code.
chuckcottrill noted:
the instructor wants demonstrate know how build own
fgets()function usinggetc()function base, or perhaps gather 1 word @ time, pushing words onto stack, , pop them stack , emit them.
jq143 commented (but should ideally have modified question state):
so wants keep adding characters array until hit newline. once hit newline can process array , print them backwards. repeat character starting after old newline... idea how can use
getc()? said should easy fix.@chuckcottrill professor saying
fgetswon't work program. said it'll break, don't see how could.
i noted:
that's proposed
read_line(), existingfgets()does. ignoring buffer overflow checking, that's trivial:char *read_line(char *buffer, size_t buflen, file *fp) { int c; char *data = buffer; while ((c = getc(fp)) != '\n') { if (c == eof) { *data = '\0'; return (data == buffer) ? 0 : buffer; } *data++ = c; } *data++ = c; *data = '\0'; return buffer; }adding buffer overflow checking not difficult, left exercise you. if need ignore lines long, or read , discard excess material if line long, done.
(that code doesn't compile under normal compiler options because buflen not used.)
jq143 responded:
i sorry having hard time figuring out how incorporate program.
to reply was:
change:
while (fgets(c, sizeof c, input)!=null){while (read_line(c, sizeof c, input)!=null){note using name
carray ofcharnot conventional;cdenotes singlecharvariable:char c;.also note code
if(outputflag) fp = freopen(filename, "a+", stdout);makes function logically incohesive. calling code should handle redirection. can either pass output file stream function (sovoid reverser(file *input, file *output)) or arrangestdoutmodifiedfreopen(). function should not accessing global variablesfilename,outputflag.
jxh noted:
see: fgets implementation (k&r); top link of google search.
as how program might fail, if line length
nlonger 80 characters, looks reverse last (n % 81) bytes of line (81 sincesizeof(c)82).
jq143 riposted:
@jxh if line length greater 80. throw stderr saying line long. part of program.
and jxh responded:
you print error, continue loop.
jq143:
@jxh oh..according professor, have process lines less 80 throw error longer.
jxh:
you process remaining lines, yes. but, process rest of long line. if line 100 bytes long, read in 81 bytes of it. when determine line long, print error, , continue. when continue, end reading in 19 more bytes of long line. 100 % 81 19.
jq143:
@jxh right. i'll try fix that.
jq143:
thank you!, upon doing [changing
fgets()read_line()] program went crazy infinite loop.
i countered with:
i compiled code extracted comment (the
read_line()function), , seems work ok long don't have overlong lines. revised version of code is:char *read_line(char *buffer, size_t buflen, file *fp) { int c; char *data = buffer; char *end = buffer + buflen - 1; while (data < end && (c = getc(fp)) != '\n') { if (c == eof) { *data = '\0'; return (data == buffer) ? 0 : buffer; } *data++ = c; } if (data < end) *data++ = c; else ungetc(c, fp); *data = '\0'; return buffer; }
this variant of function leaves data on line read next call function, fgets() does.
jq143:
any hints on how deal lines longer 80 chars?
using variable name, i'd use
char c[4096]; while (read_line(c, sizeof(c), input) != 0) { if (strlen(c) > 80) { fprintf(stderr, "too long @ %zu (line <<%s>>)\n", strlen(c), c); continue; /* or break; */ } ...reading lines 4 kib , processing ones short enough. runs (rather small) risk you'll line of 4150 bytes, , reject first 4095 bytes, process remainder 55 byte line. if that's not acceptable, modify code in
read_line()detect overlong input (passing 82 byte buffer), , have gobble eol or eof when necessary.
this affirming @jxh said behaviour of code when line long, , outlining ways of working around it.
jq143:
@jonathanleffler pretty want throw stderr (just once) if detect sentence longer 80 chars. think reading 80 , not reading rest way. how can in
read_line()instead of doing weird counter stuff in other method? wanna thank helping me. appreciate much.
at point, became possible produce answer; specification sufficiently clear — albeit information should in question rather comments.
chuckcottrill noted:
an interesting variant solution build
readlinefunction increase allocated space (seerealloc) buffer size exhausted...
that's known posix getline().
as chux noted, code not handle buflen of zero. in defence, sizeof(object) never produces 0 in c, have trying run problem. 1 crude modification function be:
assert(*buffer != 0 && buflen != 0 && fp != 0); if (buffer == 0 || buflen == 0 || fp == 0) return 0; the assert enforces correct use in development environment; test simulates eof in production environment , avoids catastrophic misbehaviour @ runtime.
Comments
Post a Comment