Like Tree13Likes

A development process

This is a discussion on A development process within the C Programming forums, part of the General Programming Boards category; Here's a development process I like to use. I'll use a program that counts letters, digits, punctuation, and whitespace in ...

  1. #1
    Registered User Noir's Avatar
    Join Date
    Mar 2007
    Posts
    218

    A development process

    Here's a development process I like to use. I'll use a program that counts letters, digits, punctuation, and whitespace in a file as an example. This was an answer to a question, but I was asked to turn it into a thread for reference. This time I'll use color keys too. Blue means new code, Red means code that replaces other code, and Green means code that hasn't changed but has moved.


    1 - Start with a skeleton program:
    Code:
    #include <stdio.h>
    
    
    int main( void ) {
      return 0;
    }
    2 - The big thing for this program is the source of the input, so I open and print a test file to make sure that everything works:
    Code:
    #include <stdio.h>
    
    
    int main( void ) {
      FILE *fp = fopen( "test.txt", "r" );
    
      if ( fp ) {
        int ch;
    
        while ( ( ch = fgetc( fp ) ) != EOF ) {
          fputc( ch, stdout );
        }
    
        fclose( fp );
      } else {
        perror( "error opening the file" );
      }
    
      return 0;
    }
    3 - Okay, the file opens and the program reads it like I think I want. Now I'll count all of the characters and compare that with the actual file to see if it's accurate:
    Code:
    #include <stdio.h>
    
    
    int main( void ) {
      FILE *fp = fopen( "test.txt", "r" );
    
      if ( fp ) {
        int ch;
        int n = 0;
    
        while ( ( ch = fgetc( fp ) ) != EOF ) {
          ++n;
        }
    
        printf( "total characters: %d\n", n );
        fclose( fp );
      } else {
        perror( "error opening the file" );
      }
    
      return 0;
    }
    4 - Now I'm sure that the file is being input the way I want, so I can start counting character types one at a time, checking each time that the count is right on a test file:
    Code:
    #include <stdio.h>
    #include <ctype.h>
    
    
    int main( void ) {
      FILE *fp = fopen( "test.txt", "r" );
    
      if ( fp ) {
        int ch;
        int nalpha = 0;
        int ndigit = 0;
        int npunct = 0;
        int nspace = 0;
    
        while ( ( ch = fgetc( fp ) ) != EOF ) {
          if ( isalpha( ch ) ) {
            ++nalpha;
          } else if ( isdigit( ch ) ) {
            ++ndigit;
          } else if ( ispunct( ch ) ) {
            ++npunct;
          } else if ( isspace( ch ) ) {
            ++nspace;
          }
        }
    
        printf( "alphabetic characters: %d\n", nalpha );
        printf( "digit characters: %d\n", ndigit );
        printf( "punctuation characters: %d\n", npunct );
        printf( "whitespace characters: %d\n", nspace );
        fclose( fp );
      } else {
        perror( "error opening the file" );
      }
    
      return 0;
    }
    5 - Testing is done on producing the output, but the file is still hard coded, and I want the user to pass a file to the program. main is getting kind of long, so I'll refactor the counting code out into a function and test it all again to make sure it still works. Any change, even something tiny, means retesting. Refactoring doesn't change the logic at all, it just restructures the program so that it's easier to manage but still works exactly the same:
    Code:
    #include <stdio.h>
    #include <ctype.h>
    
    
    void process_file( FILE *fp );
    
    
    int main( void ) {
      FILE *fp = fopen( "test.txt", "r" );
    
      if ( fp ) {
        process_file( fp );
        fclose( fp );
      } else {
        perror( "error opening the file" );
      }
    
      return 0;
    }
    
    
    void process_file( FILE *fp ) {
      int ch;
      int nalpha = 0;
      int ndigit = 0;
      int npunct = 0;
      int nspace = 0;
    
      while ( ( ch = fgetc( fp ) ) != EOF ) {
        if ( isalpha( ch ) ) {
          ++nalpha;
        } else if ( isdigit( ch ) ) {
          ++ndigit;
        } else if ( ispunct( ch ) ) {
          ++npunct;
        } else if ( isspace( ch ) ) {
          ++nspace;
        }
      }
    
      printf( "alphabetic characters: %d\n", nalpha );
      printf( "digit characters: %d\n", ndigit );
      printf( "punctuation characters: %d\n", npunct );
      printf( "whitespace characters: %d\n", nspace );
    }
    6 - Now I can add the argument stuff for taking a file as a command line parameter without cluttering main up too much. I make sure my tests touch every code path, so I'll fake error and stuff to make sure that the error cases work like I want:
    Code:
    #include <stdio.h>
    #include <ctype.h>
    
    
    void process_file( FILE *fp );
    
    
    int main( int argc, char *argv[] ) {
      if ( argc > 1 ) {
        FILE *fp = fopen( argv[1], "r" );
    
        if ( fp ) {
          process_file( fp );
          fclose( fp );
        } else {
          perror( "error opening the file" );
        }
      } else {
        fprintf( stderr, "usage: prog <filename>\n" );
      }
    
      return 0;
    }
    
    
    void process_file( FILE *fp ) {
      int ch;
      int nalpha = 0;
      int ndigit = 0;
      int npunct = 0;
      int nspace = 0;
    
      while ( ( ch = fgetc( fp ) ) != EOF ) {
        if ( isalpha( ch ) ) {
          ++nalpha;
        } else if ( isdigit( ch ) ) {
          ++ndigit;
        } else if ( ispunct( ch ) ) {
          ++npunct;
        } else if ( isspace( ch ) ) {
          ++nspace;
        }
      }
    
      printf( "alphabetic characters: %d\n", nalpha );
      printf( "digit characters: %d\n", ndigit );
      printf( "punctuation characters: %d\n", npunct );
      printf( "whitespace characters: %d\n", nspace );
    }
    7 - Now I can really crank down on the stability of the code by adding defensive cases:
    Code:
    #include <stdio.h>
    #include <ctype.h>
    
    
    int process_file( FILE *fp );
    
    
    int main( int argc, char *argv[] ) {
      if ( argc > 1 ) {
        FILE *fp = fopen( argv[1], "r" );
    
        if ( fp ) {
          if ( !process_file( fp ) ) {
            perror( "error reading from the file" );
          }
    
          fclose( fp );
        } else {
          perror( "error opening the file" );
        }
      } else {
        fprintf( stderr, "usage: prog <filename>\n" );
      }
    
      return 0;
    }
    
    
    int process_file( FILE *fp ) {
      int ch;
      int nalpha = 0;
      int ndigit = 0;
      int npunct = 0;
      int nspace = 0;
      int rc = 0;
    
      if ( fp != NULL ) {
        while ( ( ch = fgetc( fp ) ) != EOF ) {
          if ( isalpha( ch ) ) {
            ++nalpha;
          } else if ( isdigit( ch ) ) {
            ++ndigit;
          } else if ( ispunct( ch ) ) {
            ++npunct;
          } else if ( isspace( ch ) ) {
            ++nspace;
          }
        }
    
        if ( !ferror( fp ) ) {
          printf( "alphabetic characters: %d\n", nalpha );
          printf( "digit characters: %d\n", ndigit );
          printf( "punctuation characters: %d\n", npunct );
          printf( "whitespace characters: %d\n", nspace );
          rc = 1;
        }
      }
    
      return rc;
    }
    8 - Now the code is solid, but there aren't any comments, so I'll go through it and add comments to places that might be confusing and then call it a day. There aren't many because this is a pretty simple program:
    Code:
    /*
      File - prog.c
      Author - D. Burke (Noir)
      
      Count alphabetic, digit, punctuation, and
      whitespace characters in a user supplied file
    */
    #include <stdio.h>
    #include <ctype.h>
    
    
    int process_file( FILE *fp );
    
    
    int main( int argc, char *argv[] ) {
      if ( argc > 1 ) {
        FILE *fp = fopen( argv[1], "r" );
    
        if ( fp ) {
          if ( !process_file( fp ) ) {
            // failure means a stream error or bad file
            perror( "error reading from the file" );
          }
    
          fclose( fp );
        } else {
          perror( "error opening the file" );
        }
      } else {
        fprintf( stderr, "usage: prog <filename>\n" );
      }
    
      return 0;
    }
    
    
    int process_file( FILE *fp ) {
      int ch;
      int nalpha = 0;
      int ndigit = 0;
      int npunct = 0;
      int nspace = 0;
    
      // assume failure
      int rc = 0;
    
      if ( fp != NULL ) {
        while ( ( ch = fgetc( fp ) ) != EOF ) {
          if ( isalpha( ch ) ) {
            ++nalpha;
          } else if ( isdigit( ch ) ) {
            ++ndigit;
          } else if ( ispunct( ch ) ) {
            ++npunct;
          } else if ( isspace( ch ) ) {
            ++nspace;
          }
        }
    
        if ( !ferror( fp ) ) {
          // only produce output if there are no errors
          printf( "alphabetic characters: %d\n", nalpha );
          printf( "digit characters: %d\n", ndigit );
          printf( "punctuation characters: %d\n", npunct );
          printf( "whitespace characters: %d\n", nspace );
          rc = 1;
        }
      }
    
      return rc;
    }
    That's how you should do it too. Start with a skeleton and build the program up bit by bit, making sure to test after every change. It's okay to change the requirements for testing like when I counted all the characters in the file or just printed the file out. It's okay to backtrack and change your mind on stuff too like when I decided to factor the counting code into a function. It's not as much building a program from a blueprint as it is evolving a program from an idea. You get to change your mind and make it better along the way even after you've finished doing it another way.

  2. #2
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,437
    Thanks for that Noir
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  3. #3
    Registered User
    Join Date
    Apr 2007
    Posts
    1
    ^_^
    Perfact! Thank you for the steps of programming1

  4. #4
    Registered User
    Join Date
    May 2007
    Posts
    11
    thanks for the tips

  5. #5
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582
    Wouldn't you normally comment as you code along rather than at the end? Take something that needs, say, 500 lines. It'd be much easier to comment as you go along then it would after writing all that.

    What I generally do is add little bits to the code at a time and test it fixing any bugs I find. Once the bugs have been fixed, I add a little more and keep repeating this. The same would apply if modifying a part of the code.
    Debojyoti Das likes this.
    High elevation is the best elevation. The higher, the better the view!
    My computer: XP Pro SP3, 3.4 GHz i7-2600K CPU (OC'd to 4 GHz), 4 GB DDR3 RAM, X-Fi Platinum sound, GeForce 460, 1920x1440 resolution, 1250 GB HDD space, Visual C++ 2008 Express

  6. #6
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,796
    >Wouldn't you normally comment as you code along rather than at the end?
    It depends on how much you tweak and how abstract your comments are. I try to write stub code using relatively abstract comments, then after filling in the code I'll usually replace the stubs with something more appropriate. However, if I'm confident that I can keep all of the code in my mind at once, I'll work on it directly and add comments when it's at a more finalized stage. Note that all of this assumes at most a day's time. Very rarely do I add comments as I go unless they're useful to me during that day's work, but the comments are always there when I go home.
    My best code is written with the delete key.

  7. #7
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,235
    Quote Originally Posted by ulillillia View Post
    Wouldn't you normally comment as you code along rather than at the end? Take something that needs, say, 500 lines. It'd be much easier to comment as you go along then it would after writing all that.
    I typically write comments before writing the code that does what the comment says. Only in work code, though. Personal code is pretty much uncommented -- if I feel the need to comment, I resist the urge and instead rework the code so that it no longer requires comments.

  8. #8
    Java and C newbie Xero's Avatar
    Join Date
    Aug 2006
    Location
    Philippines
    Posts
    21
    Very nice reference, informative and beginner friendly.
    Code:
    Noob - a word used to describe someone like me. (noun)

  9. #9
    Registered User divineleft's Avatar
    Join Date
    Jul 2006
    Posts
    158
    yes, good thread noir! thanks for writing this.
    Gentoo Linux - 2.6.22.1
    GCC version 4.2.0

  10. #10
    Registered User
    Join Date
    Jul 2006
    Posts
    162
    You know what I do differently? It's step one.
    I have 4-6 projects that are the "bare min" for that project type which I created, whether it's openGL, audio processing, math related, each project type has the appropriate libraries and init code to get it going. Then I start.

    Because you can't really just start a 3d modeling application from that intro... it's just insane. It helps to define the beginning of a project over time by also including the base components to get it off the ground.
    Like the init OpenGL app in new dev-c++ projects for glut is spinning shapes... that's** a starting point.
    create those kinds of projects to start any other project, a better first stepping stone.


    and NO programmer (no >= decent programmer anyway) comments as they code, /laugh, that's just stupid. your code changes constantly until it's done! think about it! I mean unless you enjoy re-writing and changing comments 90&#37; of the time go ahead! W00t! comment when you're finished.

    what you should have taught people, is how to PLAN your project conceptually, to know ahead of time how to begin the project by doing research in to what it is your making.
    then pick the appropriate project type (which you'll have to learn how to make, install, or w/e...) and then...
    how then to implement concepts.
    the development process also incorporates source control, methods for multiple people working on one projects, the understanding of standards, etc. JUST SAYING! i know that's out of scope for this... just so everyone's aware though.
    planning is important because there's different kinds of input, in various formats, you have to know what you're accepting and how.... there's so much more to this, why aren't you programmers being honest. Stop being nice... that's stupid.

    i'm just going to get negative reactions but this is more just "how to build a simple program."


    don't hate me, but honestly.... this isn't about a development process, it's just a tutorial for starters.
    Last edited by simpleid; 08-14-2007 at 05:24 PM.

  11. #11
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,211
    Quote Originally Posted by simpleid View Post
    and NO programmer (no >= decent programmer anyway) comments as they code, /laugh, that's just stupid. your code changes constantly until it's done! think about it! I mean unless you enjoy re-writing and changing comments 90&#37; of the time go ahead! W00t! comment when you're finished.
    I comment as I code for things that I know could be misinterpreted at a first glance, or things that are really important to know. If I have a lot of variables, I might section them off and comment each section as to what they are used for. Usually these comments are no longer than a few words.

    If a function that does something extremely important requires something to be done before or after it's called, then I might explain my reasoning in a longer multi-line comment. Otherwise, I try to keep my function and variable names as logical and descriptive as possible so most commenting is unneeded.

    I think your statements regarding this are too broadsweeping and vague.

  12. #12
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    Quote Originally Posted by simpleid
    You know what I do differently? It's step one.
    I have 4-6 projects that are the "bare min" for that project type which I created, whether it's openGL, audio processing, math related, each project type has the appropriate libraries and init code to get it going. Then I start.

    Because you can't really just start a 3d modeling application from that intro... it's just insane. It helps to define the beginning of a project over time by also including the base components to get it off the ground.
    Like the init OpenGL app in new dev-c++ projects for glut is spinning shapes... that's** a starting point.
    create those kinds of projects to start any other project, a better first stepping stone.
    Noir was creating a whitespace counting program just as an example. I don't think [s]he was implying that they or anyone else should start all programs in that way.

    Besides, I think you missed the point of the post. After you have a template, do you program in much the same way?
    Quote Originally Posted by Noir
    That's how you should do it too. Start with a skeleton and build the program up bit by bit, making sure to test after every change. It's okay to change the requirements for testing like when I counted all the characters in the file or just printed the file out. It's okay to backtrack and change your mind on stuff too like when I decided to factor the counting code into a function. It's not as much building a program from a blueprint as it is evolving a program from an idea. You get to change your mind and make it better along the way even after you've finished doing it another way.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  13. #13
    Registered User
    Join Date
    Jul 2006
    Posts
    162
    MacGyver, me too but! most of the code I write that can be misinterpreted I end up re-writing anyway, so it's still futile to comment until the end when the project is in a state to remain static for a short while (at least), otherwise you have to go back re-edit, re-explain and just toy with it until you are actually done... but maybe it's a matter of opinion and experience so I'll accept I could be wrong on that front. if there is a wrong indeed.

    dwks, i might have missed the point, i'm used to a different environment where terms like "a development process" imply 100 other things 'along the road.' i think a lot more could have been said, and if that's too much for a beginning than maybe it's not a beginner tutorial. :-)

    i guess what i'm trying to express is, it feels like "10 chars are being forced in to a 5 char array...." and i would prefer that anyone who reads this tutorial is made aware that there is in reality more to it by reading these comments... :-)
    Last edited by simpleid; 08-14-2007 at 10:42 PM.

  14. #14
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,437
    The whole point of this tutorial is to show to those noobs who think they can write several hundred line programs right off the bat, but instead end up with several hundred error messages and they then post the whole mess on a message board for someone else to fix.

    The essence being small steps with measured progress.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  15. #15
    mog
    mog is offline
    Sasquatch mog's Avatar
    Join Date
    Dec 2006
    Location
    Caves of Narshe
    Posts
    16
    I think that when you reach a certain level of experience you know what to do and what not to do.
    So in a beginners point of view i think this is a good example, and the main point that i see is

    1. Write one line
    2. Compile
    3. Fix error(s)
    4. Write another line

    Instead of copy - paste 200 lines and then wonder why nothing is working..

    Also i suggest anyone to maybe start with more highlevel languages such as PHP (which has similar syntax and function-names as C), just to get the big picture.
    Last edited by mog; 08-15-2007 at 06:45 AM.

Page 1 of 3 123 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. init adopts zombie process?
    By password636 in forum Linux Programming
    Replies: 4
    Last Post: 07-01-2009, 10:05 AM
  2. Replies: 3
    Last Post: 10-15-2008, 09:24 AM
  3. Problem with forking a process
    By Unitedroad in forum C Programming
    Replies: 10
    Last Post: 10-04-2007, 01:43 AM
  4. process programming
    By St0rM-MaN in forum Linux Programming
    Replies: 2
    Last Post: 09-15-2007, 07:53 AM
  5. Happiest moment during development process....
    By Nutshell in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 04-02-2002, 10:40 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21