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 of fgets()? need process whole lines, reading whole lines makes lot of sense. 1 easy way around write own function, maybe char *read_line(char *buffer, size_t buflen, file *fp) uses getc() simulates fgets(). more likely, has in mind you'll use getc() 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 using getc() 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 fgets won't work program. said it'll break, don't see how could.

i noted:

that's proposed read_line() , existing fgets() 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 c array of char not conventional; c denotes single char variable: 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 (so void reverser(file *input, file *output)) or arrange stdout modified freopen(). function should not accessing global variables filename , outputflag.


jxh noted:

see: fgets implementation (k&r); top link of google search.

as how program might fail, if line length n longer 80 characters, looks reverse last (n % 81) bytes of line (81 since sizeof(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 readline function increase allocated space (see realloc) 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

Popular posts from this blog

java - Spring Data JPA: Why findOne(id) executing delete query internally? -

python - Mongodb How to add addtional information when aggregating? -

java - Incorrect order of records in M-M relationship in hibernate -