PODSTAWY INFORMATYKI
PODSTAWY INFORMATYKI
Wykład 3
Instrukcja
if
• Ogólna postać
if (wyrażenie)
instrukcja
1
else
instrukcja
2
• Wykonywana jest dokładnie jedna z dwóch
instrukcji związanych z if-else.
• Jeśli wyrazenie jest prawdą (nie 0), to
wykonywana jest instrukcja
1
; jeśli nie,
wykonywana jest instrukcja
2
.
• Każda instrukcja może być pojedynczą
instrukcją lub ciągiem instrukcji ujętą w
nawiasy klamrowe.
Warunki - przykłady
• if (a>b) printf(”tak!\n”);
• if (a>b && b>c) ...
• if (2+a == 3*b) ...
• if ((a>4) == (b<10)) ...
• Wartościowanie:
– od lewej do prawej
– wstrzymywane, gdy znany jest wynik:
• if (4>9 && a>n++) ...
/* czy n będzie zwiększone? */
Operatory inkrementacji
i dekrementacji
• ++
• --
• mogą być używane jako operatory prefiksowe
(przed zmienną, np. ++n) albo postfiksowe (po
zmiennej, np. n++)
• Przykład: jeśli n jest równe 5, to
x = n++;
ustawia x na 5, ale
x = ++n;
ustawia x na 6; obydwa przypisania ustawiają n na
6.
Operatory bitowe
&
bitwise AND
|
bitwise inclusive OR
^
bitwise exclusive OR
<< left shift
>> right shift
~
one's complement (unary)
Operator bitowy AND
• Działa na wartościach całkowitych
• Przykład:
108
0
1
1
0
1
1
0
0
& 217
1
1
0
1
1
0
0
1
= 72
0
1
0
0
1
0
0
0
Operatory bitowe -
przykłady
• 6 & 11 =
• 4 | 1 =
• 7 ^ 2 =
• 5 >> 2
=
• 3 << 2=
• ~0
=
2
5
5
1
12
-1
(por. z !0)
Ujemne liczby
całkowite:
dlaczego ~0 jest równe
-1
• Unsigned
0: 0000
1: 0001
2: 0010
...
15:
1111
• Signed
-8: 1000
-2: 1110
-1: 1111
0: 0000
1: 0001
2: 0010
7: 0111
...
...
Strumienie wejściowe i
wyjściowe
krótki przegląd
• Standardowe wejście: stdin
• Standardowe wyjście: stdout
• Stand. strumień błędów:
stderr
• Szczegóły zostaną omówione później
• Normalnie strumienie te są związane z
konsolą:
– stdin z klawiaturą
– stdout i stderr z terminalem tekstowym
• Strumienie mogą być przekierowywane
testapp.exe <dane.txt >wyniki.txt
Wejście znakowe
• Odczytanie pojedynczego znaku lub
EOF:
int getc(FILE *stream);
powyższa deklaracja nazywana jest
prototypem
• Przykład:
int c;
c = getc(stdin);
• Czytanie jednego znaku z stdin:
int getchar(void);
• getchar()
działa jak
getc(stdin)
Wyjście znakowe
• Zapis pojedynczego znaku do
strumienia:
int putc(int c, FILE *stream);
• Przykład:
putc(’A’,stdout);
• Zapis pojedynczego znaku do stdout:
int putchar(int c);
• putchar(’A’)
działa jak
putc(’A’,stdout)
• Zwracana wartość: wypisany znak
Kopiowanie plików
#include <stdio.h>
/* kopiowanie wejścia na wyjście:
pierwsza wersja */
main()
{
int c;
c = getchar();
while (c != ‘q’) {
putchar(c);
c = getchar();
}
return 0;
}
Kopiowanie plików - druga
wersja
#include <stdio.h>
/* copy input to output; 2nd version */
main()
{
int c;
while ((c = getchar()) != ‘q’)
putchar(c);
return 0;
}
Liczenie znaków
#include <stdio.h>
/* count characters in input; 1st version */
main()
{
long nc;
nc = 0;
while (getchar() != ‘q’)
++nc;
printf("%ld\n", nc);
return 0;
}
Liczenie znaków - druga
wersja
#include <stdio.h>
/* count characters in input; 2nd version */
main()
{
double nc;
for (nc = 0; getchar() != ‘q’; ++nc)
;
printf("%.0f\n", nc);
return 0;
}
Liczenie wierszy
#include <stdio.h>
/* count lines in input */
main()
{
int c, nl;
nl = 0;
/* the number of lines so far */
while ((c = getchar()) != ‘q’)
if (c == '\n')
/* new line found */
++nl;
printf("%d\n", nl);
return 0;
}
Zmienne w pamięci
• Każda zmienna pamiętana jest w
pewnym miejscu pamięci ... lub w
rejestrze procesora
•
Adres
zmiennej jest
indeksem
tej
komórki pamięci, w której znajduje się
pierwszy bajt zmiennej
• Liczba bajtów zajmowanych przez
zmienną zależy od jej typu; operator
sizeof informuje o tym rozmiarze:
sizeof(type)
Wskaźniki
• Wskaźnik jest adresem, pod którym
znajduje się zwykle coś użytecznego
• Definiowanie zmiennej przechowującej
adres:
<type> *<variable>
• Przykład:
int *pti;
• Pobieranie adresu, pod którym
przechowywana jest zmienna: operator &
int x;
pti = &x;
Wskaźniki - dostęp do
pamięci
int x;
pti = &x;
x = 5;
*pti = *pti + 1;
/* teraz x = 6
*/
x++;
printf(”%d”,x);
/* 7 */
Wskaźniki przykład
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
char*p[3]={
"tak","nie",
"byc moze.Zmien postac
pytania„
};
char nap[80];
printf("wprowadz pytanie\n");
gets(nap);
printf(p[strlen(nap)%3]);
return 0;}
/*WYNIK:
wprowadz pytanie
tak
tak
wprowadz pytanie
Nnnnn
byc moze.Zmien postac
pytania*/
scanf
• ...aby przeczytać z wejścia coś bardziej
złożonego niż pojedynczy znak
• scanf
jest odpowiednikiem
printf
dla
strumienia wejściowego
• udostępnia wiele podobnych konwersji
jak
printf
, ale w przeciwnym kierunku
• Prototyp:
int scanf(char *format, ...)
• scanf
wymaga wskaźników do
zmiennych
Przykład
scanf
#include <stdio.h>
main() {
int x;
printf(” Podaj liczbę: ”);
scanf(”%d”, &x);
printf(”Kwadrat %d wynosi %d\n”, x, x*x);
return 0;
}
/*WYNIK:
Podaj liczbę:5
Kwadrat 5 wynosi
25*/
Tablice
• Definiują więcej “zmiennych” jedną
definicją
• Składnia:
<typ> <zmienna>[liczba_elementów]
• Przykład:
int a[10];
• Indeksowanie: od 0 - jaki jest ostatni
indeks?
• Dostęp:
a[5] = 17;
Tablice przykład 1
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int a1[10],a2[10];
int i;
for(i=1;i<11;i++)a1[i-1]=i;
for(i=0;i<10;i++)a2[i]=a1[i];
for(i=0;i<10;i++)printf("%d\n",a2[i]);
return 0;
}
WYNI
K
1
2
3
4
5
6
7
8
9
10
Łańcuchy znakowe jako
Łańcuchy znakowe jako
tablice
tablice
• Definiowanie zmiennej
przechowującej łańcuchy (teksty):
jako tablicy znaków:
char nazwa[długość]
na przykład:
char s[20];
• Na końcu łańcucha jest znak ’\0’
• Uwaga na długość!
• Funkcje operujące na łańcuchach
Operacje na
Operacje na
wskaźnikach
wskaźnikach
• Wskaźniki mogą być:
– porównywane
– odejmowane
– powiększane o wartość całkowitą
(skalowaną!)
– pomniejszane o wartość całkowitą
(skalowaną!)
• Dodanie 1 do wskaźnika powiększa
adres
o
rozmiar wskazywanego typu
Dodawanie liczby
Dodawanie liczby
całkowitej
całkowitej
do wskaźnika
do wskaźnika
double *pd;
double t[10];
pd = &(t[5]);
printf(”%p\n”,pd);
/* 0065FB60 */
pd = pd + 3;
printf(”%p\n”,pd);
/* 0065FB78 */
/* teraz pd wskazuje na t[8] */
0x18 = 24
=
= 3*8
Wskaźniki i tablice
Wskaźniki i tablice
• Nazwa tablicy jest synonimem
adresu jej początkowego elementu
• Przykład:
double x[5];
double *p;
p = x;
/* tak jak p = &(x[0]); */
*p = 12;
p++;
/* teraz p wskazuje na x[1] */
*p = 13;
/* tutaj x[0]=12, x[1]=13 */
Wyprowadzenie łańcucha
Wyprowadzenie łańcucha
bez użycia
bez użycia
printf
printf
#include <stdio.h>
main()
{
char s[]="Hello again!\n";
char *p;
p=s;
while (*p)
putchar (*p++);
return 0;
}
WYNIKI:
Hello again!
Nasza pamięć
Nasza pamięć
• Człowiek dysponuje (co najmniej)
dwoma rodzajami pamięci:
– dużą
: trwałą, ale trudną w zapisie
(czas zapisu jest długi)
– małą
: zanikającą w ciągu kilku
sekund, ale łatwą do zapisania
Funkcje
Funkcje
• Człowiek potrafi analizować jednocześnie
około 7 obiektów
• Co stanie się, jeśli program ma więcej niż
7 linii?
• Program należy podzielić na funkcje:
– Zapisać kilka linii kodu i nadać im nazwę
– Uruchamiać je stosując nazwę
• Oczywiście, nie jest to jedyny powód, dla
którego należy stosować funkcje...
Funkcje w języku C
Funkcje w języku C
Definicja funkcji ma następującą postać:
typ_wyniku nazwa_funkcji(opcjonalne
deklaracje_parametrów)
{
deklaracje
instrukcje
}
Przykład Funkcji podnoszenia do
potęgi
#include <stdio.h>
/* power: podnoszenie base to n-tej potęgi;
n >= 0 */
int power(int base, int n)
{
int i, p; /* zmienne lokalne */
p = 1;
for (i = 1; i <= n; ++i)
p = p * base;
return p;
}
main(){
int i;
for (i = 0; i < 10; ++i)
printf("%d %d %d\n",
i, power(2,i), power(-3,i));
return 0;}
Wyniki programu
0 1 1
1 2 –3
2 4 9
3 8 –27
4 16 81
5 32 –243
6 64 729
7 128 –2187
8 256 6561
9 512 -19683
Sterowanie -
Sterowanie -
dokończenie
dokończenie
• Konstrukcje poznane do tej pory:
– if
– if-else
– while
– for
• Inne:
– do-while
– switch
– break
– continue
Pętla
do-while
• Składnia:
do
instrukcja
while (wyrazenie);
• Przyklad:
int n;
do {
printf(”Podaj liczbę dodatnią: ”);
scanf(”%d”,&n);
} while (n<=0);
do-while
Przykład
#include<stdio.h>
main()
{
int n;
do {
printf("Podaj liczbę dodatnia: ");
scanf("%d",&n);
} while (n<=0);
}
do-while
Wyniki
programu
Podaj liczbę dodatnia: -4
Podaj liczbę dodatnia: -4
Podaj liczbę dodatnia: -3
Podaj liczbę dodatnia: -2
Podaj liczbę dodatnia: -1
Podaj liczbę dodatnia: 0
Podaj liczbę dodatnia: 1
Instrukcja
switch
•Składnia:
switch (wyrażenie) {
case wyrazenie-stale: instrukcje
case wyrazenie-stale: instrukcje
default: instrukcje
}
•Przykład:
switch (c=getchar()) {
case ’+’:
printf("Plus");
break;
case ’-’:
printf("Minus");
break;
default: printf("Inny znak");
}
Przerywanie pętli
Przerywanie pętli
•Czasem potrzebne okazuje się
przerwanie pętli w inny sposób niż
przy testowaniu warunku
•Instrukcja
break
daje możliwość
wyjścia z pętli
for, while
i
do
, tak
jak ze
switch
•break
powoduje, że przerywana
jest najbardziej wewnętrzna pętla
lub
switch
kalkulator Przykład
switch,
break
#include<stdio.h>
#include<stdlib.h>
int main(void){
int i,j;
char dz;
printf("wprowadz dzialanie\n");
scanf("%d%c%d",&i,&dz,&j);
switch(dz){
case '+':printf("%d",i+j);
break;
case'-':printf("%d",i-j);
break;
case'/':if(j)printf("%d",i/j);
break;
case'*':printf("%d",i*j);}
return 0;}
/*WYNIKI
wprowadz dzialanie
3-2
1
wprowadz dzialanie
4*5
20
wprowadz dzialanie
4+5
9
wprowadz dzialanie
4/2
2
*/
Pomijanie iteracji:
Pomijanie iteracji:
continue
continue
• Instrukcja
continue
jest podobna do
break
, jest stosowana rzadziej
• Powoduje rozpoczęcie kolejnej iteracji
for
,
while
, lub
do
bez dokańczania
bieżącej
• W pętli
while
i
do
oznacza to
natychmiastowe przejście do
testowania warunku
• W pętli
for
, sterowanie przechodzi do
części „inkrementującej”
• Instrukcja
continue
nie dotyczy
switch
. Zastosowana w tej instrukcji
pomija iterację pętli, w której
umieszczono
switch
continue
continue
: przykład
: przykład
• Przetwarzanie
tylko
nieujemnych
elementów tablicy a
• Ujemne wartości są pomijane
for (i = 0; i < n; i++)
{
if (a[i] < 0)
/* skip negative elements */
continue;
... /* do positive elements */
}
g
g
oto
oto
i etykiety
i etykiety
• W C dostępna jest instrukcja
goto
i etykiety do
opisywania celu skoku
• Formalnie, instrukcję
goto
można zastąpić innymi
• W praktyce łatwo jest pisać kod bez
goto
• Sytuacja,
w
której
goto
jest
przydatne:
przerywanie zagnieżdżonych pętli w sytuacji
wystąpienia błędu:
for (
...
)
for (
...
) {
...
if (katastrofa)
goto error;
}
...
error:
/* clean up the mess */
g
g
oto
oto
: inny przykład
: inny przykład
• Ustalenie, czy dwie tablice a i b mają
wspólny element:
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
if (a[i] == b[j])
goto found;
/* nie znaleziono wsp. elem. */
...
found:
/* znaleziono: a[i] == b[j] */
...
Unikanie
Unikanie
g
g
oto
oto
• Kod zawierający
goto
może zawsze zostać
zapisany bez tej instrukcji, choć czasem wymaga
to wprowadzenia dodatkowych zmiennych i
wydłużenia kodu:
found = 0;
for (i = 0; i < n && !found; i++)
for (j = 0; j < m && !found; j++)
if (a[i] == b[j])
found = 1;
if (found)
/* znaleziono: a[i-1] == b[j-1] */
...
else
/* nie znaleziono el. wsp. */
...