鱼C论坛

 找回密码
 立即注册
查看: 2567|回复: 3

[技术交流] A development process

[复制链接]
发表于 2011-8-2 16:13:53 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
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;

}



想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-8-3 09:09:48 | 显示全部楼层
嗯,不错,这种步步为营的方式比较适合新手,用这种方式比较容易构建出复杂的程序。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2011-8-3 10:06:44 | 显示全部楼层
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);
                                                                                                                                                                29,1-8       顶端
    }

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, ** 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.

                               
登录/注册后可看大图

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2013-7-2 16:49:52 | 显示全部楼层
看帖,就必须回帖
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-6-11 14:13

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表