Wykład 1: Wskaźniki Podstawy programowania Programowanie w C

Slides:



Advertisements
Podobne prezentacje
Tablice 1. Deklaracja tablicy
Advertisements

C++ wykład 2 ( ) Klasy i obiekty.
C++ wykład 4 ( ) Przeciążanie operatorów.
Język C/C++ Funkcje.
Programowanie obiektowe
Standardowa biblioteka języka C++
1 Wskaźniki w C Podstawy podstaw podstaw podstaw.....
Prowadzący: mgr inż. Elżbieta Majka
argumenty wiersza poleceń: getopt
Podstawy informatyki Wirtotechnologia – Wskaźniki i referencje
Podstawy informatyki Powtórka Grupa: 1A Prowadzący: Grzegorz Smyk
Wskaźniki. Definiowanie wskaźników Wskaźnik może wskazywać na obiekt dowolnego typu. int * w; char * Wsk_Znak; float * Wskaz_Real; Przykłady: Wskaźnik.
Struktury.
Tablice.
C++ wykład 2 ( ) Klasy i obiekty.
Podstawy programowania PP – WYK3 Wojciech Pieprzyca.
Podstawy programowania PP – LAB4 Wojciech Pieprzyca.
Podstawy programowania PP – LAB5 Wojciech Pieprzyca.
Zachodniopomorskie Centrum Edukacyjne Zadanie domowe.
nowe operatory & . (kropka) * operator rzutowy -> , (przecinek)
Podstawy programowania II
Podstawy informatyki (4)
Jerzy F. Kotowski1 Informatyka I Wykład 9 TABLICE PREPROCESOR OPERATORY c.d. (nie tylko binarne)
Podstawy programowania
Podstawy informatyki 2013/2014
Wskaźnik może wskazywać na obiekt dowolnego typu. int * w; char * Wsk_Znak; float * Wskaz_Float; Przykład: Wskaźnik przechowuje adres obiektu wskazanego.
struct nazwa { lista składników }; Dostęp do składowych struktury Nazwa_Zmniennej_Strukturalnej. Nazwa_Składnika.
Podstawy programowania
Informatyka I Wykład 10 WSKAŹNIKI I ADRESY Jerzy F. Kotowski.
TABLICE C++.
Procedury i funkcje.
Podstawy programowania
Podstawy programowania w języku C i C++
Jerzy F. Kotowski1 Informatyka I Wykład 14 DEKLARATORY.
Jerzy F. Kotowski1 Informatyka I Wykład 15 PIERWSZE KROKI.
Programowanie obiektowe Wykład 3 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21 Dariusz Wardowski.
Programowanie obiektowe Wykład 6 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14 Dariusz Wardowski.
Podstawy informatyki 2013/2014
Programowanie obiektowe 2013/2014
jeszcze dygresja o macierzach...
Kurs języka C++ – wykład 3 ( )
Kurs języka C++ – wykład 8 ( )
Kurs języka C++ – wykład 9 ( )
Programowanie w języku C++
Programowanie strukturalne i obiektowe C++
Programowanie strukturalne i obiektowe C++
Programowanie strukturalne i obiektowe C++
Zmienne i typy danych w C#
Kurs języka C++ – wykład 4 ( )
K URS JĘZYKA C++ – WYKŁAD 1 ( ) Łagodne wprowadzenie do języka C++
Modele pamięci Tiny - mikroskopijny do 64 K zmienne inicjalizowane kod programu zmienne nie inicjalizowane HEAP (sterta) obszar wolny STACK (stos) Model.
Programowanie obiektowe Wykład 9 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/15 Dariusz Wardowski.
1 dynamiczny przydział pamięci malloc() free() realloc() calloc() memset() memcpy( ) mempcpy( ) memmove() (wskaźniki!! )
Przeładowanie funkcji. Dotychczas wiedzieliśmy, że: w danym zakresie ważności może być tylko jedna funkcja o danej nazwie. Kompilator języka C++ daje.
Dziedziczenie Wykład 7 Dziedziczenie sekwencyjne
Wykład 4 Klasa Vec, której konstruktory alokują pamięć dla obiektów 1.Przykład definicji klasy Vec 2.Definicje konstruktorów i destruktora 3.Definicja.
PO13-1 / 19 Wykład 13 Wyjątki i ich zgłaszanie Wyłapywanie wyjątków Obsługa wyjątków Wykorzystanie polimorfizmu Filtrowanie wyjątków Błędy w konstruktorach.
Seminarium Dyplomowe: Metodyka i Techniki Programowania Autor: Bartłomiej Fornal.
Podstawy informatyki Tablice Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi.
1 Opisy funkcji Adres strony WWW : html (należy odszukać hyperlink Function Index) (
Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego Matuszyka Podstawy.
Podstawy informatyki Struktury Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi.
Podstawy informatyki Operatory rzutowania Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały.
K URS JĘZYKA C++ – WYKŁAD 3 ( ) Przenoszenie Składowe statyczne Funkcje wbudowane Argumenty domyślne.
C++ mgr inż. Tomasz Turba Politechnika Opolska 2016.
Wskaźniki Elżbieta Labocha.
Opisy funkcji Adres strony WWW :
nowe operatory & . (kropka) * operator rzutowy -> , (przecinek)
Język C++ Typy Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego.
Język C++ Tablice Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego.
Zapis prezentacji:

Wykład 1: Wskaźniki Podstawy programowania Programowanie w C Dr inż. Zdzisława Rowińska III p. KIS, pokój 314, zrow@kis.p.lodz.pl

Gdzie wykorzystywane są wskaźniki? Praca z tablicami Funkcje – zmiana wartości przesyłanych argumentów Dostęp do specjalnych komórek pamięci Rezerwacja obszarów pamięci

Definiowanie wskaźników typ_obiektu *nazwa_wskaźnika; nazwa_wskaźnika wskazuje na obiektu typu typ_obiektu. Przykłady Można definiować wskaźniki do obiektów różnych typów: int *wi; char *wch; float *wf; Uwaga: Z definicji wskaźnika wynika, że wskaźnik pokazuje na obiekt. Referencja nie jest obiektem, dlatego nie można definiować wskaźników do referencji. Wskaźnik, który pokazuje na obiekt jednego typu, nie może być wykorzystany do pokazywania na obiekt innego typu.

Wskaźniki Sama definicja wskaźnika nie powoduje, że wskaźnik wskazuje na konkretny obiekt. Nadanie wartości obiektowi (wskaźnik wskazuje na istniejący obiekt): int *wi; int i; wi=&i; //ustawienie wskaźnika w na obiekt i Jeśli wskaźnik wskazuje na konkretny obiekt, to można odnosić się do tego obiektu za pomocą wskaźnika. Do operacji tej służy jednoargumentowy operator odniesienia (wyłuskania, dereferencji) * *nazwa_wskaźnika; Przykład: int *wi; //definicja wskaźnika int i; //definicja zmiennej i wi=&i; //ustawienie wskaźnika *wi=5; //przypisanie wartości 5 zmiennej i

Wskaźniki – cd Przykłady: int *wi,*wj; //definicja wskaźnika int i,j; //definicja zmiennych i,j wi=&i; i=5; *wi=5; j=7; j=*wi; wi=&j; wj=wi;

Wskaźniki typu void void *wv; Definicja wskaźnika bez podania typu obiektu, na jaki wskazuje. Może być użyty do wskazywania na obiekty dowolnego typu. Przykłady: void *wv; int *wi; float *wf; wv=wi; //teraz wskaźnik wv wskazuje na ten sam obiekt (typu int), //na który wskazuje wskaźnik wi wv=wf; wi=wf //kompilator zasygnalizuje błąd!! wi=(int *)wf; //wykorzystanie rzutowania wf=(float *)wv; //wykorzystanie rzutowania Wskaźnikowi typu void można przypisać wskaźnik dowolnego (niestałego) typu. Działanie odwrotne wymaga operatora rzutowania.

Zastosowanie wskaźników do tablic int *wsk; //definicja wskaźnika int tab[10]; //definicja tablicy wsk=&tab[indeks]; //ustawienie wskaźnika na elemencie tablicy //o indeksie indeks wsk=&tab[0]; wsk=tab; wsk=&tab[indeks]; wsk=wsk+ind; wsk += ind; //przesunięcie wskaźnika o ind pozycji instrukcje równoważne Dodanie do wskaźnika liczby całkowitej ind powoduje, że wskaźnik pokazuje o ind elementów dalej w tablicy; niezależnie od tego, jakiego typu są elementy tablicy.

Zastosowanie wskaźników do tablic Przykład: #include <iostream.h> void main(){ float *wf; float tab[10]; wf=tab; //lub wf=&tab[0]; for(int i=0; i<10; i++){ *(wf++)=i/10.0; } for(i=0,wf=tab;i<10;i++,wf++) printf(”%f\n”,*wf);

Nazwa tablicy i wskaźnik Nazwa tablicy jest jednocześnie adresem jej zerowego elementu. Nazwa tablicy jest stałym wskaźnikiem do jej zerowego elementu. float *wsk; float tab[10]; wsk=tab; //wsk=&tab[0]; //możliwe jest przypisanie wsk++; //niemożliwa jest instrukcja tab++; tab[ind]; *(tab+ind); Wskaźnik jest pewnym obiektem w pamięci (to znaczy posiada swój adres). Nazwa (również tablicy) nie jest obiektem (nie ma więc adresu). float *wsk; &wsk; //adres wskaźnika – odwołanie poprawne

Wskaźniki w argumentach funkcji void fun(float f) { f /= 3.3; } float fun(float *f) { *f /= 3.3; Przesyłanie argumentów przez wartość. Funkcja nie zmienia wartości przesyłanego argumentu. void main() { float fvar = 13.3; fun(fvar); printf(”%f\n”, fvar); // 13.3 fun(&fvar); printf(”%f\n”, fvar); // 4.03 } Przesyłanie argumentów przez wskaźnik. Zmiana wewnątrz funkcji wartości przesyłanego argumentu. 10

Przesyłanie tablic do funkcji #include <iostream.h> void f1(int *pi, int rozm); void f2(int *pi, int rozm); void f3(int t[], int rozm); void main(){ int tab[5]={1,2,3,4,5}; f1(tab,5); f2(tab,5); f3(tab,5); } void f1(int *pi, int rozm){ printf("\nfunkcja f1\t”); for(int i=0;i<rozm;i++) printf(”%f\t”,*(pi++)); void f2(int *pi, int rozm){ print(”%f\t”,pi[i]); void f3(int t[], int rozm){ printf("\nfunkcja f3\t”); print(”%f\t”,t[i])); Przesyłanie tablic do funkcji Funkcje są wywoływane przez podanie nazwy tablicy Przesłany adres tablicy inicjalizuje lokalny wskaźnik pi. Wewnątrz funkcji - zapis wskaźnikowy Przesłany adres tablicy inicjalizuje lokalny wskaźnik pi. Wewnątrz funkcji - zapis tablicowy Przesłany adres tablicy odebrany jako tablica 11

Przesyłanie tablic do funkcji – cd Odebranie tablicy jako tablicy – czytelność funkcji Odebranie tablicy jako adresu inicjującego wskaźnik – funkcja działa szybciej Odebranie tablicy jako adresu – łatwiejsze przekazywanie tablic wielowymiarowych (rozmiary tablicy nie muszą być znane w momencie wywołania funkcji) 12

Wskaźniki do stałych Wskaźniki do stałych mogą zawierać adresy dowolnych zmiennych i mogą być modyfikowane w programie, ale nie można za ich pomocą modyfikować zmiennych wskazywanych. const int stala = 10; // definicja stałej typu int const int *wsk_st; // wskaźnik do stałej typu int void main() { int i = 5; const int *w = &i; // wskaźnik zainicjowany wsk_st = &i; // inicjacja adresem zmiennej automatycznej i cout << *wsk_st << endl; // 5 cout << *w << endl; // 5 // *w = *w + 5; // błąd kompilatora ! // *wsk_st+= 7; // nie można modyfikować stałej wsk_st = &stala; // wskaźnik inicjowany adresem stałej w = &stala; // wskaźnik inicjowany adresem stałej cout << *wsk_st << endl; // 10 cout << *w << endl; // 10 } 13

Stałe wskaźniki Stały wskaźnik to wskaźnik, który zawsze pokazuje na to samo. Wskaźnik tego typu musi być zainicjowany w miejscu definicji - tak jak każda stała. W programie nie można już modyfikować jego wartości. Za pomocą wskaźnika stałego można jednak modyfikować zawartość zmiennej wskazywanej, ale tylko tej, której adresem wskaźnik został zainicjowany. const int st = 4; // stała int zm = 10; // definicja zmiennej int * const w = &zm; // stały wskaźnik do zmiennej zm // int * const x = &st; // błąd – wskaźnik musi wskazywać na zmienną const int * const x = &st; // dobrze - stały wskaźnik do stałej int i = 7; int * const wi = &i; // stały wskaźnik do zmiennej lokalnej i int * const pz = &zm; // stały wskaźnik do zmiennej zm cout << *wi << endl; // i=7 = i cout << *pz << *w << endl; // 10 i 10; zm=10 *wi +=8; // i = 7 + 8 = 15 cout << i << endl; // i =15 // wi = &zm; // błąd – nie wolno zmieniać stałej wi *pz += 2; // zm = 10 + 2 cout << zm << endl; // zm = 12 14

Wskaźniki do funkcji typ_zwracany (*wsk_do_funkcji)([argumenty_funkcji]); #include <iostream.h> void f1(); void f2(); void blad(); void main(){ void (*pf)()=blad; int i; cin>>i; if(i==1) pf=f1; else if(i==2) pf=f2; (*pf)(); } void f1(){ cout<<"funkcja f1\n"; void f2(){ cout<<"funkcja f2\n"; void blad(){ cout<<"blad\n"; 15

Wskaźniki do funkcji Nazwa funkcji jest adresem jej początku (adresem miejsca w pamięci, gdzie zaczyna się kod tej funkcji). Zastosowanie wskaźników do funkcji: Przesyłanie argumentów do funkcji. Adres funkcji można wysłać jako argument. Tworzenie tablic ze wskaźników do funkcji. 16

Przesyłanie argumentów do funkcji #include <iostream.h> void f1(); void f2(); void blad(); void funkcja(int i, void (*pf)()); void main(){ void (*pf)()=NULL; int i; cin>>i; funkcja(i,pf); } void funkcja(int i, void (*pf)()){ pf=blad; if(i==1) pf=f1; else if(i==2) pf=f2; (*pf)(); void f1(){ cout<<"funkcja f1\n"; void f2(){ cout<<"funkcja f2\n"; void blad(){ cout<<"blad\n"; Przesyłanie argumentów do funkcji 17

Tablice wskaźników typ_wskazywany *tablica[rozmiar]; //typ_wskazywany *(tablica[rozmiar]); zapis równoważny double *tablica[10]; 18

Tablice wskaźników - cd #include <iostream.h> void f1(); void f2(); void blad(); void main(){ void (*pt[3])()={f1,f2,blad}; for(int i=0;i<3;i++) (*pt[i])(); } void f1(){ cout<<"funkcja f1\n"; void f2(){ cout<<"funkcja f2\n"; void blad(){ cout<<"blad\n"; Tablica wskaźników do funkcji 19

Pamięć a zmienne w programie Ze względu na czas życia wyróżnia się: - obiekty statyczne - istniejące od chwili rozpoczęcia działania programu aż do jego zakończenia - obiekty dynamiczne - tworzone i usuwane z pamięci w trakcie wykonania programu: - automatycznie, czyli bez udziału programisty - kontrolowane przez programistę

Pamięć a zmienne w programie O tym czy obiekt jest statyczny czy dynamiczny decyduje miejsce deklaracji oraz klasa pamięci (przypisywana jawnie w deklaracji lub przyjmowana domyślnie). Klasę pamięci określają słowa kluczowe: auto, static, register, umieszczane przed deklaracją zmiennej, np. static int x; wszystkie zmienne globalne są statyczne wszystkie zmienne lokalne zadeklarowane bez jawnego specyfikowania klasy pamięci są automatyczne (auto). Zmienną lokalną można uczynić statyczną dodając przed deklaracją static (czasami stosowane w funkcjach) zmienne klasy register są automatyczne

Funkcje malloc, calloc, free Dynamiczna alokacja pamięci Funkcje malloc, calloc, free W języku C/C++ istnieją standardowe funkcje umożliwiające dynamiczną alokację pamięci (malloc i calloc) oraz funkcja zwalniająca przydzieloną pamięć (free). Prototypy funkcji: void *malloc(size_t K); // alokacja K bajtów void *calloc(size_t N, size_t K); // alokacja N razy po K bajtów void free(void *x); // zwolnienie obszaru Funkcje malloc i calloc przydzielają spójne obszary pamięci, których rozmiary nie przekraczają 64 KB (size_t jest zdefiniowany jako unsigned) i zwracają wskazanie do przydzielonego obszaru. Jeżeli alokacja nie jest możliwa, to zwracany jest wskaźnik NULL. Funkcja calloc dodatkowo zeruje przydzieloną pamięć. Funkcja free zwraca do systemu przydzieloną pamięć. Funkcje malloc i calloc zwracają wskaźniki do typu void dlatego niezbędne są konwersje typu przy podstawieniach do wskaźników innych typów. Należy uważać, aby za pomocą funkcji free nie zwalniać pamięci, która nie została przydzielona. 22

Funkcje malloc, calloc, free Dynamiczna alokacja pamięci Funkcje malloc, calloc, free Przykład: void main() { int i; char* ps = NULL; //wskaźnik do char ps = (char*) malloc(5 * sizeof(char)); //alokacja pamięci na //elementy typu char if (ps) strcpy(ps, "Ola"); for (i = 0; i < strlen(ps); i++) printf("%c\n", *(ps + i)); //wypisanie i-tego //elementu tablicy free(ps); //zwolnienie pamięci ps = NULL; } 23

Dynamiczny przydział pamięci - przykład Przydział pamięci dla n-liczb typu int, wczytanie liczb, obliczenie średniej #include <stdio.h> #include <stdlib.h> int main() { int *tab, i, n, x; float suma = 0.0; printf("Podaj ilosc liczb: "); scanf("%d",&n); tab = (int *) calloc(n,sizeof(int)); if (tab == NULL) printf("Nie mozna przydzielic pamieci.\n"); exit(-1); } for (i=0; i<n; i++) /* wczytanie liczb */ printf("Podaj liczbe nr %d: ",i+1); scanf("%d",&x); tab[i] = x; for (i=0; i<n; i++) suma = suma + tab[i]; printf("Srednia %d liczb wynosi %f\n",n,suma/n); free(tab); return 0;

Dynamiczny przydział pamięci na tablicę dwuwymiarową (macierz): Zamiast standardowego odwołania do elementów macierzy: tab[i][j] stosujemy odwołania do odpowiednich elementów wektora: *(tab+M*i+j) lub tab[M*i+j], gdzie M –liczba kolumn Przykład: tablica tab, dla której N=3, M=4 odwołujemy się do elementu tab[2][2]: *(tab+4*2+2)

Przydział pamięci na tablicę NxM, wygenerowanie i wyświetlenie liczb #include <stdio.h> #include <stdlib.h> #include <time.h> #define N 4 #define M 6 int main() { int i,j,*tab; tab = (int *) calloc(N*M,sizeof(int)); srand(time(NULL)); for (i=0;i<N;i++) for (j=0;j<M;j++) *(tab+M*i+j) = rand()%100; printf("%4d",tab[M*i+j]); printf("\n"); } free(tab); return 0;

Metoda 2 (wskaźnik na tablicę wskaźników): Przydzielamy pamięć na N-elementowy wektor wskaźników na typ int, a następnie do kolejnych elementów tego wektora zapisujemy adresy M-elementowych wektorów liczb typu int (pamięć na wektory jest także przydzielana dynamicznie) int **tab; tab = (int**) calloc(N,sizeof(int *)); for (i=0; i<N; i++) tab[i] = (int*) calloc(M,sizeof(int));

Przydział pamięci na tablicę NxM, wygenerowanie i wyświetlenie liczb #include <stdio.h> #include <stdlib.h> #include <time.h> #define N 4 #define M 6 int main() { int i, j, **tab; tab = (int **) calloc(N,sizeof(int *)); for (i=0;i<N;i++) tab[i] = (int*) calloc(M,sizeof(int)); srand(time(NULL)); for (j=0;j<M;j++) tab[i][j] = rand()%100; printf("%4d",tab[i][j]); printf("\n"); } free(tab[i]); /*w pierwszej kolejności zwalniamy pamięć przydzieloną na N wektorów, każdy o rozmiarze M */ free(tab); /*zwalniamy pamięć przydzieloną na N-elementowy wektor wskaźnikow na typ int */ return 0;