Poprzedni wykład [ ] :

Podobne dokumenty
Pliki. Informacje ogólne. Obsługa plików w języku C

Biblioteka standardowa - operacje wejścia/wyjścia

Wstęp do wskaźników w języku ANSI C

Podstawy programowania skrót z wykładów:

Programowanie proceduralne INP001210WL rok akademicki 2015/16 semestr letni. Wykład 6. Karol Tarnowski A-1 p.

Pliki. Informacje ogólne. Obsługa plików w języku C

Lab 9 Podstawy Programowania

Ćwiczenie 4. Obsługa plików. Laboratorium Podstaw Informatyki. Kierunek Elektrotechnika. Laboratorium Podstaw Informatyki Strona 1.

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 12. Karol Tarnowski A-1 p.

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

Obsługa plików. Laboratorium Podstaw Informatyki. Kierunek Elektrotechnika. Laboratorium Podstaw Informatyki Strona 1. Kraków 2013

Programowanie proceduralne INP001210WL rok akademicki 2018/19 semestr letni. Wykład 6. Karol Tarnowski A-1 p.

Tablice, funkcje - wprowadzenie

Podstawy programowania w języku C++

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

2 Przygotował: mgr inż. Maciej Lasota

Wskaźniki. nie są konieczne, ale dają językowi siłę i elastyczność są języki w których nie używa się wskaźników typ wskaźnikowy typ pochodny:

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1

Języki i metodyka programowania. Typy, operatory, wyrażenia. Wejście i wyjście.

Ćwiczenie nr 6. Poprawne deklaracje takich zmiennych tekstowych mogą wyglądać tak:

Języki programowania obiektowego Nieobiektowe elementy języka C++

IX. Wskaźniki.(3 godz.)

INFORMATYKA Studia Niestacjonarne Elektrotechnika

Podstawy programowania w języku C++

Funkcje zawarte w bibliotece < io.h >

Tablice deklaracja, reprezentacja wewnętrzna

Stałe, znaki, łańcuchy znaków, wejście i wyjście sformatowane

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Funkcje zawarte w bibliotece < io.h >

Podstawy programowania w języku C++

OPERACJE WEJŚCIA / WYJŚCIA. wysyła sformatowane dane do standardowego strumienia wyjściowego (stdout)

Podstawy informatyki. Elektrotechnika I rok. Język C++ Operacje na danych - wskaźniki Instrukcja do ćwiczenia

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

ISO/ANSI C - funkcje. Funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje

Funkcja (podprogram) void

Techniki Programowania wskaźniki

Wstęp do programowania INP003203L rok akademicki 2018/19 semestr zimowy. Laboratorium 2. Karol Tarnowski A-1 p.

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

ŁAŃCUCHY W JĘZYKU C/C++

Wskaźniki w C. Anna Gogolińska

DANE TEKSTOWE W JĘZYKU C/C++ - TABLICE ZNAKOWE

Języki programowania. Przetwarzanie tablic znaków. Część druga. Autorzy Tomasz Xięski Roman Simiński

Programowanie w językach wysokiego poziomu

Podstawy programowania. Wykład Pętle. Tablice. Krzysztof Banaś Podstawy programowania 1

Podstawy programowania

1. Pierwszy program. Kompilator ignoruje komentarze; zadaniem komentarza jest bowiem wyjaśnienie programu człowiekowi.

Wskaźniki. Programowanie Proceduralne 1

Języki programowania. Przetwarzanie plików amorficznych Konwencja języka C. Część siódma. Autorzy Tomasz Xięski Roman Simiński

Zmienne, stałe i operatory

Wykład VII. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

1 Wskaźniki i zmienne dynamiczne, instrukcja przed zajęciami

wykład II uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C - funkcje, tablice i wskaźniki wykład II dr Jarosław Mederski Spis

Zadanie nr 2: Arytmetyka liczb zespolonych

Podstawy programowania 1

Języki programowania. Karolina Mikulska-Rumińska Pokój 573, tel Konsultacje wtorek 9-10.

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

Tablice, funkcje, wskaźniki - wprowadzenie

Języki i metodyka programowania. Wprowadzenie do języka C

Tablice (jedno i wielowymiarowe), łańcuchy znaków

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy WSKAŹNIKI KLASOWE

Poprzedni wykład [ ] :

utworz tworzącą w pamięci dynamicznej tablicę dwuwymiarową liczb rzeczywistych, a następnie zerującą jej wszystkie elementy,

Stałe i zmienne znakowe. Stała znakowa: znak

Język C zajęcia nr 11. Funkcje

Język C++ zajęcia nr 2

Wskaźniki. Przemysław Gawroński D-10, p marca Wykład 2. (Wykład 2) Wskaźniki 8 marca / 17

Operacje wejścia/wyjścia odsłona pierwsza

Wstęp do programowania obiektowego. Przekazywanie parametrów do funkcji w C++ Metody i funkcje operatorowe Strumienie: standardowe, plikowe, napisowe

Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1

Języki programowania C i C++ Wykład: Typy zmiennych c.d. Operatory Funkcje. dr Artur Bartoszewski - Języki C i C++, sem.

> C++ wskaźniki. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki 26 kwietnia 2017

Część 4 życie programu

Programowanie komputerowe. Zajęcia 1

Informatyka I. Typy danych. Operacje arytmetyczne. Konwersje typów. Zmienne. Wczytywanie danych z klawiatury. dr hab. inż. Andrzej Czerepicki

7 Przygotował: mgr inż. Maciej Lasota

Operatory. Operatory bitowe i uzupełnienie informacji o pozostałych operatorach. Programowanie Proceduralne 1

Wstęp do programowania INP003203L rok akademicki 2018/19 semestr zimowy. Laboratorium 3. Karol Tarnowski A-1 p.

#include <stdio.h> void main(void) { int x = 10; long y = 20; double s; s = x + y; printf ( %s obliczen %d + %ld = %f, Wynik, x, y, s ); }

#include <stdio.h> int main( ) { int x = 10; long y = 20; double s; s = x + y; printf ( %s obliczen %d + %ld = %f, Wynik, x, y, s ); }

Argumenty wywołania programu, operacje na plikach

część 8 wskaźniki - podstawy Jarosław Gramacki Instytut Informatyki i Elektroniki Podstawowe pojęcia

Podstawy Programowania. Specyfikacja funkcji, operacje wejścia i wyjścia na plikach, rekurencja, tablice i wskaźniki

Podstawy Programowania

Ghost in the machine

1 Podstawy c++ w pigułce.

//zmienne globalne int *pa, *pb; //wskaźniki globalne void main(void) { clrscr(); printf("\n podaj wartosc liczby a\n"); scanf("%d",&a); pa=&a;

Operacje na plikach. Informatyka. Standardowe strumienie wejścia i wyjścia

Podstawy programowania w języku C++

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 6. Karol Tarnowski A-1 p.

Laboratorium nr 4: Arytmetyka liczb zespolonych

Podstawy programowania C. dr. Krystyna Łapin

Temat 1: Podstawowe pojęcia: program, kompilacja, kod

1 Podstawy c++ w pigułce.

Podstawy Informatyki. Inżynieria Ciepła, I rok. Wykład 10 Kurs C++

Wskaźniki do funkcji. Wykład 11. Podstawy programowania ( język C ) Wskaźniki do funkcji (1) Wskaźniki do funkcji (2)

Instrukcja do ćwiczeń nr 4 typy i rodzaje zmiennych w języku C dla AVR, oraz ich deklarowanie, oraz podstawowe operatory

TABLICE W JĘZYKU C/C++ typ_elementu nazwa_tablicy [wymiar_1][wymiar_2]... [wymiar_n] ;

Wykład VI. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

Transkrypt:

Poprzedni wykład [ 27.11.2018 ] : - Funkcje i struktura programu - Zasady podziału programu na pliki ( nagłówki, pliki źródłowe, kody pośrednie, plik wykonywalny ) - Polecenie make i pliki Makefile - Preprocesor języka C Adam Rycerz [ wyklad07.pdf ] Strona 1 z 34

Preprocesor języka C (przypomnienie) Preprocesor to narzędzie uruchamiane bezpośrednio przed tłumaczeniem programu na kod maszynowy; umożliwia mechaniczne generowanie pewnych fragmentów kodu źródłowego. Przykładowo, dyrektywy: #include <nazwa1> #include nazwa2 powodują wstawienie zawartości pliku o podanej nazwie. Z kolei dyrektywa: #define nazwa tekst-zastępujący to tzw. makrodefinicja (lub makro): powoduje, że każde pojawienie się słowa nazwa zostanie zastąpione przez tekst-zastępujący. Adam Rycerz [ wyklad07.pdf ] Strona 2 z 34

Makra z parametrami (przypomnienie) Makra takie jak: #define max(a,b) ( (A)>(B)? (A) : (B) ) wywołuje się podobnie jak funkcje: x=max(p+q, r+s); Makra jednak nie są funkcjami argumenty aktualne nie są obliczane lecz mechanicznie podstawiane w miejscach, gdzie w definicji makra (po prawej stronie) występują parametry formalne. [ => W definicji makra nie może zabraknąć nawiasów! ] Rozwijanie argumentów wewnątrz napisów: #define xprint(a) printf( Wartość #A = %g\n, A) Wywołanie: xprinf(x/y); jest równoważne instrukcji: printf( Wartość x/y = %g\n,x/y); Adam Rycerz [ wyklad07.pdf ] Strona 3 z 34

Wskaźniki i tablice Wskaźnik = zmienna, która przechowuje adres innej zmiennej w pamięci komputera Ponieważ tablice w C są niskopoziomowe ( tablica = ciągły zbiór komórek pamięci ) związek ze wskaźnikami jest b. silny: => nazwa tablicy jest adresem jej pierwszego elementu [ Pewne operacje z zakresu tzw. arytmetyki wskaźników są jednak niedozwolone dla tablic. ] Adam Rycerz [ wyklad07.pdf ] Strona 4 z 34

Jednoargumentowy operator adresu (referencji) pozwala uzyskać adres zmiennej, która jest jego argumentem. Jeśli np. x==6.5 jest typu double, zaś px to wskaźnik na double, wówczas instrukcja: px = &x; przypisuje px adres x. Odwrotnie działa operator dereferencji (wyłuskania): (*px) będzie liczbą typu double wydobytą spod adresu px. [ Źródło: https://www.physics.drexel.edu/~valliere/general/c_basics/c_tutorial.html ] Adam Rycerz [ wyklad07.pdf ] Strona 5 z 34

Przykładowo, po zestawie deklaracji: int x=1, y=2, z[10]; /* 2 zmienne + tablica */ int *ip; /* ip to >>wskaźnik do int<< */ poprawne będą instrukcje: ip = &x; /* teraz ip >wskazuje< x*/ y = *ip; /* y ma wartość 1 */ *ip = 0; /* x ma wartość 0 */ ip = &z[0]; /* ip wskazuje z[0] */ Ogólnie, deklaracja wskaźnika, np. double *px; ma formę tzw. mnemonika informuje, że wynikiem dereferencji ( *px ) będzie liczba typu double. [ Inna forma: double* px; ] Podobnie, prototyp funkcji: double atof(char*); informuje, że argument to wskaźnik na char. Adam Rycerz [ wyklad07.pdf ] Strona 6 z 34

Zasadniczo, wskaźnik zawsze wskazuje określony rodzaj obiektu; jest zatem powiązany z konkretnym typem danych. Niekiedy wygodnie będzie użyć np. jako parametru funkcji wskaźnika do void który pozwala przechować dowolny rodzaj wskaźnika (dereferencja jest wówczas niemożliwa!). Jeśli (przykładowo!) ip jest wskaźnikiem na x typu int wyrażenie *ip może wystąpić wszędzie tam, gdzie samo x : *ip = *ip + 10; /* zwiększa *ip o 10 */ y = *ip + 1; /* pobiera *ip, dodaje 1, */ *ip += 1; /* zwiększa *ip o 1 */ Adam Rycerz [ wyklad07.pdf ] Strona 7 z 34

Zwiększenie wartości wskazywanej o 1 następuje także w wyrażeniach: ++*p oraz (*p)++ [ UWAGA na nawiasy! ] Dla odmiany, wyrażenie: *p++ spowoduje zwiększenie wskaźnika, zamiast wartości wskazywanej ( po takiej operacji, p będzie wskazywać na następną komórkę pamięci komputera ). [ => Operatory jednoargumentowe * i ++ wiążą od prawej do lewej. ] Wskaźniki to także zmienne; jeśli iq oraz ip są wskaźnikami na int, instrukcja przypisania: iq = ip; skopiuje adres zapisany w ip do zmiennej iq. Adam Rycerz [ wyklad07.pdf ] Strona 8 z 34

Wskaźniki jako argumenty funkcji Przypomienie: W języku C argumenty są przekazywane przez wartość fukcja de facto otrzymuje ich kopie. Próbujemy napisać funkcję swap zamieniającą miejscami dwie liczby całkowite: void swap(int x, int y) /* ŹLE!!! */ { int temp; } temp = x; x = y; y = temp; Adam Rycerz [ wyklad07.pdf ] Strona 9 z 34

Poprawiona wersja operuje na wskaźnikach do x i y: void swap(int *px, int *py) /* DOBRZE! */ { int temp; temp = *px; *px = *py; *py = temp; } Dostęp do zmiennych jest realizowany pośrednio (poprzez adresy), dlatego zamiana wyłuskanych wartości dokona się naprawdę. Wywołanie funkcji dla a i b zmiennych całkowitych: swap(&a, &b); /* podajemy >>adresy<<! */ Adam Rycerz [ wyklad07.pdf ] Strona 10 z 34

Podobny mechanizm stosuje się w licznych sytuacjach, gdy funkcja musi zmodyfikować wartość jakiejś zmiennej, a proste zwrócenie wartości ( instrukcją return ) nie jest możliwe. Przykładowo, funkcja biblioteczna scanf zwraca liczbę wczytanych elementów lub kod błędu, a zatem samo wczytanie dokonuje się za pośrednictwem adresu. Przykład Wczytywanie liczb do końca pliku : int n, tab[nmax]; for (n=0; n<nmax && EOF!=scanf( %d,&tab[n]); n++) ; Wczytana liczba całkowita może być równa EOF (to pewna stała), a zatem nie może zostać zwrócona przez funkcje wczytującą. Adam Rycerz [ wyklad07.pdf ] Strona 11 z 34

Związek wskaźników z tablicami W języku C wskaźniki są silnie powiązane z tablicami każda operacja na tablicy może być wykonana z użyciem wskaźnika. Instrukcja: int a[10]; definiuje tablicę 10 liczb typu int; elementy tablicy mają nazwy: a[0], a[1],, a[9] i są umieszczone w pamięci kolejno jeden po drugim. Ogólnie: a[i] oznacza i-ty element tablicy; jeśli tablica zawiera n elementów poprawne są wartości i to: 0,1,, n-1. UWAGA: Standard języka C gwarantuje, że odwołanie do elementu bezpośrednio za tablicą (tutaj: a[10]) formalnie nie jest błędem (!) Adam Rycerz [ wyklad07.pdf ] Strona 12 z 34

W języku C nazwa tablicy jest synonimem adresu pierwszego elementu; jeśli zadeklarujemy: int *pa; poprawne (i równoważne!) będą przypisania: pa = &a[0]; oraz pa = a; a możliwe odwołania do wartości i-tego elementu to: a[i] *(pa+i) *(a+i) pa[i] [ Różne typy wskaźników potrzebne aby wykonać przesunięcie! ] Różnica pomiędzy tablicą a wskaźnikiem: Wskaźnik to zmienna, poprawne zatem będą wyrażenia: pa=a pa++ [ Natomiast: a=pa oraz a++ są niepoprawne! ] Adam Rycerz [ wyklad07.pdf ] Strona 13 z 34

Kiedy nazwa tablicy jest przekazywana do funkcji funkcja de facto otrzymuje adres pierwszego elementu. Wewnątrz funkcji wspomniany adres kopiowany jest do zmiennej lokalnej, która działa już jak zwyczajny wskaźnik. Dopuszczalne są zatem operacje zwiększania i zmniejszania, które nie mają żadnych konsekwencji na zewnątrz funkcji. Przykład F-cja obliczająca długość napisu: [ Kernighan&Ritchie ] int strlen(char s[]) /* <=> int strlen(char *s) */ { } int n; for (n=0; *s!= \0 ; s++) n++; return n; Adam Rycerz [ wyklad07.pdf ] Strona 14 z 34

W funkcji strlen deklaracje parametru (char s[]) oraz (char *s) są absolutnie równoważne; w obu wypadkach funkcja otrzymuje wskaźnik zainicjowany kopią adresu &s[0] i operacja zwiększania ( s++ ) jest dozwolona. Wszystkie poniższe wywołania funkcji są poprawne: strlen( Witaj! ); /* dla stałej napisowej */ strlen(array); /* dla: char array[100]; */ strlen(ptr); /* dla: char *ptr; */ Poprawne ( i bardzo pożyteczne! ) są także odwołania do części tablicy, np: strlen(&a[2]); wówczas 2 pierwsze elementy tablicy zostaną pominięte. [ Wewnątrz f-cji poprawne będzie: a[-7] ] Adam Rycerz [ wyklad07.pdf ] Strona 15 z 34

Komentarz: Zasada przekazywania de facto kopii adresu w przypadku, gdy parametrem jest tablica, pozwala zrozumieć działanie funkcji swap w wersji z poprzednich wykładów: void swap(int v[], int i, int j) { } int temp; temp = v[i]; v[i] = v[j]; v[j] = temp; => Zmienna lokalna v działa jak wskaźnik, a zatem przypisania, (np. v[i]= ) mają realne konsekwencje dla zawartości elementów zewnętrznej tablicy podanej jako pierwszy argument wywołania. [ Inaczej będzie np. w przypadku struktury zawierającej 2 elementy! ] Adam Rycerz [ wyklad07.pdf ] Strona 16 z 34

Arytmetyka adresów Wyrażenia takie jak: p++ ( zwiększenie wskaźnika t., aby wskazywał następny element ), p-- ( zmiejszenie wskaźnika t., aby wskazywał poprzedni element ) stanowią przykłady tzw. arytmetyki wskaźników. Wskaźniki w języku C to jednak nie liczby całkowite a zatem nie wszystkie operacje arytmetyczne są dozwolone. Do wskaźnika można dodać (lub od niego odjąć) liczbę całkowitą: wyrażenie p+n ( p-n ) oznacza adres n-tego elementu za ( przed ) elementem wskazywanym przez p. ( Zależnie od typu wskaźnika, liczba typu int zostanie odpowiednio przeskalowana. ) [ Nie można jednak dodać dwóch wskaźników! ] Adam Rycerz [ wyklad07.pdf ] Strona 17 z 34

Jeśli p i q wskazują na elementy tej samej tablicy, poprawne będą wyrażenia porównania: p == q p!= q p < q p >= q itp. W sytuacji j.w., poprawne jest także odejmowanie wskaźników: Jeśli p<q (oraz p i q nadal wskazują na elementy tej samej tablicy) wyrażenie: q-p+1 jest liczbą elementów od wskazywanego przez p do wskazywanego przez q (włącznie). Przykładowo, po przypisaniach: p=&a[i]; q=&a[j]; element pośrodku możemy znaleźć jako wartość wyrażenia : *(p+(q-p)/2) /* inaczej: a[(i+j)/2] */ [ prostsza operacja *((p+q)/2) byłaby niepoprawna! ] Adam Rycerz [ wyklad07.pdf ] Strona 18 z 34

Zaawansowana wersja funkcji strlen może wyglądać tak: int strlen(char *s) { } char *p=s; /* <=> char *p; p=s; */ while (*p!= \0 ) p++; return p-s; Po definicji, p wskazuje na pierwszy znak napisu s. W każdym obiegu pętli, p jest przesuwane do następnego znaku i sprawdza się, czy tym znakiem nie jest \0. Wartość p-s to długość napisu (nie licząc \0 ). [ Inna (poprawna) forma definicji wskaźnika p: char* p=s; ] Adam Rycerz [ wyklad07.pdf ] Strona 19 z 34

Operacje arytmetyki adresów: Podsumowanie Lista poprawnych operacji na wskaźnikach przypisanie wskaźników tego samego typu (lub void*) dodawanie/odejmowanie wskaźnika i liczby całkowitej odejmowanie i porównywanie wskaźników wyłącznie w obrębie tej samej tablicy przypisanie zera i porównania z nim (zwykle zastępujemy: NULL) Inne operacje są niedozwolone! W szczególności, wskaźników nie możemy dodawać, dzielić ani mnożyć; jak również dodawać do nich liczb zmiennopozycyjnych. Adam Rycerz [ wyklad07.pdf ] Strona 20 z 34

Funkcje operujące na wskaźnikach znakowych Każda stała napisowa, np. Jestem napisem! jest reprezentowana w pamięci komputera jako tablica znakowa, uzupełniona znakiem \0 na końcu. [ Ten dodatek pozwala różnym funkcjom użytkowym łatwo znajdować koniec napisu. ] Pierwszy element takiej tablicy ma swój adres, który może być przekazany do funkcji ( lub: przypisany zmiennej typu char * ). Poprawne będzie zatem wywołanie funkcji: strlen( Ja też jestem napisem ) jak również deklaracja: char *ptext = Lorem ipsum dolor sit amet ; Adam Rycerz [ wyklad07.pdf ] Strona 21 z 34

Istnieje jednak pewna różnica pomiędzy definicjami: char atext[] = Lorem ipsum ; /* tablica */ char *ptext = dolor sit amet ; /* wskaźnik */ W pierwszym przypadku, tworzona jest tablica znakowa, o długości dopasowanej do inicjującej stałej napisowej (11 znaków); wszystkie znaki w tablicy atext mogą być później zmieniane. W drugim przypadku, ptext jest wskaźnikiem wskazującym na stałą napisową; o ile sam wskaźnik może być modyfikowany, standard języka nie określe co się stanie, jeśli spróbujemy modyfikować znaki tworzące napis. [ W j.c nie istnieją żadne operatory przetwarzające całe napisy. ] Adam Rycerz [ wyklad07.pdf ] Strona 22 z 34

Przykład: Funkcja kopiująca t do s; wersja tablicowa [ wg Kernighan & Ritchie ] void strcpy(char *s, char *t) { int i; } i = 0; while ((s[i] = t[i])!= \0 ) i++; [ Poprawnie zainicjowana tablica znakowa zawiera przynajmniej \0 ] Adam Rycerz [ wyklad07.pdf ] Strona 23 z 34

Taka sama funkcja; wersja wskaźnikowa void strcpy(char *s, char *t) { while ((*s = *t)!= \0 ) { s++; t++; } } => Argumenty t i s są przekazywane przez wartość, a zatem operacje: s++ i t++ dotyczą w istocie ich kopii (!) Adam Rycerz [ wyklad07.pdf ] Strona 24 z 34

Kopiowanie napisów: Wersja wskaźnikowa zaawansowana void strcpy(char *s, char *t) { while ((*s++ = *t++)!= \0 ) ; } Objaśnienie: Operatory zwiększania (++) w wersji przyrostkowej działają po zakończeniu wszystkich obliczeń, zatem przypisanie i porównanie zostaną wykonane przed modyfikacją wskaźników. [ Uwaga: Tym razem, po wystąpieniu \0 oba wskaźniki zostaną jeszcze raz zwiększone, zatem pokażą na znak poza napisem. ] Adam Rycerz [ wyklad07.pdf ] Strona 25 z 34

Jeszcze krótsza wersja funkcji kopiującej napisy: void strcpy(char *s, char *t) { while (*s++ = *t++); } => Tutaj korzystamy z idiomu: znak pusty \0 to zawsze zero, zatem jawne porównanie nie jest potrzebne. Funkcja strcpy jest zdefiniowana w bibliotece standardowej (nagłówek: <string.h>); jej prototyp wygląda tak: char * strcpy(char * dst, const char * src); Funkcja zwraca wskaźnik to tekstu docelowego (dst), deklaracja drugiego parametru jako const char * daje pewność, że napis źródłowy (src) nie będzie zmieniony. Adam Rycerz [ wyklad07.pdf ] Strona 26 z 34

Inna (prosta) funkcja pozwala na porównanie napisów: int strcmp(char *s, char *t) /* z tablicami */ { int i; for (i = 0; s[i] == t[i]; i++) if (s[i] == \0 ) return 0; return s[i] - t[i]; } Funkcja zwraca zero, jeśli napisy wskazywane przez s i t są identyczne, wartość dodatnią, jeśli s jest leksykalnie większe od t, lub wartość ujemną w przeciwnym przypadku. Adam Rycerz [ wyklad07.pdf ] Strona 27 z 34

Wersja wskaźnikowa funkcji porównującej napisy: int strcmp(char *s, char *t) /* z tablicami */ { for ( ; *s == *t; s++, t++) if (*s == \0 ) return 0; return *s - *t; } [ Warunek w pętli można jeszcze zastąpić przez: if (!*s) będzie to jednak raczej mało czytelne ] Adam Rycerz [ wyklad07.pdf ] Strona 28 z 34

Wskaźnik FILE * i funkcja fopen Operacje na plikach (innych niż standardowe wejście lub wyjście) realizujemy za pomocą wskaźników plikowych. Potrzebne deklaracje i prototypy funkcji zawiera nagłówek <stdio.h>. Przykładowo, po deklaracji: instrukcja: FILE *fp; fp = fopen( mojplik.txt, w ); otworzy plik ( mojplik.txt ) w trybie zapisu ( w ) i powiąże go z fp. W takim przypadku, plik nieistniejący zostanie utworzony, istniejący zamazany. [ Oba paramery fopen są typu: char * ] Inne tryby otwarcia to: r odczyt oraz a dopisywanie. [ Istnieją są także tryby: r+ w+ oraz a+ pozwalające na czytanie i pisanie po tym samym pliku. ] Adam Rycerz [ wyklad07.pdf ] Strona 29 z 34

Większość systemów rozróżnia pliki tekstowe i binarne; domyślne są tekstowe, otwarcie pliku binarnego wymaga dodania litery b w napisie oznaczającym tryb otwarcia ( wb rb r+b itp). W każdym przypadku, aby zmiany zostały zachowane, konieczne jest zamknięcie pliku, np.: fclose(fp); wywołanie fclose zarazem zwalnia wskaźnik (fp), który można następnie powiązać z innym plikiem wywołując: fopen. Inne funkcje, użyteczne (zwłaszcza w trybach z plusem ), to np. rewind(fp) powraca do początku pliku fflush(fp) opróżnia bufor (dla strumienia wyjściowego) Ponadto, instrukcja: fp = tmpfile(); tworzy plik tymczasowy (w trybie wb+ ), który będzie usunięty po zamknięciu. Adam Rycerz [ wyklad07.pdf ] Strona 30 z 34

W przypadku plików tekstowych, często używamy funkcji: formatowanego wejścia/wyjścia (z nagłówka <stdio.h>): int fprintf(file * stream, const char * format, ); int fscanf(file * stream, const char * format, ); Są one bardzo podobne do printf i scanf z tym, że pierwszym argumentem jest zawsze wskaźnik plikowy. Dla plików binarnych, elementarz stanowią funkcje: int getc(file *fp) oraz int putc(int c, FILE *fp) które wywołane tak: getc(stdin) lub putc(c,stdout) zadziałają identycznie jak getchar() i putchar(c). stdin i stdout to także wskaźniki typu FILE *, są to jednak stałe trwale powiązane ze standardowym wejściem i wyjściem. Adam Rycerz [ wyklad07.pdf ] Strona 31 z 34

Przykład funkcja kopiująca plik ifp do ofp: [ wg Kernighan & Ritchie ] void filecopy(file *ifp, FILE *ofp) { int c; } while (EOF!= (c = getc(ifp))) putc(c, ofp); [ Inaczej niż przy kopiowaniu napisów - tym razem nie przepisujemy znacznika końca pliku EOF zostanie wstawiony przez system operacyjny podczas zamykania pliku lub po prawidłowym zakończeniu działania programu. ] Adam Rycerz [ wyklad07.pdf ] Strona 32 z 34

W poniższym programie, funkcja filecopy jest użyta do kopiowania danych ze standardowego wejścia na wyjście: #include <stdio.h> int main() { void filecopy(file *, FILE *); filecopy(stdin, stdout); } => Ćwiczenie: Łatwo przekonać się, że mechanizm potoków unixowych pozwala na kopiowanie dowolnych plików, także binarnych:./a.out < plik1 > plik2 Możemy też wykorzystać filecopy do wyświetlenia dowolnego pliku na standardowe wyjście: Adam Rycerz [ wyklad07.pdf ] Strona 33 z 34

#include <stdio.h> #define MAXNAM 100 int main() { char fnam[maxnam]; FILE *fp; void filecopy(file *, FILE *); printf( ==> Podaj nazwę pliku: ); scanf( %s,fnam); if (NULL == (fp=fopen(fnam, rb )) ) { printf( Nie znaleziono pliku: %s\n,fnam); return -1; } filecopy(fp, stdout); fclose(fp); } Adam Rycerz [ wyklad07.pdf ] Strona 34 z 34