background image

Ć

wiczenia 22 maja 2012 

 

Zadanie 9.2 
 
Napisz program (korzystając z tablicy dwuwymiarowej), który dla wczytanego z klawiatury ciągu liczb 
całkowitych wypisze sumę  cyfr każdej z tych liczb.  
 
PSEUDOLOSOWE LICZBY CAŁKOWITE 

 

Generowanie losowe liczb całkowitych. 

 

Funkcja losująca liczby całkowite pochodzi ze standardowej biblioteki języka C. Bibliotekę, którą należy 
dołączyć jest cstdlib.  
 
Funkcja losująca  po prostu losuje liczbę całkowitą, która mieści się w przedziale od 0 do RAND MAX (jest 
to stała, która zależy od kompilatora i załączonych bibliotek).  
 
Przykład 
 
 
#include <iostream> 
#include <cstdlib> 
int main() 

    cout << "losowanie pierwsze: " << rand() << endl; 

background image

    int liczba = rand(); 
    cout << "losowanie drugie: " << liczba << endl; 
    liczba = rand(); 
    cout << "losowanie trzecie: " << liczba << endl; 
    return 0; 

 
Konfiguracja maszyny losującej 
Jeżeli uruchomimy kilka razy powyższy program to zauważymy, że komputer wylosował nam za każdym 
razem te same liczby. Takie zachowanie oczywiście nie jest pożądane, dlatego też wymagane jest 
skonfigurowanie generatora liczb losowych.  
 
srand( time( NULL ) ); 
 
Powyższą linijkę wystarczy wywołać tylko raz na samym początku programu, kod wygląda teraz tak:  
 
#include <iostream> 
#include <cstdlib> 
#include <ctime> 
int main() 

    srand( time( NULL ) ); 
    cout << "losowanie pierwsze: " << rand() <<  endl; 
    int liczba = rand(); 

background image

    cout << "losowanie drugie: " << liczba <<  endl; 
    liczba = rand(); 
    cout << "losowanie trzecie: " << liczba << :endl; 
    return 0; 

 
Jeżeli potrzebujemy zmienić zakres to wykorzystać musimy działanie modulo i dodawanie. Najpierw 
ustalamy ile liczb mieści się w przedziale z którego chcemy losować, np. 50 liczb. Następnie ustalamy 
pierwszą losowaną liczbę np. 7.  
 
int wylosowana_liczba =( rand() % ile_liczb_w_przedziale ) + startowa_liczba; 
 
a dokładnie:  
  
int wylosowana_liczba =( rand() % 50 ) + 7; 
 
Albo dla liczb z dowolnego przedziału <a,b> wypełnimy nimi tablicę: T[i] = a + rand() % (b - a + 1) 
 
Ostatecznie program losujący liczby z przedziału od 7 do 56 będzie więc wyglądał tak:  
  
#include <iostream> 
#include <cstdlib> 
#include <ctime> 
int main() 

background image


    srand( time( NULL ) ); 
    cout << "losowanie pierwsze: " <<(( rand() % 50 ) + 7 ) << endl; 
    int liczba =( rand() % 50 ) + 7; 
    cout << "losowanie drugie: " << liczba << endl; 
    liczba =( rand() % 50 ) + 7; 
    cout << "losowanie trzecie: " << liczba << endl; 
    return 0; 

 
Zadanie 9.3 
 
Napisz program, który wylosuje pewną ilość liczb (wartość wczytana z klawiatury) z określonego przedziału 
(wartości początku i końca przedziału wczytane z klawiatury). 
 
REKORDY (STRUKTURY) 
 
W  tablicach  mieliśmy  do  czynienia  z  elementami  tego  samego  typu,  natomiast  tutaj  możemy  łączyć  różne 
typy danych. Matematycznie, możemy to potraktować jako iloczyn kartezjański, tzn. 
Mając  dane  zbiory  Z1,  ...,  Zn  możemy  utworzyć  iloczyn  kartezjański  Z1  x...xZn.  Wówczas  element  ma 
postać:  (z1,...,zn).  Każdy  taki  ciąg  nazywamy  rekordem.  W  tym  przypadku  można  wybrać  operator 
pozwalający pobrać poszczególne wartości. Operator ten wybiera z rekordu (z1,...,zn) np. i-tą składową. W 
tablicy  mogliśmy  za  pomocą  pętli  for  oraz  indeksu  (liczba  całkowita)  wykonać  potrzebne  operacje, 
natomiast  w  przypadku  rekordu,  identyfikatory  stanowią  nieuporządkowany  zbiór  różnych  nazw,  nie 

background image

tworząc  ustalonego  typu  danych.  Składowe  rekordów  należy  nazywać  oddzielnie  nie  mogąc  się  do  nich 
odwoływać  kolejno.  Rekordy  warto  stosować  wówczas,  gdy  chcemy  operować  złożoną  strukturą  danych 
mając  do  niej  dostęp  przez  jedną  zmienną.  Struktury  są  deklarowane  ze  słowem  kluczowym  struct
Deklaracja ma postać: struct nazwa; 
Natomiast jej definicja: struct nazwa { /*...*/ }; 
Zauważmy,  że  nazwa  jest  nazwą  nowo  zdefiniowanego  typu.  Na  końcu  struktury  dajemy  średnik  po 
nawiasie klamrowym. 
 
Przykład 
 
#include <cstdlib> 
#include <iostream> 
 
using namespace std; 
 
struct pracownik  { 
        char *tytul_stopien; 
        char *nazwisko; 
        int wiek, liczba_publikacji;  }; 
int main() { 
 

pracownik prac; 

 

prac.tytul_stopien ="Dr"; 

 

prac.nazwisko = "Jan Nowak"; 

 

prac.wiek = 35; 

background image

 

prac.liczba_publikacji = 32; 

 

cout <<"info1 : "<<prac.tytul_stopien <<endl; 

 

cout <<"info2  : "<<prac.nazwisko << endl; 

 

cout <<"info3  : "<<prac.wiek<< endl; 

 

cout <<"info4  : "<<prac.liczba_publikacji <<endl; 

 

 

    system("PAUSE"); 
    return EXIT_SUCCESS; 

 
Szczególną  uwagę  przy  korzystaniu  z  rekordów  należy  zwrócić  na  zgodność  typów.  Każda  deklaracja 
struktury wprowadza nowy, niepowtarzalny typ, np.

 

struct sI { int n ; }; 
struct sII { int m ; }; 

są to dwa różne typy, stąd w deklaracjach 

sI a,b ; 
sII c ; 

zmienne a oraz b są tego samego typu 

sI

, ale c już nie!  

Wobec tego przypisania

 

a=b; 
b=a; 

są poprawne!

  

a = c;

 

nie jest poprawne! 
Natomiast przypisania składowych rekordów o tych samych typach są poprawne, np. 

background image

a.i = b.j; 

 
WSKAŹNIKI 
Do tej pory deklarowaliśmy np. 
int i; 
rezerwując miejsce w pamięci dla zmiennej i typu całkowitego. 
Wskaźnik  (ang.  pointer)  jest  to  specjalny  rodzaj  zmiennej,  w  której  zapisany  jest  adres  w  pamięci 
komputera,  tzn.  wskaźnik  wskazuje  miejsce,  gdzie  zapisana  jest  jakaś  informacja  (stąd  nazwa  zmienna 
wskaźnikowa). 
Adres  to  pewna  liczba  całkowita,  w  sposób  jednoznaczny  definiująca  położenie  pewnego  obiektu  (np. 
liczby,  znaku,  struktury  czy  tablicy)  w  pamięci  komputera.  Wskaźnik  ma  ścisłą  kontrolę  typów  i  z  tego 
powodu nie tylko wskazuje miejsce zajmowane przez zmienną, ale także ile bajtów ta zmienna potrzebuje,  
Definicja zmiennej typu wskaźnikowego ma następującą strukturę: 
typ *identyfikator_zmiennej; 
 
Przykład:  
int *i; (zapis może być różny: int    *i1; int    *     i2; int*     i3; int*i4;)   
float *x; 
float *x,y; 
 
Jak  już  wspominaliśmy,  operator  &  służy  do  pobrania  adresu  miejsca  w  pamięci,  gdzie  istnieje  dana 
zmienna, jest nazywany referencją a operator * jest nazywany operatorem dereferencji lub wskaźnikiem. 
 
Przykład 

background image

 
#include <cstdlib> 
#include <iostream> 
 
using namespace std; 
 
int main() 

   int i=3;   
        int *j;  
        j=&i; //przypisanie zmiennej, która przechowuje adres adresu zmiennej i 
cout<<"wartosc liczby j="<<*j<<endl;  
        cout<<"adres liczby i ="<<&i<<endl; 
 
    system("PAUSE"); 
    return EXIT_SUCCESS;   
 }  

 

 
Inicjalizacja wskaźnika może być wykonana następująco: 
int *wsk = NULL;  

(

NULL oznacza element nie istniejący)

 

int *wsk = 0;  

 

Przy  tworzeniu  i  używania  wskaźników  łatwo  można  popełnić  błąd.  Jeżeli  zaniedbamy  przypisanie 
wskaźnikowi adresu. 

background image

int *wskaznik_numer; 
*wskaznik_numer = 1532;  
Jest to błąd, ponieważ nie wiemy co oznacza komórka o adresie 1532, może się okazać, iż adres ten jest już 
zajęty przez program, wówczas nie będzie można zapisać nic w miejsce wskazane przez wskaznik_numer 
(jest on dość trudny do wykrycia).  
 
TABLICE-WSKAŹNIKI 
 
Przykład: 
 
#include <cstdlib> 
#include <iostream> 
 
using namespace std; 
 
int main() 
{        int x[15]; 
int k; 
cout<<"podaj rozmiar swojej tablicy"<<endl; 
cin>>k; 
 
        for (int i=0; i<k; i++) 
                x[i]=rand()%100; 
        for (int i=0; i<k; i++) 

background image

                cout<<"x "<<i<<"= "<<*(x+i)<<"*   "<<x[i]<<endl; 
 
    system("PAUSE"); 
    return EXIT_SUCCESS; 

 
Zadanie 9.4. (domowe) 
 
Napisać grę, która ma działać następująco: 1. Program losuje liczbę z przedziału od 1 do 1000.  
2. Użytkownik zgaduje liczbę, która została wylosowana.  
3. Jeżeli podana liczba jest za duża (za mała) gra wypisuje stosowny komunikat i powraca do kroku 2.  
4. Jeżeli gracz trafi liczbę wylosowaną to pogram kończy działanie, wypisując na ekran wylosowaną liczbę 
oraz liczbę 'strzałów', które oddał gracz.  
Gra ma być zabezpieczona przed możliwością wprowadzenia błędnych wartości liczbowych.