x - Politechnika Śląska
Transkrypt
x - Politechnika Śląska
Programowanie komputerów Jacek Lach Zakład Oprogramowania Instytut Informatyki Politechnika Śląska Plan • Biblioteka standardowa • funkcje operujące na łańcuchach Jacek Lach. Programowanie komputerów • funkcje operujące na plikach • funkcje matematyczne • funkcje pomocnicze Jacek Lach. Programowanie komputerów Biblioteka standardowa • <assert.h> <complex.h> <ctype.h> <errno.h> <fenv.h> <float.h> <inttypes.h> <iohw.h> <iso646.h> <limits.h> <locale.h> <math.h> <setjmp.h> <signal.h> <stdarg.h> <stdbool.h> <stddef.h> <stdint.h> <stdio.h> <stdlib.h> <string.h> <tgmath.h> <time.h> <uchar.h> <wchar.h> <wctype.h> Funkcje operujące na łańcuchach • Plik nagłówkowy: <string.h> Jacek Lach. Programowanie komputerów • Wszystkie funkcje przyjmują, że łańcuchy kończą się znakiem ’\0’ • Większość funkcji nie alokuje pamięci dla łańcuchów • Ich użytkownik jest odpowiedzialny za dostarczenie miejsca w pamięci na wynik strcpy() • char *strcpy(char *dest, const char *src); Jacek Lach. Programowanie komputerów • Kopiuje łańcuch src do dest #include <stdio.h> #include <string.h> int main(void) { char string[10]; char *str1 = "abcdefghi"; strcpy(string, str1); printf("%s\n", string); return 0; } strcpy() implementacja /* strcpy: kopiowanie t do s; wersja z tablicami i indeksami */ Jacek Lach. Programowanie komputerów void strcpy(char *s, char *t) { int i; i = 0; while ((s[i] = t[i]) != '\0') i++; } Jacek Lach. Programowanie komputerów strcpy() implementacja /* strcpy: kopiowanie t do s; wersja ze wskaźnikami */ void strcpy(char *s, char *t) { int i; i = 0; while ((*s = *t) != '\0') { s++; t++; } } strcpy() implementacja /* strcpy: kopiowanie t do s; druga wersja ze wskaźnikami */ Jacek Lach. Programowanie komputerów void strcpy(char *s, char *t) { while ((*s++ = *t++) != '\0') ; } strncpy() • char *strncpy(char *dest, const char *src, size_t maxlen); Jacek Lach. Programowanie komputerów • Kopiuje najwyżej maxlen znaków ze src do dest. • Docelowy łańcuch, dest, może być pozbawiony końcowego zera, jeśli długość src wynosi maxlen lub więcej. Jacek Lach. Programowanie komputerów strncpy() #include <stdio.h> #include <string.h> int main(void) { char string[3+1]; char *str1 = "abcdefghi"; strncpy(string, str1, 3); string[3] = '\0'; /* inaczej zabrakłoby ’\0’ */ printf("%s\n", string); return 0; } /* Wynik: abc */ strcmp() • int strcmp(const char *s1, const char*s2); Jacek Lach. Programowanie komputerów • strcmp dokonuje porównania łańcuchów s1 i s2 traktując je jak ciąg wartości unsigned char • Wartość zwracana: • < 0 jeśli s1 < s2 • == 0 jeśli s1 == s2 • > 0 jeśli s1 > s2 Jacek Lach. Programowanie komputerów strcmp() #include <string.h> #include <stdio.h> int main(void) { char *buf1 = "alice", *buf2 = ”andrew"; int p; p = strcmp(buf2, buf1); if (p > 0) printf("buffer 2 is greater than buffer 1\n"); else printf("buffer 2 is not greater than buffer 1\n"); return 0; } /* Wynik: buffer 2 is greater than buffer 1 */ strcmp() /* strcmp: zwraca <0 jeśli s<t, 0 jeśli s==t, >0 jeśli s>t */ Jacek Lach. Programowanie komputerów int strcmp(char *s, char *t) { int i; for (i = 0; s[i] == t[i]; i++) if (s[i] == '\0') return 0; return s[i] - t[i]; } strcmp() /* strcmp: zwraca <0 jeśli s<t, 0 jeśli s==t, >0 jeśli s>t */ Jacek Lach. Programowanie komputerów int strcmp(char *s, char *t) { for ( ; *s == *t; s++, t++) if (*s == '\0') return 0; return *s - *t; } strlen() • size_t strlen(const char *s); Jacek Lach. Programowanie komputerów • Zwraca liczbę znaków w łańcuchu s, nie licząc kończącego ten łańcuch zera #include <stdio.h> #include <string.h> int main(void) { char *string = ”The ANSI C compiler"; printf("%d\n", strlen(string)); return 0; } /* Wynik: 19 */ strcat() • char *strcat(char *dest, const char *src); • strcat dołącza kopię src do końca łańcucha dest. Jacek Lach. Programowanie komputerów • dest musi być wystarczająco pojemny • Długość wynikowego łańcucha jest równa strlen(dest) + strlen(src) • strcat zwraca wskaźnik na połączone łańcuchy. Jacek Lach. Programowanie komputerów strcat() #include <string.h> #include <stdio.h> int main(void) { char destination[25]; char *blank = " ", *c = "C ", *a = ”ANSI"; strcpy(destination, a); strcat(destination, blank); strcat(destination, c); printf("%s\n", destination); /* ANSI C */ return 0; } strchr() • char *strchr(const char *s, int c); Jacek Lach. Programowanie komputerów • Szuka w łańcuchu pierwszego wystąpienia podanego znaku • Kończące zero uznawane jest za część łańcucha • Jeśli c nie występuje w s, funkcja zwraca NULL Jacek Lach. Programowanie komputerów strchr() #include <string.h> #include <stdio.h> int main(void) { char string[15]; char *ptr, c = 'r'; strcpy(string, "This is a string"); ptr = strchr(string, c); if (ptr) printf("The character %c is at position: %d\n", c, ptr-string); else printf("The character was not found\n"); return 0; } /* Wynik: The character r is at position: 12 */ strrchr() • char *strrchr(const char *s, int c); Jacek Lach. Programowanie komputerów • strrchr szuka ostatniego wystąpienia znaku c w łańcuchu s strpbrk() Jacek Lach. Programowanie komputerów • char *strpbrk(const char *s1, const char *s2); • strpbrk szuka w łańcuchu s1 pierwszego wystąpienia jakiegokolwiek znaku występującego w łańcuchu s2 • Jeśli znajdzie, strpbrk zwraca wskaźnik na pierwsze wystąpienie takiego znaku • Jeśli nie znajdzie, zwrócona zostanie wartość NULL Jacek Lach. Programowanie komputerów strpbrk() #include <stdio.h> #include <string.h> int main(void) { char *string1 = "value=123"; char *string2 = ",:=;"; char *ptr; ptr = strpbrk(string1, string2); if (ptr) printf("strpbrk found first character: %c\n", *ptr); else printf("strpbrk didn't find character in set\n"); return 0; } /* strpbrk found first character: = */ strstr() • char *strstr(const char *s1, const char *s2); Jacek Lach. Programowanie komputerów • strstr szuka w łańcuchu s1 pierwszego wystąpienia łańcucha s2 • Jeśli znajdzie, strstr zwraca wskaźnik na ten element s1, od którego zaczyna się s2 (wskaźnik na wystąpienie s2 w s1) • Jeśli nie znajdzie, strstr zwraca NULL strstr() #include <stdio.h> #include <string.h> Jacek Lach. Programowanie komputerów int main(void) { char *str1 = ”Computer Programming", *str2 = ”ram", *ptr; ptr = strstr(str1, str2); printf("The substring is: %s\n", ptr); return 0; } /* The substring is: ramming */ strtok() Jacek Lach. Programowanie komputerów • char *strtok(char *s1, const char *s2); • strtok traktuje s1 jako sekwencję tokenów, rozdzielonych ciągami separatorów zdefiniowanych przez s2 • Pierwsze wywołanie strtok – zwraca wskaźnik do pierwszego znaku pierwszego tokenu w s1oraz zapisuje znak 0 do s1 bezpośrednio za tym tokenem • Kolejne wywołania tej funkcji z pierwszym argumentem równym NULL zwracają wskaźniki do kolejnych tokenów w s1, aż do ich wyczerpania Jacek Lach. Programowanie komputerów strtok() #include <string.h> #include <stdio.h> int main(void) { char input[16] = "abc,d"; char *p; /* strtok umieszcza znak 0 za ewentualnie znalezionym tokenem */ p = strtok(input, ","); if (p) printf("%s\n", p); /* Drugie wywołanie z pierwszym argumentem równym NULL zwraca wskaźnik do kolejnego tokenu */ p = strtok(NULL, ","); if (p) printf("%s\n", p); return 0; } Funkcje operujące na pamięci memcpy() • void *memcpy (void *dest, const void *src, size_t n); Jacek Lach. Programowanie komputerów • Kopiuje blok n bajtów z src do dest • Jeśli obszary src i dest nakładają się, wynik jest niezdefiniowany (nie mogą nakładać się) Jacek Lach. Programowanie komputerów memcpy() #include <stdio.h> #include <string.h> int main(void) { char src[] = "******************************"; char dest[] ="abcdefghijlkmnopqrstuvwxyz0123456709"; char *ptr; printf("destination before memcpy: %s\n", dest); ptr = (char *) memcpy(dest, src, strlen(src)); if (ptr) printf("destination after memcpy: %s\n", dest); else printf("memcpy failed\n"); return 0; } destination before memcpy: abcdefghijlkmnopqrstuvwxyz0123456709 destination after memcpy: ******************************456709 memmove() • void *memmove(void *dest, const void *src, size_t n); Jacek Lach. Programowanie komputerów • Kopiuje blok n bajtów z src do dest • Nawet jeśli bloki pamięci nakładają się, wynik kopiowania jest poprawny (bufor pomocniczy) Jacek Lach. Programowanie komputerów memmove() #include <string.h> #include <stdio.h> int main(void) { char dest[] = "abcdefghijklmnopqrstuvwxyz0123456789"; char *src = "******************************"; printf("destination prior to memmove: %s\n", dest); memmove(dest, src, 26); printf("destination after memmove: %s\n", dest); return 0; } destination prior to memmove: abcdefghijklmnopqrstuvwxyz0123456789 destination after memmove: **************************0123456789 memset() • void *memset (void *s, int c, size_t n); Jacek Lach. Programowanie komputerów • memset ustawia pierwszych n bajtów tablicy s na znak c • Zwraca s Makra klasyfikujące znaki Jacek Lach. Programowanie komputerów • Zdefiniowane w ctype.h • Służą do stwierdzenia, czy dany znak należy do określonej klasy, np. czy znak c jest cyfrą: if (isdigit(c)) printf(”To jest cyfra %c\n”, c) • Zwracana wartość: niezerowa, jeśli znak należy do danej klasy Makra klasyfikujące znaki • Możliwe realizacje: Jacek Lach. Programowanie komputerów • wyrażenia warunkowe, np. #define isdigit(c) ((c)>=’0’ && (c)<=’9’) • predefiniowane tablice Makra klasyfikujące znaki Jacek Lach. Programowanie komputerów • Predefiniowana tablica opisująca klasy #define _IS_SP 1 /* is space */ #define _IS_DIG 2 /* is digit indicator */ #define _IS_UPP 4 /* is upper case */ #define _IS_LOW 8 /* is lower case */ #define _IS_HEX 16 /* [0..9] or [A-F] or [a-f] */ #define _IS_CTL 32 /* Control */ #define _IS_PUN 64 /* punctuation */ extern char _ctype[]; /* Character type array */ ... #define isdigit(c) (_ctype[(c) + 1] & _IS_DIG) #define isalnum(c) (_ctype[(c) + 1] & (_IS_DIG | _IS_UPP \ | _IS_LOW)) #define isalpha(c) (_ctype[(c) + 1] & (_IS_UPP | _IS_LOW)) Makra klasyfikujące znaki Jacek Lach. Programowanie komputerów • ...zawartość tablicy 0: 8: 16: 24: 32: 40: 48: 56: 64: 72: 80: 88: 96: 104: 112: 120: 128: 136: 0 32 32 32 32 64 64 2 64 4 4 4 64 8 8 8 32 0 1: 9: 17: 25: 33: 41: 49: 57: 65: 73: 81: 89: 97: 105: 113: 121: 129: 137: 32 32 32 32 1 64 2 2 64 4 4 4 64 8 8 8 0 0 2: 10: 18: 26: 34: 42: 50: 58: 66: 74: 82: 90: 98: 106: 114: 122: 130: 138: 32 33 32 32 64 64 2 2 20 4 4 4 24 8 8 8 0 0 3: 11: 19: 27: 35: 43: 51: 59: 67: 75: 83: 91: 99: 107: 115: 123: 131: 139: 32 33 32 32 64 64 2 64 20 4 4 4 24 8 8 8 0 0 4: 12: 20: 28: 36: 44: 52: 60: 68: 76: 84: 92: 100: 108: 116: 124: 132: 140: 32 33 32 32 64 64 2 64 20 4 4 64 24 8 8 64 0 0 5: 13: 21: 29: 37: 45: 53: 61: 69: 77: 85: 93: 101: 109: 117: 125: 133: 141: 32 33 32 32 64 64 2 64 20 4 4 64 24 8 8 64 0 0 6: 14: 22: 30: 38: 46: 54: 62: 70: 78: 86: 94: 102: 110: 118: 126: 134: 142: 32 33 32 32 64 64 2 64 20 4 4 64 24 8 8 64 0 0 7: 15: 23: 31: 39: 47: 55: 63: 71: 79: 87: 95: 103: 111: 119: 127: 135: 143: 32 32 32 32 64 64 2 64 20 4 4 64 24 8 8 64 0 0 Makra klasyfikujące znaki Jacek Lach. Programowanie komputerów • ...zawartość tablicy : : : : : (: 0: 8: @: H: P: X: `: h: p: x: : : 0 32 32 32 32 64 64 2 64 4 4 4 64 8 8 8 32 0 : : : : !: ): 1: 9: A: I: Q: Y: a: i: q: y: : : 32 32 32 32 1 64 2 2 64 4 4 4 64 8 8 8 0 0 : : : : ": *: 2: :: B: J: R: Z: b: j: r: z: : : 32 33 32 32 64 64 2 2 20 4 4 4 24 8 8 8 0 0 : : : : #: +: 3: ;: C: K: S: [: c: k: s: {: : : 32 33 32 32 64 64 2 64 20 4 4 4 24 8 8 8 0 0 : : : : $: ,: 4: <: D: L: T: \: d: l: t: |: : : 32 33 32 32 64 64 2 64 20 4 4 64 24 8 8 64 0 0 : : : : %: -: 5: =: E: M: U: ]: e: m: u: }: : : 32 33 32 32 64 64 2 64 20 4 4 64 24 8 8 64 0 0 : : : : &: .: 6: >: F: N: V: ^: f: n: v: ~: : : 32 33 32 32 64 64 2 64 20 4 4 64 24 8 8 64 0 0 : : : : ': /: 7: ?: G: O: W: _: g: o: w: : : : 32 32 32 32 64 64 2 64 20 4 4 64 24 8 8 64 0 0 Makra klasyfikujące znaki • Deklaracje: int isalnum(int c); int islower(int c); Jacek Lach. Programowanie komputerów int isalpha(int c); int isprint(int c); int isascii(int c); int ispunct(int c); int iscntrl(int c); int isspace(int c); int isdigit(int c); int isupper(int c); int isgraph(int c); int isxdigit(int c); Pliki • Zanim plik będzie czytany lub zapisywany, musi zostać otworzony Jacek Lach. Programowanie komputerów • Funkcja biblioteczna fopen otwiera plik • fopen na podstawie nazwy pliku dokonuje pewnych negocjacji z systemem operacyjnym i zwraca wskaźnik na strukturę danych FILE; ten wskaźnik jest potem stosowany przez funkcje dostępu do plików • Wskaźnik ten (ang. file pointer) wskazuje na strukturę zawierającą informacje o pliku: • położenie bufora • bieżącą pozycję w buforze • informację, czy plik jest czytany czy pisany • informację o ewentualnych błędach, końcu pliku itp. • Użytkownicy nie muszą znać szczegółów Pliki Jacek Lach. Programowanie komputerów • W pliku nagłówkowym <stdio.h> zawarta jest deklaracja struktury nazywanej FILE • Jedyną definicją wymaganą do użycia fopen jest definicja wskaźnika na taką strukturę: FILE *fp; FILE *fopen(char *name, char *mode); • Powyższe instrukcje mówią, że fp jest wskaźnikiem na FILE, a fopen zwraca wskaźnik na FILE. • Zauważmy, że FILE jest nazwą typu, jak int, a nie etykietą struktury; jest zdefiniowane przez typedef Pliki Jacek Lach. Programowanie komputerów • Wywołanie fopen w programie: fp = fopen(name, mode); • Pierwszy parametr przekazany fopen to łańcuch zawierający nazwę pliku. • Drugi parametr jest trybem dostępu, opisywanym również przez łańcuch znakowy określający, jak użytkownik zamierza używać pliku. Pliki • Dopuszczalne tryby dostępu (standard): • do czytania ("r") Jacek Lach. Programowanie komputerów • do pisania ("w") • do rozszerzania ("a") • do aktualizacji ("r+") • nowy do aktualizacji ("w+") • do aktualizacji części rozszerzającej ("a+"). • Niektóre systemy odróżniają pliki znakowe i binarne; dla tych ostatnich, należy dołączyć "b" do opisu trybu dostępu: rb, wb, ab, r+b (rb+), w+b (wb+), a+b, (ab+). Pliki Jacek Lach. Programowanie komputerów • Jeśli podejmowana jest próba otwarcia nieistniejącego pliku do zapisu lub dołączania, jest on tworzony (jeśli to możliwe) • Otwieranie istniejącego pliku do zapisu powoduje usunięcie poprzedniej jego zawartości • Otwierania do dołączania zachowuje ją • Próba czytania nieistniejącego pliku jest błędem • Inne przyczyny błędów: próba dostępu do pliku, do którego użytkownik nie ma odpowiednich praw • W razie błędu, fopen zwraca NULL Pliki Jacek Lach. Programowanie komputerów • Co zrobić po otwarciu pliku... • getc zwraca następny znak odczytany z pliku; wymaga podania wskaźnika do FILE: int getc(FILE *fp) • getc zwraca EOF jeśli wystąpił koniec pliku lub błąd • W przypadku wystąpienia błędu ustawiany jest znacznik błędu dla strumienia • putc jest funkcją wyprowadzającą dane: int putc(int c, FILE *fp) • putc zapisuje znak c do pliku fp i zwraca ten znak w razie sukcesu lub EOF w razie błędu Pliki • Plik w Dos/Windows: • abracadabra\r\n Jacek Lach. Programowanie komputerów • czarymary\r\n //CR/LF • Plik w Linux/Unix: • abracadabra\n • czarymary\n • „Wewnątrz” programu w C (działającego w DOS lub Unix) pliki przechowywane są zawsze w konwencji Unix Pliki Jacek Lach. Programowanie komputerów • W trybie tekstowym znak nowej linii \n jest na wyjściu tłumaczony na kombinację \r\n. Na wejściu kombinacja \r\n jest tłumaczona na \n • W trybie binarnym takie tłumaczenie nie następuje Pliki Jacek Lach. Programowanie komputerów • W trybie tekstowym koniec pliku oznaczony jest odczytaniem znaku CTRLZ (kod dziesiętny 26 lub 1A szesnastkowo). • W trybie binarnym koniec pliku sygnalizowany jest wartością całkowitą –1 (FFFFh). Jeżeli więc w pliku występują dane w formacie binarnym lub tekst w innym kodzie niż ASCII, to w trybie tekstowym, przypadkowe wystąpienie bajtu o wartości 1A, zostanie potraktowane jako koniec pliku. Pliki Jacek Lach. Programowanie komputerów • Kiedy uruchamiany jest program w C, system operacyjny jest odpowiedzialny za otwarcie trzech plików i powiązanie z nimi odpowiednich wskaźników • Tymi plikami są: • wejście standardowe, ang. standard input, • wyjście standardowe, ang. standard output, • strumień błędów, ang. standard error. • Odpowiednie wskaźniki nazywane są stdin, stdout, stderr, i zadeklarowane są w <stdio.h> • Normalnie stdin jest połączony z klawiaturą, stdout Pliki Jacek Lach. Programowanie komputerów • Dla formatowanego wejścia i wyjścia, stosowane są funkcje fscanf i fprintf • Działają analogicznie jak scanf i printf; dodatkowo wymagają wskaźnika na plik czytany lub pisany: • int fscanf(FILE *fp, char *format, ...) • int fprintf(FILE *fp, char *format, ...) Jacek Lach. Programowanie komputerów Program cat #include <stdio.h> /* cat: polacz pliki, wersja 1 */ main(int argc, char *argv[]) { FILE *fp; void filecopy(FILE *, FILE *) if (argc == 1) /* brak par.; kopiuj stand. wej. */ filecopy(stdin, stdout); else while(--argc > 0) if ((fp = fopen(*++argv, "r")) == NULL) { printf("cat: can't open %s\n, *argv); return 1; } else { filecopy(fp, stdout); fclose(fp); } return 0; Jacek Lach. Programowanie komputerów Program cat /* filecopy: kopiuj plik ifp do pliku ofp */ void filecopy(FILE *ifp, FILE *ofp) { int c; while ((c = getc(ifp)) != EOF) putc(c, ofp); } Zamykanie plików Jacek Lach. Programowanie komputerów • Funkcja int fclose(FILE *fp) działa odwrotnie do fopen, przerywa połączenie między wskaźnikiem fp a plikiem; zwalnia wskaźnik, który może być użyty do obsługi innego pliku • Większość SO ma limit liczby jednocześnie otwartych plików; należy więc zwalniać te zasoby, kiedy pliki nie są już używane • Jest też inny powód stosowania fclose ta funkcja opróżnia bufor, w którym putc i inne funkcje gromadzą dane. • fclose jest wywoływane automatycznie dla każdego otwartego pliku, jeśli program kończy się normalnie Obsługa błędów Jacek Lach. Programowanie komputerów • Jeśli do któregoś z plików cat nie może się dostać, wypisywany jest komunikat o błędzie na końcu danych wyjściowych • Jest to niedopuszczalne, jeśli wyjście trafia do pliku albo na wejście innego programu przez potok • Strumień wyjściowy, nazywany stderr, jest stosowany do wypisywania komunikatów dla użytkownika. Pojawiają się one normalnie na ekranie nawet, jeśli stdout zostało przekierowane Jacek Lach. Programowanie komputerów cat obsługa błędów #include <stdio.h> #include <stdlib.h> /* cat: concatenate files, version 2 */ main(int argc, char *argv[]) { FILE *fp; void filecopy(FILE *, FILE *); char *prog = argv[0]; /* program name for errors */ if (argc == 1 ) /* no args; copy standard input */ filecopy(stdin, stdout); else while (--argc > 0) if ((fp = fopen(*++argv, "r")) == NULL) { fprintf(stderr, "%s: can't open %s\n", prog, *argv); exit(1); } else { filecopy(fp, stdout); fclose(fp); } if (ferror(stdout)) { fprintf(stderr, "%s: error writing stdout\n", prog); exit(2); } exit(0); } Kopiowanie #include <stdio.h> int main() Jacek Lach. Programowanie komputerów { int c; while ((c=getc(stdin))!=EOF) putc(c,stdout); return 0; } Jacek Lach. Programowanie komputerów • Kopiowanie plików #include <stdio.h> int main() { FILE *f1, *f2; int c; f1 = fopen("data.bin","rb"); /* otwieranie do odczytu */ f2 = fopen("output.bin","wb"); /* otwieranie do zapisu */ if (!(f1 && f2)) return -1; /* problemy z otwieraniem? */ while ((c=getc(f1))!=EOF) /* pętla główna */ putc(c,f2); fclose(f1); fclose(f2); return 0; } Inne funkcje Jacek Lach. Programowanie komputerów • feof testuje warunek końca pliku (endoffile): int feof( FILE *stream ); • Funkcja feof zwraca wartość niezerową po pierwszej nieudanej próbie czytania poza końcem pliku • Zwraca 0, jeśli nie było prób czytania poza końcem pliku • Nie informuje o innych błędach Jacek Lach. Programowanie komputerów feof() #include <stdio.h> int main(void) { FILE *stream; /* open a file for reading */ stream = fopen(”TEST.TXT", "r"); /* read a character from the file */ fgetc(stream); /* check for EOF */ if (feof(stream)) printf("We have reached end-of-file\n"); /* close the file */ fclose(stream); return 0; } Jacek Lach. Programowanie komputerów feof() #include <stdio.h> #include <stdio.h> int main() int main() { { int c; int c; while (!feof(stdin)) { while (1) { c = getc(stdin); c = getc(stdin); putc(c,stdout); if (feof(stdin)) } break; return 0; putc(c,stdout); } } return 0; } ferror() Jacek Lach. Programowanie komputerów • Testuje, czy wystąpił błąd w obsłudze strumienia int ferror( FILE *stream ); • Jeśli nie wystąpił błąd, ferror zwraca 0. W innym przypadku zwraca wartość niezerową. • Funkcja ferror testuje błędy zapisu lub odczytu pliku związanego ze strumieniem stream • Jeśli wystąpił błąd, znacznik błędu dla tego strumienia jest ustawiony aż do zamknięcia strumienia, przewinięcia lub wywołania dla niego funkcji clearerr Jacek Lach. Programowanie komputerów ferror() #include <stdio.h> int main(void) { FILE *stream; /* otwieramy plik do zapisu */ stream = fopen("DUMMY.FIL", "w"); /* wymuszamy błąd przez próbę odczytu */ (void) getc(stream); if (ferror(stream)) /* test wystąpienia błędu */ { /* wypisujemy komunikat */ printf(”Błąd odczytu z pliku DUMMY.FIL\n"); /* zerujemy znacznik błędu i EOF */ clearerr(stream); } fclose(stream); return 0; } clearerr() Jacek Lach. Programowanie komputerów • Zeruje znacznik błędu dla strumienia void clearerr( FILE *stream ); • Funkcja clearerr zeruje znacznik błędu i końca pliku (EOF) dla strumienia stream. • Znaczniki błędów nie są automatycznie zerowane; kiedy jeden z nich zostanie ustawiony, kolejne operacje na strumieniu zwracają komunikat o błędzie do czasu wywołania clearerr, fseek, fsetpos lub rewind perror() Jacek Lach. Programowanie komputerów • Wyprowadzenie komunikatu o błędzie, który wystąpił podczas wykonywania programu void perror(const char *string); • „Mapuje” numer błędu przechowywanego w zmiennej errno w komunikat o błędzie • Wyprowadza komunikat do pliku identyfikowanego przez stderr. Komunikat składa się z ciągu znaków wskazywanego przez string, znaku : oraz tekstu związanego z błędem (+ znak nowego wiersza) Przykład Jacek Lach. Programowanie komputerów /* crt_clearerr.c - from MSDN * This program creates an error on the standard input * stream, then clears it so that future reads won't fail. #include <stdio.h> int main( void ) { int c; /* Create an error by writing to standard input. */ putc( 'c', stdin ); if( ferror( stdin ) ) { perror( "Write error" ); clearerr( stdin ); } /* See if read causes an error. */ printf( "Will input cause an error? " ); c = getc( stdin ); if( ferror( stdin ) ) { perror( "Read error" ); clearerr( stdin ); } } fflush() Jacek Lach. Programowanie komputerów • Opróżnia bufor obsługujący strumień int fflush( FILE *stream ); • Jeśli plik związany ze strumieniem stream został otwarty do zapisu, fflush zapisuje do pliku zawartość bufora związanego ze strumieniem • W niektórych systemach, jeśli plik jest otwarty do odczytu, fflush czyści zawartość bufora (poza standardem). W innych systemach, fflush w takich przypadkach nie działa (zgodnie ze standardem) • fflush zwraca 0 po poprawnym wykonaniu. Po wykryciu błędu zwraca EOF i ustawia znacznik błędu. ftell() Jacek Lach. Programowanie komputerów • Podaje bieżącą pozycję w pliku long ftell( FILE *stream ); • Funkcja ftell podaje bieżącą pozycję w pliku związanym ze strumieniem stream, jeśli jest z nim związany plik • Pozycja podawana jest względem początku strumienia fseek() Jacek Lach. Programowanie komputerów • Zmienia bieżącą pozycje w pliku na wskazaną int fseek( FILE *stream, long offset, int origin ); • Funkcja fseek przesuwa „wskaźnik” w pliku (jeśli jest związany ze strumieniem stream) do nowego położenia oddalonego o offset bajtów od origin • Następna operacja na strumieniu wykonywana jest w nowej pozycji • Jeśli plik jest otwarty do uaktualniania („a”), następną operacją może być zapis lub odczyt fseek() Jacek Lach. Programowanie komputerów • Parametr origin musi być jedną z następujących stałych, zdefiniowanych w stdio.h: • SEEK_CUR Bieżąca pozycja „wskaźnika” • SEEK_END Koniec pliku • SEEK_SET Początek pliku Jacek Lach. Programowanie komputerów Przykład #include <stdio.h> long filesize(FILE *stream) { long curpos, length; curpos = ftell(stream); fseek(stream, 0L, SEEK_END); length = ftell(stream); fseek(stream, curpos, SEEK_SET) return length; } rewind() Jacek Lach. Programowanie komputerów • Przemieszcza „wskaźnik” pliku na początek pliku. void rewind( FILE *stream ); • Funkcja rewind przemieszcza „wskaźnik” pliku związanego ze strumieniem stream na początek pliku • Wywołanie rewind jest podobne do (void) fseek( stream, 0L, SEEK_SET ); • Ale, w przeciwieństwie do fseek, rewind zeruje znaczniki błędów dla strumienia oraz znacznik końca pliku (end offile). Ponadto, w przeciwieństwie do fseek, rewind nie zwraca wartości tmpfile() Jacek Lach. Programowanie komputerów • Tworzy tymczasowy plik. FILE *tmpfile( void ); • Funkcja tmpfile tworzy tymczasowy plik i zwraca wskaźnik do tego strumienia (tj. struktury FILE) • Jeśli plik nie może zostać utworzony, tmpfile zwraca wskaźnik NULL • Plik tymczasowy jest automatycznie usuwany kiedy plik jest zamykany, kiedy program normalnie się kończy lub wywołana zostanie funkcja _rmtmp • Plik tymczasowy jest otwierany w trybie w+b (binary read/write) Pliki tymczasowe • char *tmpnam(char *s); • FILE *tmpfile(void); Jacek Lach. Programowanie komputerów • char *mktemp(char *template); • int mkstemp(char *template) fread() / fwrite() Jacek Lach. Programowanie komputerów • size_t fread( void *buffer, size_t size, size_t count, FILE *stream ); • size_t fwrite( void *buffer, size_t size, size_t count, FILE *stream ); fread() Jacek Lach. Programowanie komputerów • Czyta do count elementów o rozmiarze size bajtów każdy z wejściowego strumienia stream i zapisuje je w buforze o adresie buffer • Zwraca liczbę pełnych elementów odczytanych z pliku • „Wskaźnik” na pozycję w pliku (jeśli jest) jest zwiększany o liczbę przeczytanych bajtów • Jeśli plik jest otwarty w trybie tekstowym, pary crlf są zastępowane pojedynczym znakiem lf (linefeed) • Wartość częściowo odczytanych elementów jest nieokreślona fwrite() • Zapisuje do count elementów o rozmiarze size bajtów każdy, z bufora buffer to strumienia stream Jacek Lach. Programowanie komputerów • Zwraca liczbę pełnych zapisanych elementów • „Wskaźnik” zwiększany jest o liczbę zapisanych bajtów • Jeśli plik jest otwarty w trybie tekstowym, cr jest zastępowany przez crlf Inne Jacek Lach. Programowanie komputerów • Usunięcie pliku o podanej nazwie int remove(const char *filename); • Zmiana nazwy pliku int rename(const char *oldname, const char *newname); ungetc() Jacek Lach. Programowanie komputerów • Zwraca znak z powrotem do strumienia wejściowego (!) int ungetc(int c, FILE *stream); • Zwraca znak c do strumienia stream, który musi być otwarty do czytania. • Ten znak zostanie zwrócony przez najbliższe wywołanie getc lub fread dla tego strumienia. • Tylko jeden znak może zostać zwrócony do strumienia bez czytania. • Drugie wywołanie ungetc bez getc spowoduje, że poprzedni znak zostanie zapomniany. • Funkcje fflush, fseek, fsetpos, rewind kasują zwrócony znak. Jacek Lach. Programowanie komputerów ungetc() #include <stdio.h> #include <ctype.h> int main( void ) { int i=0; char ch; puts(”Wpisz liczbę całkowitą i literę:"); /* czytamy znaki aż do nie-cyfry lub EOF */ while((ch = getchar()) != EOF && isdigit(ch)) i = 10 * i + ch - 48; /*zamieniamy ASCII na wartość cyfry*/ /* jeśli przeczytano nie-cyfrę, zwracamy ją do stdin */ if (ch != EOF) ungetc(ch, stdin); printf("i = %d, nast. znak w buforze = %c\n", i, getchar()); return 0; } Jacek Lach. Programowanie komputerów Funkcje biblioteczne – wywołania systemowe Funkcje matematyczne • Plik nagłówkowy: math.h Jacek Lach. Programowanie komputerów • Niektóre systemy wymagają ręcznego łączenia z biblioteką matematyczną (libm) • Szybkość: zależy od typów danych i architektury procesora Funkcje trygonometryczne • Stopnie wyrażone w radianach Jacek Lach. Programowanie komputerów • Parametry i rezultaty są zawsze typu double – sin(x) sinus x – cos(x) cosinus x – tan(x) tangens x – asin(x) sin1(x), x in [1,1] – acos(x) cos1(x), x in [1,1] – atan(x) tan1(x) – atan2(y,x) tan1(y/x) Jacek Lach. Programowanie komputerów Funkcje hiperboliczne • sinh(x) hsinus x • cosh(x) hcosinus x • tanh(x) htangens x Funkcje log, exp... • exp(x) funkcja ex Jacek Lach. Programowanie komputerów • log(x) naturalny logarytm ln(x), x>0 • log10(x) logarytm 10 log10(x), x>0 • pow(x,y) xy • sqrt(x) pierwiastek x, x>=0 Obcinanie Jacek Lach. Programowanie komputerów • ceil(x) najmniejsza liczba całkowita niemniejsza niż x • floor(x) największa liczba całkowita niewiększa niż x Inne • fabs(x) |x| Jacek Lach. Programowanie komputerów • ldexp(x,n) x*2n • frexp(x, int *ip) • modf(x, double *ip) • fmod(x,y) Funkcje pomocnicze • <stdlib.h> • konwersje liczb Jacek Lach. Programowanie komputerów • allokacja • liczby losowe Liczby losowe int rand(void); • Zwraca pseudolosową liczbę od 0 do RAND_MAX Jacek Lach. Programowanie komputerów void srand(unsigned seed); • Ustawia generator liczb pseudolosowych na nową liczbę startową time.h • Funkcje: Jacek Lach. Programowanie komputerów • asctime ctime difftime ftime gettime gmtime localtime mktime settime time_t tzset • System oblicza czas w sposób ciągły w sekundach • Czas startowy: 1 styczeń, 1970 • typ: long int (signed, 32bitowy integer) • Wartość maksymalna: 2^311 = 2 147 483 647 • Co się stanie po 2^311 sekundach od 1 I 1970? Czas • Czwartek, 19 Styczeń 2038 Jacek Lach. Programowanie komputerów • Licznik "przekręci się" na wartość zerową • Prawdopodobne rozwiązanie: użycie liczb 64bitowych • Problem zostanie przesunięty do Soboty, 4 grudnia roku 292 277 026 596 • To chyba rozwiązanie docelowe, ponieważ data przekracza prognozowany czas istnienia Ziemi