[WikiDyd] [TitleIndex] [WordIndex

Jimp1/Przykłady 2007

Wykład 11

Zajmowaliśmy się strukturą opisującą macierz dwuwymiarową przechowywaną w postaci wektora wskaźników na wiersze.

   1 typedef struct {
   2   int lw, lk;   /* liczba wierszy i kolumn */
   3   double ** w;  / * wskaźniki na wiersze */
   4 } mati_t;

Pisaliśmy funkcje czytające i wypisujące taka macierz.

   1 #ifndef _MATI_H_IS_INCLUDED_
   2 #define _MATI_H_IS_INCLUDED_
   3 
   4 #include <stdio.h>
   5 
   6 typedef struct {
   7   int lw, lk;
   8   double ** w;
   9 } mati_t;
  10 
  11 mati_t *new_mati( int lw, int lk );
  12 
  13 void free_mati( mati_t * );
  14 
  15 mati_t *read_mati( FILE * );
  16 
  17 void print_mati( mati_t *, FILE * );
  18 
  19 mati_t * solve( mati_t *, mati_t * );
  20 
  21 #endif
  22 

Rozmawialismy o allokacji pamięci na elementy macierzy.

Można albo wierszami:

   1   for( i= 0; i < lw; i++ )
   2     n->w[i] = malloc( lk * sizeof * n->w[i] );

Mozna wszystko na raz i odpowiednio poustawiac wskaźniki:

   1   n->w[0] = malloc( lw*lk * sizeof * n->w[0] );
   2   for( i= 1; i < lw; i++ )
   3     n->w[i] = n->w[i-1]+lk;

Mówilismy też o potrzebie porzadkowania kodu (refaktoryzacji), o błędzie, jakim jest powielanie tego samego, albo bardzo podobnego kodu robiacego to samo. Ostatecznie doszliśmy do takiej postaci funkci działających na macierzy:

   1 #include "mati.h"
   2 #include <stdlib.h>
   3 
   4 mati_t * new_mati( int lw, int lk ) {
   5   int i, j;
   6   mati_t *n;
   7 
   8   if( lk <= 0 || lw <= 0 )
   9     return NULL;
  10 
  11   if( (n= malloc( sizeof *n )) == NULL )
  12     return NULL;
  13 
  14   n->w = malloc( lw * sizeof * n->w );
  15   if( n->w == NULL ) {
  16     free( n );
  17     return NULL;
  18   }
  19 
  20   if( (n->w[0] = malloc( lw*lk * sizeof * n->w[0] )) == NULL ) {
  21     free( n->w );
  22     free( n );
  23   }
  24 
  25   for( i= 1; i < lw; i++ )
  26     n->w[i] = n->w[i-1]+lk;
  27 
  28   for( i= 0; i < lw; i++ )
  29     for( j= 0; j < lk; j++ )
  30       n->w[i][j] = 0;
  31 
  32   n->lw = lw;
  33   n->lk = lk;
  34 
  35   return n;
  36 }
  37 
  38 void free_mati( mati_t * m ) {
  39   free( m->w[0] );
  40   free( m->w );
  41   free( m );
  42 }
  43 
  44 mati_t * read_mati( FILE * input )
  45 {
  46   mati_t * n;
  47   int lw, lk;
  48   int i,j;
  49 
  50   if( fscanf( input, "%dx%d", &lw, &lk ) != 2 || lw <= 0 || lk <= 0 ) {
  51     return NULL;
  52   }
  53 
  54   if( (n = new_mati( lw, lk )) == NULL ) {
  55     return NULL;
  56   }
  57 
  58   for( i= 0; i < lw; i++ )
  59     for( j= 0; j < lk; j++ )
  60       if( fscanf( input, "%lf", &(n->w[i][j]) ) != 1 ) {
  61         free_mati( n );
  62         return NULL;
  63       }
  64 
  65   n->lw = lw;
  66   n->lk = lk;
  67 
  68   return n;
  69 }
  70 
  71 void print_mati( mati_t * m, FILE *out )
  72 {
  73   int i,j;
  74 
  75   fprintf( out, "%dx%d\n", m->lw, m->lk );
  76   for( i= 0; i < m->lw; i++ ) {
  77     for( j= 0; j < m->lk; j++ )
  78       fprintf( out, " %g", m->w[i][j] );
  79     fprintf( out, "\n" );
  80   }
  81 }

Program testujący te funkcje:

   1 #include "mati.h"
   2 
   3 int
   4 main( int argc, char **argv )
   5 {
   6   FILE *in = argc > 1 ? fopen( argv[1], "r" ) : stdin;
   7 
   8   mati_t * m1 = new_mati( 2, 3 );
   9 
  10   print_mati( m1, stdout );
  11 
  12   free_mati( m1 );
  13 
  14   m1 = read_mati( in );
  15 
  16   if( m1 != NULL )
  17     print_mati( m1, stdout );
  18   else
  19     fprintf( stderr, "Zla zawartosc pliku %s\n", argv[1] );
  20 
  21   return 0;
  22 }

Przy testowaniu działania funkcji posłużyliśmy się debuggerem gdb. Pokazaliśmy opcję kompilatora (-g), która powoduje wygenerowanie kodu wraz z symboliczną informacja wykorzystywaną przez debugger. Pokazywaliśmy jak uruchomić program pod kontrolą debuggera (instrukcje dbg: run, break, n, p):

lap-jk:~/dydaktyka/c/struktury_danych/v_t> cc -Wall -g test_mati.c mati.c
lap-jk:~/dydaktyka/c/struktury_danych/v_t> gdb a.out 
GNU gdb 6.6-debian
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) break read_mati
Breakpoint 1 at 0x8048786: file mati.c, line 50.
(gdb) run test1
Starting program: /home/jstar/dydaktyka/c/struktury_danych/v_t/a.out test1
2x3
 0 0 0
 0 0 0

Breakpoint 1, read_mati (input=0x804a008) at mati.c:50
50              if( fscanf( input, "%dx%d", &lw, &lk ) != 2 || lw <= 0 || lk <= 0 ) {
(gdb) n
54        if( (n = new_mati( lw, lk )) == NULL ) {
(gdb) p lw
$1 = 3
(gdb) p lk
$2 = 4

Więcej o gdb: http://students.mimuw.edu.pl/SO/Projekt05-06/temat3-g5/gdb/gdb.html http://sourceware.org/gdb/documentation/.

Na koniec zajęliśmy się programem rozwiązującym układ równań liniowych A x = b.

Przygotowaliśmy plik testowy:

2x2
1 2
3 4
2x1
1
1

i napisalismy program

   1 #include "mati.h"
   2 
   3 int
   4 main( int argc, char ** argv ) {
   5 
   6   FILE *in = argc > 1 ? fopen( argv[1], "r" ) : stdin;
   7   mati_t * A;
   8   mati_t * b;
   9   mati_t * x;
  10 
  11   if( (A= read_mati( in )) == NULL )
  12     return 1;
  13 
  14   if( (b= read_mati( in )) == NULL )
  15     return 2;
  16 
  17   x = solve( A, b );
  18 
  19   if( x != NULL )
  20     print_mati( x, stdout );
  21   else
  22     fprintf( stderr, "Blad!\n" );
  23 
  24   return 0;
  25 }

Do szczęścia brakuje nam tylko funkcji solwe, która na poczatek napisaliśmy tak:

   1 mati_t * solve( mati_t * A, mati_t * b )
   2 {
   3   if( A->lw == A->lk && A->lw == b->lw ) {
   4     return new_mati( b->lw, 1 );
   5   } else
   6     return 0;
   7 }

Pozwala to przetestować program, ale nie działa, jak należy.

Zadanie domowe to napisanie i uruchomienie f. solve realizującej algorytm eliminacji Gaussa. Troszkę już zrobiłem, trzeba uzupełnic, poprawić i uruchomić (to znaczy przetestować na kilku zestawach danych!):

   1 mati_t * solve( mati_t * A, mati_t * b )
   2 {
   3   if( A->lw == A->lk && A->lw == b->lw ) {
   4     mati_t *x = new_mati( b->lw, 1 ); /* miejsce na rozwiązanie */
   5     /* LU */
   6     int k,i,j;
   7     /* Petla zerująca poddiagonalne częsci kolumn k=0...lw-1 (pamietamy o indeksowaniu od 0) */
   8     for( k= 0; k < A->lw; k++ ) {
   9       /* wyznaczamy dzielnik - jest to element diagonalny (k,k) */
  10       double d= A->w[k][k];
  11       /* Pętla po wierszach */
  12       for( i= k+1; i < A->lw; i++ ) {
  13         /* wyznaczamy mnoznik - początkową wartośc elemetu (i,k) podzielona przez d */
  14         double m = A->w[i][k] / d;
  15         /* nowa wartość elementu A(i,k) to 0 */
  16         /* Pętla modyfikująca elementy i-tego wiersza - wystarczy modyfikowac od kolumny k+1 */
  17         for( j= k+1; j < A->lk; j++ )
  18           A->w[i][j]= /* tutaj już Państwo ;-) */
  19         /* modyfikujemy prawe strony */
  20         b->w[i][0] = /* Panstwo */
  21       }
  22     }
  23     /* Tu powinnismy miec macierz górna trójkatna */
  24     print_mati( A, stderr );
  25 
  26     /* teraz podstawienie wstecz */
  27     for( i= b->lw-1; i >= 0; i-- ) {
  28       x->w[i][0] = b->w[i][0];
  29       for( j= b->lw-1; j > i; j-- )
  30         x->w[i][0] -= x->w[j][0]*A->w[i][j];
  31       x->w[i][0] /= A->w[i][i];
  32     }
  33     return x;
  34   } else
  35     return 0;
  36 }

Wesołych Świąt i Szczęśliwego Nowego Roku!

Wykład 10

W dalszym ciagu pisalismy funkcje operujace na zdefiniowanych przez nas typach danych: wektor (v_t) i macierz (m_t). Mnożenie macierzy przez wektor (m_t * v_t)

   1 #include "vect.h"
   2 #include <assert.h>
   3 
   4 /* .... kod z poprzedniego wykładu */
   5 v_t * mnoz_m_t_cdot_v_t( m_t *m, v_t *v ) {
   6   if( m->lk == v->n ) {
   7     v_t * iloczyn = malloc( sizeof *iloczyn );
   8     if( iloczyn != NULL ) {
   9       int i,j; /* zmienne robocze do obl. iloczyn skalarnego */
  10       if( (iloczyn->data = malloc( m->lw * sizeof * iloczyn->data )) == NULL ) {
  11         free( iloczyn );
  12         return NULL;
  13       }
  14       iloczyn->size = m->lw;
  15       iloczyn->n = m->lw;
  16       for( i= 0; i < m->lw; i++ ) {
  17         double s= 0;
  18         for( j= 0; j < m->lk; j++ )
  19           s += m->data[i*m->lk+j] * v->data[j];
  20         iloczyn->data[i] = s;
  21       }
  22     }
  23     return iloczyn;
  24   } else
  25     return NULL;
  26 }

Mnozenie macierzy przez macierz

   1 #include "vect.h"
   2 #include <assert.h>
   3 
   4 /* .... kod z poprzedniego wykładu */
   5 
   6 m_t * mnoz_m_t_cdot_m_t( m_t *a, m_t *b ) {
   7   if( a->lk != b->lw )
   8     return NULL;
   9   else {
  10     m_t *n = malloc( sizeof *n );
  11     int i,j,k;
  12     if( n == NULL )
  13       return NULL;
  14 
  15     if( (n->data = malloc( a->lw*b->lk * sizeof * n->data )) == NULL ) {
  16       free( n );
  17       return NULL;
  18     }
  19     n->lw = a->lw;
  20     n->lk = b->lk;
  21 
  22     for( i= 0; i < a->lw; i++ )
  23       for( j= 0; j < b->lk; j++ ) {
  24         double s= 0;
  25         for( k= 0; k < a->lk; k++ )
  26           s += a->data[i*a->lk+k] * b->data[k*b->lk+j];
  27         /*
  28         n->data[i*n->lk+j] = s;
  29         */
  30         assert( set_failed_m_t( n, i, j, s ) == 0 );
  31       }
  32     return n;
  33   }
  34 }

Walczyliśmy z kodem zawierającym błędy merytoryczne - pokazaliśmy, że często mozna znaleźć te błędy w wyniku analizy kodu popartego rozsądnie prowadzonymi testami. Wykorzystywaliśmy wydruki kontrolne do lokalizacji błędu:

   1 #include "mat.h"
   2 #include <stdio.h>
   3 
   4 int main() {
   5   m_t w;
   6   m_t v;
   7   m_t *r;
   8 
   9   int i,j;
  10   init_m_t( &w, 5, 3 );
  11   for( i= 0; i < 5; i++ )
  12     for( j= 0; j < 3; j++ )
  13       if( set_failed_m_t( &w, i, j, i+10*j ) )
  14         fprintf( stderr, "Index(%d,%d) is not legal for this table!\n",i,j );
  15   printf( "w:\n" );
  16   print_m_t( &w );
  17 
  18   init_m_t( &v, 1, 6 );
  19   for( i= 0; i < v.lw; i++ ) {
  20     for( j= 0; j < v.lk; j++ )
  21         set_failed_m_t( &v, i, j, i );
  22   }
  23   printf( "v:\n" );
  24   print_m_t( & v );
  25 
  26 
  27   fprintf( stderr, "Będę mnożył\n" );
  28   r=  mnoz_m_t_cdot_m_t( &v, &w);
  29   if( r != NULL )
  30     fprintf( stderr, "Udało się!\n" );
  31   else {
  32     fprintf( stderr, "Porashka!\n" );
  33     return 1;
  34   }
  35 
  36   fprintf( stderr, "r->lw=%d r->lk=%d\n", r->lw, r->lk );
  37 
  38   print_m_t( r );
  39 
  40   return 0;
  41 }

Rozmawialiśmy o tym, dlaczego wydruki kontrolne wędrują na stderr, dlaczego wazne jest kompilowanie programu z włączonymi ostrzeżeniami (-Wall) i do czego służą asercje.

Wykład 9

Powtarzaliśmy informacje o "inteligentnych" strukturach. Demonstrowałem operacje powiększania struktury (pola data) przy dodawaniu nowych liczb. Można to robić przy wykorzystaniu f. realloc

   1 void addTo_v( v_t *v, double new )
   2 {
   3         if( v->n == v->size ) {
   4                 v->data = realloc( v->data, 2*v->size*sizeof * v->data );
   5                 v->size *= 2;
   6         }
   7         v->data[v->n]= new;
   8         v->n++;
   9 }

lub "ręcznie"

   1 void addTo_v( v_t *v, double new )
   2 {
   3         if( v->n == v->size ) {
   4                 double *p = malloc( 2*v->size*sizeof *v->data );
   5                 int i;
   6                 for( i= 0; i < v->n; i++ )
   7                         p[i]= v->data[i];
   8                 free( v-> data );
   9                 v->data = p;
  10                 v->size *= 2;
  11         }
  12         v->data[ v->n++ ] = new;
  13 }

Napisaliśmy też funkcję, która tworzy nowy wektorów

   1 v_t * sum_v( v_t *a, v_t * b )
   2 {
   3         if( a->n != b-> n )
   4                 return NULL;
   5         else {
   6                 int i;
   7                 v_t *c = malloc( sizeof *c );
   8                 if( c == NULL )
   9                         return NULL;
  10                 c->data = malloc( sizeof *c->data * a->n );
  11                 if( c->data == NULL ) {
  12                         free( c );
  13                         return NULL;
  14                 }
  15                 for( i= 0; i < a->n; i++ )
  16                         c->data[i] = a->data[i] + b->data[i];
  17                 c->n = a->n;
  18                 c->size = c->n;
  19                 return c;
  20         }
  21 }

Następnie przeszliśmy do rozważań nad tablicami wielowymiarowymi - wyjaśniliśmy, że składnia języka C traktuje tablice 2D jako wektory wektorów, tablice 3D jako wektory wektorów wektorów, itd. Implikuje to przechowywanie np. tablic dwuwymiarowych wierszami, a więc referencja do (i,j)-tego elementu tablicy A[LW][LK] oznacza w istocie referencję do obiektu przechowywanego pod A + i*LK +j.

Pokazaliśmy relacje pomiędzy macierzą dwuwymiarową a adekwatnym wskaźnikiem - zwłaszcza w kontekście operacji na wskaźnikach.

Jako sprawdzian mogą Państwo spróbować zrozumieć działanie tego prostego programu:

   1 #include <stdio.h>
   2 
   3 int main()
   4 {
   5         double t[10][20];
   6 
   7         double (*p)[20];
   8 
   9         t[0][0]= 1;
  10         t[1][0]= 10;
  11         t[2][1]= 21;
  12 
  13         p = t+1;
  14 
  15         printf( "t(1,0)=%g\n", (*p)[0] );
  16 
  17         p++;
  18 
  19         printf( "t(2,1)=%g\n", (*p)[1] );
  20 
  21         return 0;
  22 }

Na koniec stworzyliśmy zaczątek biblioteczki funkcji operujących na dwuwymiarowej macierzy.

Plik nagłówkowy

   1 typedef struct {
   2         double * data;  /* dane przechowywane wierszami */
   3         int lw;         /* liczba wierszy */
   4         int lk;         /* liczba kolumn */
   5 } m_t;
   6 
   7 int init_m_t( m_t *m, int pn, int pm );  /* inicjalizacja tablicy pn x pm */
   8 
   9 void print_m_t( m_t * );                  /* wypisywanie na stdout */
  10 
  11 int set_failed_m_t( m_t *, int, int j, double ); /* wstawienie pod (i,j) - zwraca 1 w razie porażki (złe indeksy)*/

Implementacja

   1 #include "mat.h"
   2 #include <stdlib.h>
   3 #include <stdio.h>
   4 
   5 int init_m_t( m_t *m, int pn, int pm ) {
   6         m->data = malloc( sizeof * m->data * pn * pm );
   7         if( m->data == NULL )
   8                 return 0;
   9         m->lw = pn;
  10         m->lk = pm;
  11         return 1;
  12 }
  13 
  14 void print_m_t( m_t *m ) {
  15         int i,j;
  16         for( i= 0; i < m->lw; i++ ) {
  17                 for( j=0; j < m->lk; j++ )
  18                         printf( " %9g", m->data[i*m->lk+j] );
  19                 printf( "\n" );
  20         }
  21 }
  22 
  23 int set_failed_m_t( m_t *m, int i, int j, double x )
  24 /* m[i][j] = x */
  25 {
  26         if( i < 0 || i >= m->lw || j < 0 || j >= m->lk )
  27                 return 1;
  28         else {
  29                 m->data[i*m->lk+j] = x;
  30                 return 0;
  31         }
  32 }

Testy:

   1 #include "mat.h"
   2 #include <stdio.h>
   3 
   4 int main() {
   5         m_t w;
   6         int i,j;
   7         init_m_t( &w, 5, 3 );
   8         for( i= 0; i < 5; i++ )
   9                 for( j= 0; j < 4; j++ )
  10                         if( set_failed_m_t( &w, i, j, i+10*j ) )
  11                                 fprintf( stderr, "Index(%d,%d) is not legal for this table!\n", i, j );
  12         print_m_t( &w );
  13         return 0;
  14 }

Wykład 8

Omawialiśmy trochę test i jeszcze raz powtarzaliśmy wykorzystanie plików nagłówkowych do kontroli (przez kompilator) poprawności wywołania funkcji (uzgadniania listy parametrów formalnych i aktualnych).

Potem zajęliśmy się strukturami danych.

Pisaliśmy programik demonstrujący zaszytą w strukturze tablicę, która pamięta własne rozmiary i aktualną liczbę elementów.

Program testujący:

   1 #include <stdio.h>
   2 #include <stdlib.h>
   3 #include "vect.h"
   4 
   5 int
   6 main( int argc, char ** argv ) {
   7   int i;
   8 
   9   v_t w;
  10 
  11   init_v( &w, 5 );
  12 
  13   for( i= 1; i < argc; i++ )
  14     addTo_v( &w, atof(argv[i]) );
  15 
  16   print_v( w );
  17 
  18   zero_v( w );
  19 
  20   print_v( w );
  21 
  22   return 0;
  23 }

Plik nagłówkowy (proszę zwrócić uwagę na def. struktury):

   1 typedef struct {
   2   double *data;
   3   int n;
   4   int size;
   5 } v_t;
   6 
   7 void init_v( v_t * w, int prefered_size );
   8 
   9 void addTo_v( v_t *w, double new );
  10 
  11 void print_v( v_t );
  12 
  13 void zero_v( v_t );
  14 
  15 double sum( v_t );

I wreszcie definicje funkcji:

   1 #include "vect.h"
   2 #include <stdlib.h>
   3 #include <stdio.h>
   4 
   5 void init_v( v_t *v, int p_s )
   6 {
   7   (*v).data = malloc( p_s * sizeof * (*v).data );
   8   (*v).size = p_s;
   9   (*v).n = 0;
  10 }
  11 
  12 void addTo_v( v_t *v, double new )
  13 /* Ćiczenie nr 1 - proszę poprawić tę funkcję,
  14    aby zachowywała się poprawnie nawet gdyby liczba
  15    elementów (n) miała przekroczyć zaalokowaną wielkość (size) */
  16 {
  17   v->data[v->n]= new;
  18   v->n++;
  19 }
  20 
  21 void print_v( v_t v )
  22 {
  23   int i;
  24   for( i = 0; i < v.n; i++ )
  25     printf( " %g", v.data[i] );
  26   printf( "\n" );
  27 }
  28 
  29 void zero_v( v_t v ) {
  30   int i;
  31   for( i= 0; i < v.n; i++ )
  32     v.data[i]= 0;
  33 }
  34 
  35 double sum( v_t v )
  36 /* Ćiczenie nr 2 - proszę napisac tę funkcję */
  37 {
  38   return 0;
  39 }

Wykład 7

[attachment:jimp1_2007_s1.pdf Pytania] (PDF)

Wykład 6

To dalszy ciąg o wskaźnikach, a w szczególności o:

Poza tym mówiliśmy też o technikach programowania:

Program przykładowy

#include <stdio.h>
#include <stdlib.h>

void
wypisz_wektor( double *v, int n )
{
  while( n-- )
    printf( "%g ", *v++ );
  printf( "\n" );
}

void
wypisz_napisy( char* *v, int n )
{
  while( n-- )
    printf( "\"%s\" ", *v++ );
  printf( "\n" );
}

int mystrcmp( char *, char * );

int
str_cmp( const void *a, const void *b )
{
  char ** sa = (char**)a;
  char ** sb = (char**)b;

  char* na = * sa;
  char* nb = * sb;

  return - mystrcmp( na, nb );
}

int
mystrcmp( char *s1, char *s2 )
{
  while( *s1 != '\0' && *s1 == *s2 ) {
    s1++;
    s2++;
  }
  return *s1 - *s2;
}
int
double_cmp( const void *a, const void *b )
{
  double *pa = (double *)a;
  double *pb = (double *)b;

  if( *pa < *pb )
    return -1;
  else if( *pa == *pb )
    return 0;
  else
    return 1;
}

int
main( int argc, char ** argv )
{
  double v[1000];
  int n;
  int i;

  char *t[100];
  int m;
  int j;

  char **sp;
  int l;
  int k;

  scanf( "%d", &n );
  for( i= 0; i < n; i++ )
    scanf( "%lf", v+i );

  wypisz_wektor( v, n );

  qsort( v, n, sizeof v[0], double_cmp );

  wypisz_wektor( v, n );

  m= argc - 1;
  for( j= 0; j < m; j++ )
    t[j] = argv[j+1];
  m= argc - 1;
  for( j= 0; j < m; j++ )
    t[j] = argv[j+1];

  wypisz_napisy( t, m );

  qsort( t, m, sizeof( char * ), str_cmp );

  wypisz_napisy( t, m );

  l = argc - 1;
  sp = malloc( l * sizeof( char * ) );
  for( k= 0; k < l; k++ )
    *(sp+k)= argv[k+1];

  wypisz_napisy( sp, l );
  qsort( sp, l, sizeof( char *), str_cmp );
  wypisz_napisy( sp, l );

  free( sp );

  return 0;
}

Wykład 5

To wprowadzenie do wskaźników

#include <stdio.h>

int
main( )
{
  int i;

  int *pi;

  int t[] = { 10, 20, 30, 40 };

  pi = &(t[0]);

  printf( "t[0]=%d\n", t[0] );

  printf( "za pomocą wskaxnika=%d\n", *pi );

  *pi = 7;

  for( i= 0; i < sizeof t / sizeof t[0]; i++ )
    printf( "t[%d]=%d ", i, t[i] );
  printf( "\n" );

  pi++;

  printf( "*pi=%d\n", *pi );

  pi = &t[0];
  while( *pi != 40 ) {
    printf( "*pi=%d ", *pi );
    pi++;
  }
  printf( "\n" );


  return 0;
}

Plik pd.c

#include <stdio.h>

int
main()
{

  double t[] = { 1, 23, 10, .123, 17, 12, 0, 6, 7, 99, 22 };

  double *pd;
  double *pp;

  pd = &t[0];
  pp = pd;

  while( *pd != 0 )
    pd++;

  printf( "0 to element nr %d\n", pd - pp );

  return 0;
}

Plik pokazujący wykorzystanie operatore sizeof

#include <stdio.h>

int
main( int argc, char *argv[] )
{
  double z[] = { 1, 2, 3, 4, 10, 20, 300 };

  printf( "sizeof z = %d\n", sizeof z );
  printf( "sizeof z[0] = %d\n", sizeof z[0] );
  printf( "Liczba elementów tablicy z to %d\n", sizeof z / sizeof z[0] );

  return 0;
}

Plik pokazujący dualizm tablica<->wskaźnik na liście argumentów funkcji

#include <stdio.h>

int my_strlen( char s [] )
{
  int i;
  for( i = 0; s[i] != '\0'; i++ )
    ;
  return i;
}

int my_strlen_w( char *s )
{
  char * p= s;
  *(p+1) = 'Z';
  while ( *s != '\0' )
    s++;
  return s - p;
}

int
main( int argc, char * argv[] )
{
  int i;

  for( i= 0; i < argc; i++ )
    printf( "Dlugosc napisu \"%s\" to %d\n", argv[i], my_strlen_w( argv[i] ) );

  return 0;
}

Plik demonstrujący dualizm na przykładzie wektorów zawierających double

#include <stdio.h>

void reverse( double *v, int n )
{
  int i;
  for( i = 0; i < n / 2; i++ ) {
    double tmp = *(v+i) /* v[i] */;
    *(v+i) = *(v+n-1-i) /* v[i] = v[ n-1 - i] */;
    *(v+n-1-i) = tmp;
  }
}

int
main()
{

  double v[] = { 10, 20, 30, 40, 50 };

  int i;

  double *p;

  p= v;

  printf( "wartość v[3] to %f\n", *(p+3) );
  printf( "wartość v[3] to %f\n", *(v+3) );

  reverse( v, sizeof v / sizeof v[0] );

  for( i= 0; i < sizeof v / sizeof v[0]; i++ )
    printf( "%g ", v[i] );
  printf( "\n" );

  return 0;
}

Wykład 4

Mówiliśmy o kilku ważnych zagadnieniach:

Plik cgnuplot.c

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "myfun.h"

#define DATA_MAX_SIZE 1000   /* maksymalna liczba punktow w tabeli w. funkcji */

double wlasna( double x )
{
  return x*x - 2*x + 4;
}

void kwik( char *s )
{
  fprintf( stderr, "\nBŁĄD: %s\n", s );
  exit( 1 );
}

int
main (int argc, char *argv[])
{
    int ret_code;
    double x[DATA_MAX_SIZE];
    double y[DATA_MAX_SIZE];
    int n = 100;
    int i;
    double f = -1;
    double t = 1;
    FILE *out = fopen ("plot.gpt", "w");

    double (*wsk_na_fun)( double ) = wlasna;

    if( argc > 1 ) {
      if( strcmp( argv[1], "wlasna" ) == 0 )
        wsk_na_fun = wlasna;
      else if( strcmp( argv[1], "sin" ) == 0 )
        wsk_na_fun = sin;
      else if( strcmp( argv[1], "cos" ) == 0 )
        wsk_na_fun = cos;
      else if( strcmp( argv[1], "sqrt" ) == 0 )
        wsk_na_fun = sqrt;
    }
    for( i = 2; i < argc; i++ )
      if( strcmp( argv[i], "-n" ) == 0 ) {
        if( argc == i+1 )
          kwik( "opcja -n nie ma wymaganego argumentu!" );
        n= atoi( argv[i+1] );
        i++;
      } else if( strcmp( argv[i], "-f" ) == 0 ) {
        if( argc == i+1 )
          kwik( "opcja -f nie ma wymaganego argumentu!" );
        f= atof( argv[i+1] );
        i++;
      } else if( strcmp( argv[i], "-t" ) == 0 ) {
        if( argc == i+1 )
          kwik( "opcja -t nie ma wymaganego argumentu!" );
        t= atof( argv[i+1] );
        i++;
      }

    fprintf (out, "plot 'dataset' w linespoints\n"
                  "pause -1\n");

    fclose (out);

    if( fill_vector (x, DATA_MAX_SIZE, f, t, n) != n )
      kwik( "zła wartosc n" );

    if (function_table (x, n, y, DATA_MAX_SIZE, wsk_na_fun) != n)
      kwik( "twórca programu czegoś nie rozumie - pokaż mu ten błąd" );

    out = fopen ("dataset", "w");
    output_table (out, x, y, n);
    fclose (out);

    ret_code = system ("gnuplot plot.gpt");

    printf ("gnuplot return code = %d\n", ret_code);

    if (ret_code == 0) {
        remove ("plot.gpt");
        remove ("dataset");
    }

    return 0;
}

Plik myfun.h

int
fill_vector (double x[], int x_size, double start, double stop, int n_steps);

int
function_table (double x[], int n_x, double y[], int y_size,
                double (*f) (double));

void
output_table (FILE * out, double x[], double y[], int n);

Plik myfun.c

#include <stdio.h>
#include "myfun.h"

int
fill_vector (double x[], int x_size, double start, double stop, int n_steps)
{
    double dx = (stop - start) / (n_steps - 1);
    int i;

    if (n_steps > x_size)
        return -1;

    for (i = 0; i < n_steps; i++)
        x[i] = start + i * dx;

    return n_steps;
}

int
function_table (double x[], int n_x, double y[], int y_size,
                double (*f) (double))
{
    int i;

    if (n_x > y_size)
        return -1;

    for (i = 0; i < n_x; i++)
        y[i] = f (x[i]);

    return n_x;
}

void
output_table (FILE * out, double x[], double y[], int n)
{
    int i;
    for (i = 0; i < n; i++)
        fprintf (out, "%g %g\n", x[i], y[i]);
}

Plik makefile

a.out: cgnuplot.c myfun.c
  $(CC) $(COPT) -o$@ $^ -lm

cgnuplot.o: cgnuplot.c myfun.h

myfun.o: myfun.c myfun.h

test: a.out
  ./a.out

Wykład 3

Opowiadałem o funkcji, przekazywaniu argumentów do niej, podziale programu na funkcje i na pliki, niezależnej kompilacji plików, uzgadnianiu definicji i wywołania przez pliki nagłówkowe.

Piszemy program, który policzy liczby z pliku, obliczy ich sumę i średnią.

Dane testowe (plik dane.test):

1
2.2
3.7
4
-2

Program pokazujący, jak czytać plik:

#include <stdio.h>

int
main( int argc, char * argv[] ) {
  FILE* inp = fopen( argv[1], "r" );
  int n = 0;
  double x;

  if( inp == NULL ) {
    printf( "%s: Can't read %s\n", argv[0], argv[1] );
    return 1;
  }

  while( fscanf( inp, "%lf", &x ) == 1 ) {
    printf( "Got number %9.2f\n", x );
    n++;
  }
  printf( "Total: %d numbers\n", n );

  return 0;
}

Program główny:

#include <stdio.h>
#include "readV.h"
#include "sumV.h"

int main( int argc, char * argv[] ) {

   double w[1000];
   int n = 0;
   double sum = 0;

   if( argc != 2 ) {
     printf( "Missing input filename!\n" );
     return 1;
   }

   if( (n= readV( argv[1], w, 1000 )) <= 0 ) {
     printf( "%s: Can't read input %s or bad contents of %s\n", argv[0], argv[1], argv[1] );
     return 1;
   }

   sum = sumV( w, n );

   printf( "%d numbers, sum = %g, average = %g\n", n, sum, sum/n );

   return 0;
}

readV.h

int readV( char *, double [], int );

sumV.h

double sumV( double [], int );

readV.c

#include <stdio.h>
#include "readV.h"

int readV( char * file_name, double v[], int max ) {
  FILE* inp = fopen( file_name, "r" );
  int n = 0;
  double x;

  if( inp == NULL ) {
    return -1;
  }

  while( n < max && fscanf( inp, "%lf", &x ) == 1 )
    v[n++] = x;

  if( n == max && ! feof( inp ) ) {
    fclose( inp );
    return -2;
  }

  fclose( inp );
  return n;
}

sumV.c

#include "sumV.h"

double sumV( double v[], int n )
{
  double sum = 0;
  while( --n >= 0 )  /*mozna też n-- > 0 */
    sum += v[n];
  return sum;
}

Wykład 2

int gciag( double xp, double xk, double dx, double x[]  )
{
   int i= 0;
   int n = ( xk - xp ) / dx + 1;
   for( i= 0; i < n; i++ )
     x[i] = xp + i*dx;
   return n;
}

void x2( double x[], double y[], int n )
{
  int i;
  for( i= 0; i < n; i++ )
    y[i] = 2*x[i]*x[i] + 3*x[i] - 2;
}

#include <stdio.h>
#include <stdlib.h>

int gciag( double, double, double, double [] );

void x2( double x[], double y[], int n );

int main( int argc, char * argv[] )
{
  double w[1000];
  double t[1000];

  double xp = atof( argv[1] );
  double xk = atof( argv[2] );
  double dx = atof( argv[3] );

/*
  printf( "Podaj xp:" );
  scanf( "%lf", &xp );
  printf( "Podaj xk:" );
  scanf( "%lf", &xk );
  printf( "Podaj dx:" );
  scanf( "%lf", &dx );
*/

  int lw= gciag( xp, xk, dx, w );

  int i;

  x2( w, t, lw );

  for( i= 0; i < lw; i++ )
    printf( "%g %g\n", w[i], t[i] );

  return 0;
}

#include <stdio.h>

int main( int argc, char * argv[] )
{
   int i;
   for( i= 0; i < argc; i++ )
     printf( "%s\n", argv[i] );

   return 0;
}

Wykład 1

#include <stdio.h>

double x2( double x )
{
  return 2*x*x + 3*x - 2;
}

int main()
{
  double xp= -10.;
  double xk= 10.;
  double dx= (xk-xp) / 99;

  while( xp <= xk ) {
    printf( "%g %g\n", xp, x2( xp ) );
    xp += dx;
  }
  return 0;
}

2015-09-23 06:43