C Board  

Go Back   C Board > General Programming Boards > C Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 04-10-2007, 12:23 PM   #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.
Noir is offline   Reply With Quote
Old 04-10-2007, 01:35 PM   #2
and the hat of vanishing
 
Salem's Avatar
 
Join Date: Aug 2001
Location: The edge of the known universe
Posts: 21,214
Thanks for that Noir
__________________
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
Up to 8Mb PlusNet broadband from only £5.99 a month!
Salem is offline   Reply With Quote
Old 05-17-2007, 01:03 AM   #3
Registered User
 
Join Date: Apr 2007
Posts: 1
^_^
Perfact! Thank you for the steps of programming1
fantasy.lion is offline   Reply With Quote
Old 05-29-2007, 11:50 PM   #4
Registered User
 
Join Date: May 2007
Posts: 11
thanks for the tips
kky2k is offline   Reply With Quote
Old 05-30-2007, 12:49 PM   #5
Math wizard
 
Join Date: Dec 2006
Location: Minot, ND, USA
Posts: 516
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.
__________________
High elevation is the best elevation. The higher, the better the view!
My computer: XP Pro SP3, 3.17 GHz C2D CPU, 4 GB DDRII800 RAM (3 GB effective), X-Fi Platinum sound, GeForce 7600 GT, 1920x1440 resolution, 250 GB HDD, Visual C++ 2008 Express
ulillillia is offline   Reply With Quote
Old 05-30-2007, 02:52 PM   #6
Code Goddess
 
Prelude's Avatar
 
Join Date: Sep 2001
Posts: 9,661
>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.
Prelude is offline   Reply With Quote
Old 05-30-2007, 03:39 PM   #7
Senior software engineer
 
brewbuck's Avatar
 
Join Date: Mar 2007
Location: Portland, OR
Posts: 5,381
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.
brewbuck is online now   Reply With Quote
Old 07-03-2007, 07:41 AM   #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)
Xero is offline   Reply With Quote
Old 07-20-2007, 05:44 PM   #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
divineleft is offline   Reply With Quote
Old 08-14-2007, 05:11 PM   #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% 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.
simpleid is offline   Reply With Quote
Old 08-14-2007, 05:32 PM   #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% 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.
__________________
MacGyver is offline   Reply With Quote
Old 08-14-2007, 05:45 PM   #12
Frequently Quite Prolix
 
dwks's Avatar
 
Join Date: Apr 2005
Location: Canada
Posts: 7,629
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, etc.

New project: nort
dwks is offline   Reply With Quote
Old 08-14-2007, 10:38 PM   #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.
simpleid is offline   Reply With Quote
Old 08-14-2007, 11:51 PM   #14
and the hat of vanishing
 
Salem's Avatar
 
Join Date: Aug 2001
Location: The edge of the known universe
Posts: 21,214
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.
Up to 8Mb PlusNet broadband from only £5.99 a month!
Salem is offline   Reply With Quote
Old 08-15-2007, 06:40 AM   #15
mog
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.
mog is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
init adopts zombie process? password636 Linux Programming 4 07-01-2009 10:05 AM
How can you make a parent process wait for a child? I'm gettin a seg fault. mr_coffee C Programming 3 10-15-2008 09:24 AM
Problem with forking a process Unitedroad C Programming 10 10-04-2007 01:43 AM
process programming St0rM-MaN Linux Programming 2 09-15-2007 07:53 AM
Happiest moment during development process.... Nutshell A Brief History of Cprogramming.com 16 04-02-2002 11:40 AM


All times are GMT -6. The time now is 09:05 PM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.0 RC2

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