Projektowanie programu - przykład

Posłużymy się przykładem programu, który na podstawie pliku tekstowego o postaci:

dowolny tekst
<strona>1</strona>
dowolny tekst
<rozdzial>Wstep</rozdzial>
dowolny tekst
<podrozdzial>Wprowadzenie</podrozdzial>
dowolny tekst
<podpodrozdzial>Oznaczenia</podpodrozdzial>
dowolny tekst
<strona>2</strona>
dowolny tekst
<podpodrozdzial>Założenia</podpodrozdzial>
dowolny tekst
... itd

Tworzy spis treści, np.

1.        Wstep ............................................         1
1.1.      Wprowadzenie .....................................         1
1.1.1.    Oznaczenia .......................................         1
1.1.2.    Założenia ........................................         2

Podzielimy program na trzy moduły:

Opracujemy pierwsze przybliżenie rozwiązania (kod można ściągnąć z http://www.iem.pw.edu.pl/~jstar/dyd/w_jimp2/2004-2005/r1.tgz) i stwierdzimy, że nie jest to kod idealny.

Zadanie domowe po pierwszych zajęciach: zastanowić się nad tym, co jest w tym kodzie zrobione źle.

Na kolejnym wykładzie zastanowimy się nad poprawieniem kodu. Stwierdzimy, że podstawowe błędy to:

Poprawiona wersja kodu to http://www.iem.pw.edu.pl/~jstar/dyd/w_jimp2/2004-2005/r2.tgz.

Następnie zbadamy, czy nie możnaby zrobić funkcji formatującej wyjście zgodnie z formatem zadanym przez użytkownika, w linii polecenia. W wyniku pierwszych eksperymantów pojawia się problem, który ilustruje zamieszczony poniżej prosty programik:

   1 #include <stdio.h>
   2 
   3 /*
   4 Potraktuj pierwszy argument jako format sluzacy
   5 do wypisania na stderr kolejnych argumentow (traktowanych jako napisy)
   6 */
   7 
   8 /* Uwaga: program jest zly - nie dziala, jak oczekujemy */
   9 
  10 int main( int argc, char **argv ) {
  11   int i;
  12   if( argc > 2 ) {
  13     for( i= 2; i < argc; i++ )
  14       fprintf( stderr, argv[1], argv[i] );
  15     fprintf( stderr, "\n---\n" );
  16     return 0;
  17   }
  18   return 1;
  19 }

Problem polega na tym, że program nie działa tak, jak moglibyśmy oczekiwać. Przykladowe jego wywołanie może wyglądać tak:

oer:~/jimp2/format> ./f "%s\n" ala ma kota
ala\nma\nkota\n

Widać, że program nie zmienia linii po wypisaniu kolejnych argumentów, ale wypisuje między nimi po prostu literalnie napis "\n".

W domu powinni się Państwo zastanowić, dlaczego tak jest i jak to poprawić.

Na kolejnych zajęciach pokazaliśmy, na czym problem polega i zaproponowaliśmy rozwiązanie:

   1 #include <stdio.h>
   2 
   3 /*
   4 Potraktuj pierwszy argument jako format sluzacy
   5 do wypisania na stderr kolejnych argumentow (traktowanych jako napisy)
   6 */
   7 
   8 char *
   9 specchartr (char *s)
  10 {
  11   char *pi = s;
  12   char *po = s;
  13 
  14 #ifdef DEBUG
  15   fprintf( stderr, "s=<%s>\n", s );
  16 #endif
  17 
  18   while (*pi) {
  19     if (*pi == '\\') {
  20       switch (*(pi + 1)) {
  21       case 'n':
  22         *po++ = '\n';
  23         pi += 2;
  24         break;
  25       case 't':
  26         *po++ = '\t';
  27         pi += 2;
  28         break;
  29       case 'v':
  30         *po++ = '\v';
  31         pi += 2;
  32         break;
  33       case 'b':
  34         *po++ = '\b';
  35         pi += 2;
  36         break;
  37       case 'r':
  38         *po++ = '\r';
  39         pi += 2;
  40         break;
  41       case 'f':
  42         *po++ = '\f';
  43         pi += 2;
  44         break;
  45       case 'a':
  46         *po++ = '\a';
  47         pi += 2;
  48         break;
  49       case '\\':
  50         *po++ = '\\';
  51         pi += 2;
  52         break;
  53       case '?':
  54         *po++ = '\?';
  55         pi += 2;
  56         break;
  57       case '\'':
  58         *po++ = '\'';
  59         pi += 2;
  60         break;
  61       case '"':
  62         *po++ = '\"';
  63         pi += 2;
  64         break;
  65       default:
  66         *po++ = *pi++;
  67         break;
  68       }
  69     }
  70     else {
  71       *po++ = *pi++;
  72     }
  73   }
  74   *po++ = *pi++;
  75 
  76 #ifdef DEBUG
  77   fprintf( stderr, "s=<%s>\n", s );
  78 #endif
  79 
  80   return s;
  81 }
  82 
  83 /* Test: traktujemy pierwszy argument wywołania jako format
  84    do wypisania kolejnych argumentów
  85 */
  86 
  87 int
  88 main (int argc, char **argv)
  89 {
  90   int i;
  91   if (argc > 2) {
  92     specchartr( argv[1] );
  93     for (i = 2; i < argc; i++)
  94       fprintf (stderr, argv[1], argv[i]);
  95     fprintf (stderr, "\n");
  96     return 0;
  97   }
  98   return 1;
  99 }

Poprawimy też trochę nasz projekt, wykorzystując wyrażenia regularne. Ostateczna wersja jest w archiwum http://www.iem.pw.edu.pl/~jstar/dyd/w_jimp2/2004-2005/rozdzialy.tgz

wikidyd - IETiSIP, Wydzial Elektryczny Politechniki Warszawskiej: Jimp1/ProgramowanieProceduralne2 (last edited 2007-03-21 11:36:25 by JacekStarzyński)