kurs c/c++ wykład 4

Transkrypt

kurs c/c++ wykład 4
KURS C/C++
WYKŁAD 4
1. Typy zmiennych
2. Typy podstawowe
3. Stałe
3.1. Stałe całkowite
3.2. Stałe zmiennoprzecinkowe
3.2. Stałe znakowe
3.4. Stałe tekstowe
4. Typy pochodne
4.2. Typ void
4.2. Tablice
4.2.1. Jednowymiarowe
4.2.2. Wielowymiarowe
4.2.3. Znakowe
1. Typy zmiennych.
Język C++ dostarcza dwa rodzaje typów:
a) typy podstawowe,
b) typy pochodne, wyprowadzane z typów podstawowych za pomocą operatorów deklaracji i
mechanizmu deklarownia struktury,
Z każdą nazwą (identyfiaktorem) jest związany typ.
Typ zmiennej określa jakie operacje mogą być wykonywane na zmiennej danego typu i jak te
operacje są intrerpretowane. Np;
float zmienna;
Oznacza to że jest to zmienna numeryczna i może być ona używana np. w wyrażeniach
arytmetycznych, można jej nadawać wartości itp.
2. Typy podstawowe:
Typami podstawowymi są:
char
short int
int
long int
do reprezentownia zmiennych całkowitych różnych rozmiarów,
float
double
long double
do reprezentownia zmiennych zmiennopozycyjnych
unsigned char
unsigned short int
unsigned int
unsigned long int
do reprezentownia liczb całkowitych bez znaku, wartości logicznych, tablic bitowych itp.
signed char
signed short int
signed int
signed long int
do jawnego reprezentowania zmiennych ze znakiem.
Typ int i char są typami całkowitymi.
Zmienne całkowite mogą występować w dwóch wariantach: ze znakiem (signed) lub bez
znaku(unsigned). Np.:
signed int lub unsigned int.
ˇ
Wyposażenie typu w znak: signed int, sprawia, że może on reprezentować liczbę ujemną i
dodatnią.
* Typ bez znaku unsigned int reprezentuje liczbę niejemną.
* Przez domniemanie przyjmuje się, że zapis int a; oznacza typ signed int, czyli liczbę ze znakiem.
* Dla typu char sprawa nie jest taka prosta.
* Od sprzętu zależy ilość bajtów pamięci przeznaczonej na przechowanie danego typu
podstawowego, czyli długość typu.
Standart języka zapewnia, iż typ char jest dostatecznie duży, aby pomieścić dowolny elemnt
podstawowego zbioru znaków implementacji. Jest to zwykle ośmiobitowy bajt.
Typy signed char , unsigned char i char są traktowane jako oddzielne typy, choć zajmują tyle
samo miejsca w pamięci.
Standard gwarantuje że:
1 ≡ sizeof(char)<=sizeof(short) <=sizeof(int)<=sizeof(long)
sizeof(float)<=sizeof(double) <=sizeof(long double)
sizeof(I) ≡ sizeof(signed I) ≡ sizeof(unsigned I)
gdzie I: może byc typem: char, short, int lub long
Liczby całkowite mają rozmiar naturalny dla architektury danej maszyny.
Poniżej przedstawione wartości dotyczą implementacji dostępnej w laboratorium: (dla pakietu
Borland 3.1):
char (ze znakiem)
- 1 bajty
-128 do 127
unsigned char
- 1 bajt
0 do 255
unsigned short
- 2 bajt
0 do 65535
signed short
- 2 bajty
-32768 do 32767
unsigned int
- 2 bajty
0 do 65535
signed int
- 2 bajty
-32768 do 32767
unsigned long int
- 4 bajty
0 do 4294967295
signed long int
- 4 bajty
2147483648 do 2147483647
float
- 4 bajty
3.4 E- 38 do 3.4e+38
double
- 8 bajtów
1.7 E-308 do 1.7 E+308
long double
- 10 bajtów
3.4 E-4932 do1.1E+4932
Największe i najmniejsze wartości każdego typu dla danej implementacji są podane w
standardowym pliku nagłówkowym limits.h.
Przy wyborze typu należy pamiętać, że za lepszą dokładność płaci się dłuższym czasem
obliczeń.
3. Literały (inaczej zwane stałymi)
W programach często posługujemy się stałymi, możemy używać:
- stałych całkowitych
- stałych zmiennopozycyjnych
- stałych znakowych
- literałów napisowych
Przykład: x = 10.53; i = i+5; if(m>12)
3.1. Stałe całkowite
- dziesiętne np. 12, -100 (bez znakow wiodących)
- ósemkowe: jeśli zapis stałej zaczniemy od cyfry 0 np: 014
014 dziesiętnie: 4*80 + 1*81= 12
-
szesnastkowe: jeśli zapis stałej zaczniemy od cyfry 0x lub 0X
np: 0x10 lub 0X10
Do reprezentowania 10, 11, 12, 13, 14, 15, 16 używa się
liter a,b,c,d,e,f lub ich dużych odpowiedników.
0xA1 dziesiętnie: 1*160 + 10*161= 161
Stałe całkowite traktowane są jako int chyba, że ze względu na ich rozmiar trzeba je oznaczyć
jako long. Wtedy dopisujemy na końcu literę L (lub l) np: 0L, 200L.
Jeśli chcemy, żeby stała była typu unsigned dopisujemy na końcu literę u np:277u.
Może ona występować razem z L np: 50 uL, czyli stała ma być traktowana jako unsigned long.
#include<stdio.h>
main(){
int i, j, k, n, m;
i = 5;
k = i + 010;
printf ("k=%d",k);
//5+8
m = 100;
//100
n = 0x100; //256
j = 0100;
//64
j=23;
printf ("%#x %o %d", j, j, j);
}
3.2. Stałe zmiennoprzecinkowe
//0x17
27
23
Można je zapisać na dwa sposoby:
- normalny zapis liczby z kropką np: 17.89 - 12.
- tzw. notacja naukowa. W zapisie tym występuje litera e, po której występuje
wykładnik potęgi o podstawie 10, a więc:
8 e 2 = 8 * 102
10.4 e 8 = 10.4 * 108
10.4e -8 = 10.4 * 108
Stałe te traktowane są jako double, chyba że typ określimy przy pomocy przyrostka: f, F - float,
l, L - long double.
Część całkowitą i ułamkową można pominąć, ale nie obie naraz. Kropkę lub część wykladniczą
z literą e(E) można pominąć, ale nie obie naraz.
double x = 1.2e2; x= 12e2; x=.22e2
printf (″%e″, x); // ekran: 1.200000e+02
3.3. Stałe znakowe
Są to stałe reprezentujące np. znaki alfanumeryczne. Zapisuje się je ujmując dany znak w znaki
apostrofu. Pojedyncze stałe znakowe są typu char:
'a' - oznacza literę a
'7' - oznacza cyfre 7 (CYFRĘ a NIE LICZBĘ)
przykład deklaracji i użycie stałej znakowej:
char znak;
znak = 'n';
Wartością stałej znakowej jest wartość kodu znaku !!!
Są jednak znaki, których nie można bezpośrednio umiecić między apostrofami. Służą one do
sterowania wypisywanym tekstem. Są to znaki nie mające reprezentacji graficznej.
'\b' - cofacz(Bsp )
'\v' - tabulator pionowy
'\f' - nowa strona
'\a' - sygnał alarmowy
'\n' - nowa linia -NL(LF)
'\r' - powrót karetki
'\t' - tabulator poziomy
'\\' � bekslesz
'\' ' - apostrof
'\" ' - cudzysłów
'\?' = pytajnik.
'\0' - NULL specjalny znak o kodzie 0
\ooo
- liczba ósemkowa (oktalnia)
\xhh
- liczba szesnastkowa (heksadecymalna)
Mimo, że widzimy kilka znaków zapisy te reprezentują tylko jeden znak. Typem stałej znakowej
jest znak.
Stałe znakowe można podawać bezpośrednio w znakach apostrofu lub podając kod stałej też w
znakach apostrofu w postaci liczby ósemkowej lub heksadecymalnej.
oktalnie:
heksadecymalnie:
'k' -> '\153'
char znak='k';
'k' -> '\x6B�
lub
znak= '\153';
lub znak= '\x6B';
printf (″%c″, znak); Ekran: k
Używanie notacji numerycznej do reprezentacji stałych znakowych ogranicza przenośność
oprogramowania, że względu na możliwość innego kodowania znaków niż ASCII.
3.4. Stałe tekstowe (stringi)
Jest to ciąg znaków ujęty w cudzysłów.
Stringi w pamięci przechowywane są jako ciąg znaków zakończonych znakiem NULL czyli
znakiem o wartości!!! 0.
"arbuz" sizeof ( "arbuz") = 6
znaków w napisie:
napis "arbuz" ma 6 znaków, czyli o jeden znak więcej niż ilość
znaki z tekstu "arbuz" + miejsce na NULL.
""
sizeof ("") = 1
napis pusty zawiera 1 znak jest to znak NULL
Stała 'x' nie oznacza tego samego co "x" - pierwsza reprezentuje tylko jeden znak x, druga
jednoznakowy łańcuch zawierający znak x oraz znak końca stringu �\0�
!!!
Wewnątrz napisu można reprezentować cudzysłów ,bekslash, apostrof. należy te znaki
poprzedzić znakiem bckslash�a.
cout<<"witamy w \"C++\");
printf ("witamy w \"C++\");
Wewnątrz napisu można również umieszczać znak �\0�, lecz większość funkcji nie spodziewa
się tego znaku wewnątrz.
printf("Pomarańczowa \0 Alternatywa");
na ekranie będzie wyświetlone tylko słowo Pomarańczowa
Jeśli string nie mieści się w jednej linii, wtedy możemy postąpić nastepująco:
cout<<"To jest"
<< " przykład dobrego łamania stringu";
cout<<"To jest"
" przykład dobrego łamania stringu"
kompilator łączy dwa sąsiadujące ze sobą stringi.
cout<<"To jest
przykład błędnego łamania stringu"
lub: printf ("To jest"
" przykład dobrego łamania stringu";
printf ("To jest
przykład błędnego łamania stringu");
4. Typy pochodne
Istnieje nieskończenie wiele typów pochodnych konstruowanych z typów podstawowych mogą
to być:
tablice, funkcje, wskaźniki, referencje, stałe (const), klasy, struktury, unie.
Typy pochodne można wyprowadzać z typów podstawowych za pomocą operatorów deklaracji:
[]
- operator indeksowania pozwala tworzyć tablicę obiektów danego typu.
*
- wskaźnik do pokazywania na obiekt danego typu.
którym można umieścić adres jakiegoś obiektu.
()
- operator do deklarowania funkcji zwracającej wartość danego typu.
&
- referencja obiektu danego typu. Oznacza inną nazwę obiektu. Dzięki referencji na
tę samą zmienną można mówić używając jego drugiej
nazwy.
oraz mechanizmu definiowania struktury.
* & - operatory przedrostkowe
[] () - operatory przyrostkowe
Przykłady typów pochodnych:
int tab[10];
float *p;
int *wsk
char func ();
Wskaźnik jest obiektem, w
int i; int &refer=i;
4.1. Typ void
Typ void specyfikuje pusty zbiór wartości. Typu void można jedynie użyć jako części typu
pochodnego. Nie ma obiektów typu void.
Stosuje się go jako typ wartości funkcji, która nie przekazuje na zewnątrz żadnej wartości, oraz
jako wskaźnika do obiektu nieznanego typu.
void f ();
- funkcja f () nie przekazuje żadnej wartości
void *wsk; - wskaźnik do obiektu nieznanego typu.
Można dokonać jawnej konwersji każdego wyrażenia do typu void.
4.2. Tablice
4.2.1. Tablice jednowymiarowe
Jest to ciąg obiektów tego samego typu, zajmujących ciągły obszar w pamięci.
Zamiast odnosić się do każdej zmiennej z osobna, odnosimy się do n-tego elementu tablicy.
Rozmiar tablicy musi być wartością stałą, znaną już na etapie kompilacji.
Jeśli jednak zachodzi konieczność pracy z tablicą o rozmiarze ustalanym w czasie działania
programu , to wtedy realizujemy proces dynamicznej alokacji pamięci, który zostanie pokazany
przy omawianiu wskaźników.
Tablice można tworzyć z:
- typów podstawowych
- typów wyliczeniowych
- wskaźników
- innych tablic
- z klas
- ze wskaźników do pokazywania na składniki klasy.
Tablice nie mogą być ciągiem referencji.
Jeśli zadeklarowaliśmy tablicę: float tablica[rozmiar];
to elementy tablicy numerowane są od 0 do rozmiar �1
Deklarujemy tablicę:
float tablica[3];
to jest to zbiór trzech elementów typu float:
tablica[0], tablica[1], tablica[2].
Uwaga: Instrukcja tablica[3]=90 nie będzie sygnalizowana jako błąd, gdyż język C/C++ nie
sprawdza przekroczenia zakresu tablic. Zapis taki powoduje zniszczenie obiektu zapisanego
bezpośrednio za tablicą i w konsekwencji błędy wykonania programu.
Nadanie wartości elementom tablicy może odbywać się:
- w trakcie działania programu:
Przykład 1
#include <stdio.h>
void main (){
int tab [10], i;
for( i = 0;i<10;i++)
tab[i]= 2*i -1;
for( i = 0;i<10;i++)
printf (″\ntab[%d] = %d″, i, tab[i]) ;
}
Przykład 2
#include <stdlib.h>
#include <iostream.h>
void main (){
const int r =10;
int tab[r], los;
randomize();
for( i = 0; i<r; i++){
tab[i] = random(70);
cout<<″\ntab[″<<i<<″] =″<<tab[i] ;
}
}
- podczas deklaracji tablicy:
należy inicjalizować każdy element z osobna np.:
int tab[3] = {1,2,3};
umieszczenie w nawiasie większej ilości liczb niż wynika to z deklaracji
int tab[3] = {1,2,3,4};
generuje błąd, kompilator sprawdza czy podczas inicjalizacji nie został przekroczony zakres.
Jeżeli elementów jest mniej, brakujące elementy uzupełniane są zerami:
int tab[4] = {1,2} => int tab[4] = {1,2,0,0}
lub nie podając rozmiaru tablicy:
int tab[] = {1,2,3};
4.2.2. Tablice wielowymiarowe
int tab[3][2]; Tablice wielowymiarowe są reprezentowane jako tablice tablic.
Odwołania do tablicy tab przy pomocy indeksowania:
tab[0][0], tab[0][1],
tab[1][0], tab[1][1],
tab[2][0], tab[2][1].
Używanie notacji z przecinkiem takiej jaka jest stosowana w innych językach (Pascal), powoduje
błędy kompilacji:
int tab[5,2];
int tab[5][2];
// błąd
// poprawnie
int zle = tab[5,2];
// błąd
int dobrze = tab[4][1];
Podobnie jak dla tablic jednowymiarowych można je inicjalizować:
tab[3][2] = {10, 11,
20, 21,
30, 31};
tab[0][0]
tab[1][0] tab[2][0]
tab[0][1]
tab[1][1] tab[2][1]
Przy inicjalizacji tablic dwuwymiarowych konieczne jest podanie co najmniej jednego wymiaru,
jest nim ilość elementów w wierszu:
tab[][] = {0,1, 10,11, 20,21, 30,31}; //źle
tab[3][] = {0,1, 10,11, 20,21, 30,31}; //źle
tab[][2] = {0,1, 10,11, 20,21, 30,31}; //dobrze, potrafi ustalić rozmiar
{0,1, 10,11, 20,21, 30,31, 40};//dobrze, potrafi ustalić rozmiar
tab[][2] =
Uzupełnianie brakujących elementów tablic odbywa się wg. zasad dla tablic jednowymiarowych
Przykład zastosowania obu typów tablic przedstawia program obliczania sumy elementów wierszy
macierzy 5x5.
#include <stdio.h>
#include <conio.h>
void main (){
const int r=5;
int A[r][r], B[r];
int i,j;
clrscr();
for (i = 0; i<r;i++)
for(j = 0; j<r; j++)
A[i][j]=1;
/* sumowanie wierszy */
for (i = 0; i<r;i++) {
B[i]=0;
for(j = 0; j<r; j++)
B[i] += A[i][j];
}
/* wyświetlanie wyników zapisanych w tablicy jednowymiarowej */
for(i = 0; i<r; i++)
cout << B[i]<< "\n";
getch();
}
4.2.3. Tablice znakowe
Specjalnym rodzajem tablic są tablice znakowe. Deklaracja takiej tablicy:
char zdanie[50];
W tablicach takich można przechowywać tekst.
Nazwa tablicy jest adresem jej pierwszego elementu w pamięci.
Podobnie jak inne tablice, tablica znakowa może być w trakcie deklaracji inicjalizowana:
(a)
char zdanie [12] = "ala ma kota"; lub char zdanie [] = "ala ma kota";
Teksty w tablicach przechowywane są tak, że po ciągu znaków następuje znak o kodzie 0 tzw. NULL.
Znak NULL został zapisany automatycznie, ponieważ przy inicjalizacji tablicy ciąg znaków
ograniczyliśmy znakami cudzysłowia.
Ciąg znaków zakończony NULL'em nazywamy łańcuchem (stringiem).
W przypadku gdy nie określono rozmiaru tablicy, rozmiar wynosi:
sizeof (zdanie)= ilość znaków + NULL.
deklarujemy: char zdanie[20];
Iinicjalizacja tablicy w następujący sposób jest błędna:
zdanie = ″ala ma kota″;
Tak poprawnie powinna być inicjalizowana tablica: char zdanie[] = ″ala ma kota″;
lub z ustalonym rozmiarem co najmniej 12, takim żeby można było umiścić wszystkie znaki tekstu
+ NULL. Np.: char zdanie[15] = ″ala ma kota″;
Przykłady:
char t1[1] = "a";
//błąd
char t1[2] = "a";
//poprawnie
char t2[1] = {'a'}; //poprawnie
Która z deklaracji jest poprawna?. Pierwsza nie, bo tablica ma być jednoelementowa, a string "a" to
string o długości 2 (litera a + NULL).
Powstała specjalna biblioteka <string.h> zawierająca podstawowe funkcje obsługujące
łańcuchy: kopiowanie , wycinanie, poszukiwanie znaku itd.
char s[]=″Politechnika″; //ze znakiem NULL
int dl= strlen (s);
//strlen () � funkcja obliczana długość łańcucha, w oparciu o
// o znak NULL, a przy takiej inicjalizacji brak tego znaku
dl=12, długość łańcucha jest liczona bez znaku NULL
char nazwa[30];
strcpy (nazwa, ″Informatyka″);
funkcja strcpy() skopiuje do tablicy nazwa[] łańcuch Informatyka, kopiowanie zostaje zakończone
po napotkaniu znaku NULL.
Można inicjalizować:
(1) char
s[]={�P�,�o�,�l�,�i�,�t�,�e�,�c�,�h�,�n�,�i�,�k�,�a�,�\0�}
(2) char
s[]={�P�,�o�,�l�,�i�,�t�,�e�,�c�,�h�,�n�,�i�,�k�,�a�};
znaku NULL
s [0]=�P�, s [1]=�o�, s[2]=�l� ,....,
dla (1) i (2) można sprawdzić czy:
if (s [0] = = �X�)
if (isalpha (s[0]) czylitera=1; else czylitera=0;
if (czylitera) printf (″znak jest literą″);
chcemy przejrzeć cały tekst:
(1)
dl=strlen (s);
//dl=12, tablica 0..11
for (i=0; i<dl; i++)
if (!isalpha (s[i]) break;
if (i = = dl) printf (″wszystkie znaki to litery″);
else printf (na %d pozycji tablicy znak nie jest literą″, i);
(2)
dl=strlen (s); //błąd, brak znaku NULL
for (i=0; i<?; i++)
const r=5;
char zestaw[r]={�a�, �e�,�i�,�o�,�u�};
znak=getch();
for (i=0; i<r; i++)
if (znak= =zestaw[i]) {printf (″litera jest samogloska″); break;}
//bez