PODSTAWY INFORMATYKI
PODSTAWY INFORMATYKI
Wykład 4
Zmienne zewnętrzne i
Zmienne zewnętrzne i
lokalne
lokalne
int x;
/* zmienna zewnętrzna */
float func3(int z)
{ int x;
/* zmienna lokalna */
return 3*z;
}
main()
{
int y; ....
}
Zmienne lokalne
Zmienne lokalne
•
Zmienne zadeklarowane wewnątrz funkcji są
prywatne (lokalne) dla tej funkcji
•
Żadna inna funkcja nie ma do nich
bezpośredniego dostępu
•
Domyślnie, takie zmienne są automatyczne
•
Zmienne automatyczne są alokowane w
pamięci na czas wykonywania funkcji, potem
są usuwane
•
Nie zachowują wartości między wywołaniami
funkcji
•
Początkowo mają przypadkową wartość
•
Zmienne lokalne mogą być też statyczne;
wtedy nie są alokowane
Zmienne zewnętrzne
Zmienne zewnętrzne
• Zmienna zewnętrzna musi zostać
zdefiniowana, dokładnie raz, poza
jakąkolwiek funkcją (przydział pamięci)
• Zmienna musi również zostać
zadeklarowana w każdej funkcji, która
będzie jej używała; deklaracja określa typ
zmiennej
• Deklaracją może być
– jawna deklaracja extern
– pośrednia deklaracja - wynikająca z
kontekstu; definicja jest też deklaracją,
wystarczy umieścić ją przed użyciem zmiennej
Parametry i wyniki
Parametry i wyniki
funkcji
funkcji
•
Pierwszy wiersz funkcji power,
int power(int base, int n)
deklaruje typy parametrów i ich nazwy oraz typ wyniku
funkcji
•
Nazwy użyte przez power dla parametrów są lokalne dla
funkcji power, nie są widoczne dla żadnej innej funkcji
•
Będziemy stosować nazwę parametr dla nazwanej
zmiennej na liście parametrów funkcji. Czasem stosuje się
tu też nazwę argument formalny oraz argument aktualny
dla argumentu przekazywanego w wywołaniu funkcji
•
Wartość wyznaczana przez power jest zwracana instrukcją
return
•
Funkcja nie musi zwracać wartości
•
Zwracana wartość może zostać zignorowana
Prototypy funkcji
Prototypy funkcji
• Kompilator musi wiedzieć, że dany
identyfikator oznacza funkcję,
przed
jej
wywołaniem; musi również znać listę
parametrów
• W języku C można:
– zdefiniować
funkcję przed jej wywołaniem, lub
– zadeklarować
funkcję przed jej wywołaniem
stosując
prototyp
i zdefiniować ją później
• Deklaracja, nazywana
prototypem funkcji
,
musi
zgadzać się
z definicją funkcji
Definicje i prototypy
Definicje i prototypy
• Definicja
float fun(int x)
{ return 3*x;
}
int main()
{ float w;
w =
fun
(5);
...
return 0;
}
• Prototyp
...i definicja
float fun(int);
int main()
{ float w;
w =
fun
(5);
...
return 0;
}
float fun(int x)
{ return 3*x;
}
wywołani
e!
wywołani
e!
P
P
rzykład funkcji
rzykład funkcji
temperatury
temperatury
#include <stdio.h>
double cels(int x)
{ return (5.0/9.0)*(x-32);}
/* print Fahrenheit-Celsius table */
main()
{
int fahr;
for (fahr = 0; fahr<=300;fahr=fahr+20)
printf("%3d %6.1lf\n", fahr,
cels(fahr));
return 0;
}
Przykład funkcji wypisywania
znaku
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int daj_znak_a(void);
int main(void)
{
char ch;
ch=daj_znak_a();
printf("%c",ch);
return 0;
}
int daj_znak_a(void){
return 'a';
}
/*WYNIK
a*/
Przykład funkcji ze
wskaźnikiem
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int*inic(int x);
int licznik;
int main(void){
int*p;
p=inic(110);
printf("wartosc licznik (przez wskaznik p)wynosi
%d\n",*p);
return 0;
}
int*inic(int x){
licznik=x;
return &licznik;
}
/*WYNIK
wartosc licznik (przez wskaznik p)wynosi 110*/
Przykład funkcji
sumy/10
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
double srd();
int main(void){
printf("%f",srd());
return 0;
}
double srd(){int i; double
suma,num;suma=0.0;
for(i=0;i<4;i++){
printf("wprowadz kolejna liczba:\n");
scanf("%lf",&num);
suma=suma+num;
}
return suma/10.0;
}
Wynik programu
wprowadz kolejna liczba:3
wprowadz kolejna liczba:3
wprowadz kolejna liczba:4
wprowadz kolejna liczba:4
1.400000
Przykład funkcji
wypisywania
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void f2(int b);
void f1(int a);
int main(void){
f1(30);
return 0;
}
void f1(int a){
if(a)f2(a-1);
printf("%d",a);
}
void f2(int b){
printf(".");
if(b)f1(b-1);
}
/*WYNIK
...............024681012141618202224262830
*/
Przykład funkcji silnia
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int silnia(int i);
int main(void){
printf("5 silnia wynosi %d",silnia(5));
return 0;
}
int silnia(int i){
if(i==1){return 1;}
else
return i*silnia(i-1);
}
/*WYNIK
5 silnia wynosi 120*/
Przekazywanie wartości do
Przekazywanie wartości do
funkcji
funkcji
• Wszystkie
argumenty są
przekazywane przez wartość
• Wywoływana funkcja otrzymuje kopie
przekazanych wartości w zmiennych
lokalnych
• Aby uzyskać efekt przekazania
argumentu przez zmienną (jak w
języku Pascal), można użyć wskaźnika
jako typu parametru i przekazać
funkcji adres miejsca, które ma zostać
zmodyfikowane
Przekazywanie wartości do
Przekazywanie wartości do
funkcji
funkcji
• Przykład:
int fun5(double *w) { ... }
...
fun5(&x);
Przekazywanie tablic do
Przekazywanie tablic do
funkcji
funkcji
• Po zastosowaniu nazwy tablicy
jako argumentu funkcji,
przekazywany jest tylko
adres
początkowego elementu tablicy
• Nie są kopiowane elementy
tablicy!
• Więcej szczegółów o
przekazywaniu tablic funkcjom:
później
Konwersje typów
Konwersje typów
• Kiedy operator ma działać na
operandach różnych typów, są one
konwertowane przy zastosowaniu
według niewielkiego zbioru reguł.
double x, y;
int k;
y = x + k;
• Ogólnie, jedynymi automatycznymi
konwersjami są takie, które
przekształcają typ „mniejszy” w
„większy” bez utraty informacji.
Różne typy!
Konwersje typów - c.d.
Konwersje typów - c.d.
• Wyrażenia, które
nie mają sensu
, są
zakazane
• Przykład: użycie float jako indeksu
• Wyrażenia, w których można utracić
informację, powodują zgłoszenie
ostrzeżenia, ale są dozwolone;
przykłady:
– kopiowanie większego typu całkowitego do
mniejszego
– przypisanie wartości zmiennoprzecinkowej
do zmiennej całkowitej
Konwersje typów -
Konwersje typów -
reguły
reguły
• Jeśli nie występują operandy
unsigned
,
wystarczający jest następujący zestaw
reguł:
– Jeśli jeden z operandów jest typu
long
double
,
przekształć drugi na
long double
.
– W przeciwnym wypadku, jeśli jeden operand
jest
double
, przekształć drugi na
double
.
– W przeciwnym wypadku, jeśli operand jest
float
, przekształć drugi na
float
.
– W przeciwnym wypadku, przekształcić
char
i
short
na
int
.
– Potem, jeśli jeden z operandów jest
long
,
przekształć drugi na
long
.
Wymuszanie konwersji
Wymuszanie konwersji
• Jawna konwersja typu może być wymuszona
w wyrażenie przez zastosowanie operatora
rzutowania (ang. cast)
• W następującej konstrukcji:
(nazwa_typu) wyrażenie
wyrażenie jest przekształcane na wyrażenie
o podanym typie
cels = ((double)5/9) * (fahr-32);
• Konwersje są również wykonywane
w wywołaniach funkcji
Struktury
Struktury
•
Struktura jest obiektem zawierającym ciąg
nazwanych składowych niekoniecznie tego samego
typu
•
Słowo struct wprowadza deklarację struktury,
która jest listą deklaracji ujętą w nawiasy klamrowe
•
Po słowie struct może wystąpić opcjonalna nazwa
(structure tag)
•
Nazwa ta opisuje ten rodzaj struktury i może zostać
użyta potem jako skrót deklaracji w nawiasach
•
Dostęp:
struct-name.member
•
Przykład:
struct point {
int x;
int y;
}k;
Struktury - szczegóły
Struktury - szczegóły
• Przykład:
struct
point
{
int x;
int y;
}
k
;
struct point v, w;
v.x = 7;
v.y = 9;
w = v;
opcjonalna
nazwa
składo
we
opcjonalne definicje
zmiennych
Przypisywanie nazw typom
Przypisywanie nazw typom
strukturalnym
strukturalnym
typedef
struct {
float re, im;
} tcompl;
tcompl a, b, c;
a.re = 10.5;
a.im = 36.6;
b = c = a;
...działa jak:
struct compl {
float re, im;
};
struct compl a, b, c;
a.re = 10.5;
...
albo:
struct {
float re, im;
} a, b, c;
Do czego służą nazwy
Do czego służą nazwy
struktur
struktur
i typedef
i typedef
struct {
float re, im;
} a, b;
struct {
float re, im;
} c;
a.re = 10.5;
a.im = 36.6;
c
=
a;
struct compl {
float re, im;
} a, b;
struct compl c;
...
c
=
a;
struct {
float re, im;
} a, b, c;
ZAKAZAN
E
OK
Struktury przykład 1
#include<stdio.h>
#include<stdlib.h>
struct typ_s {
int i;
char ch;
double d;
char nap[80];
}s;
int main(void){
printf("wprowadz liczbe calkowita:\n");
scanf("%d",&s.i);
printf("wprowazdz znak:");
scanf("%c",&s.ch);
printf("wprowadz liczbe zmiennoprzecinkowa:\n");
scanf("%lf",&s.d);
printf("wprowadz napis:");
scanf("%s",s.nap);
printf("%d%c%f%s",s.i,s.ch,s.d,s.nap); return 0;}
Wynik programu
wprowadz liczbe calkowita:4
wprowazdz znak:wprowadz liczbe
zmiennoprzecinkowa:4.5
wprowadz napis:ttt
4
4.500000ttt
Struktury przykład 2
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
struct typ_s{
int i;
int j;
}s;
int i;
i=10;
s.i=100;
s.j=101;
printf("%d%d%d",i,s.i,s.j);
return 0;}
/*
WYNIK
10100101
*/
Struktury przykład 3
#include<stdio.h>
#include<stdlib.h>
struct typ_s{
int i;
double d;
};
void f(struct typ_s tymcz);
int main(void)
{
struct typ_s zmi1;
zmi1.i=99;
zmi1.d=98.6;
f(zmi1);
return 0;
}
void f(struct typ_s tymcz){
printf("%d %f",tymcz.i,tymcz.d);
}
/*
WYNIK
99 98.600000
*/
Struktury mogą być
Struktury mogą być
zwracane przez funkcje
zwracane przez funkcje
typedef struct {
float re, im;
} cplx;
cplx
mult(cplx c, float x)
{
c.im *= x;
c.re *= x;
return c;
}
Struktury mogą być
Struktury mogą być
zagnieżdżane
zagnieżdżane
typedef struct {
char name[50];
struct {
int ye, mo, da;
} birthdate;
} tperson;
tperson p1;
strcpy(p1.name,"Jan Kowalski");
p1.birthdate.ye = 1945;
p1.birthdate.mo = 1;
p1.birthdate.da = 17;
Tablice struktur
Tablice struktur
typedef struct {
double re,im;
} tcplx;
void test()
{
int i;
tcplx tab[50];
for (i=0;i<50;i++)
tab[i].re = tab[i].im = 0.0;
}