MATERIAŁY POMOCNICZE PODSTAWY PROGRAMOWANIA Na podstawie: Programowanie w C - Stworzone na Wikibooks, bibliotece wolny podręczników Funkcja getchar() Jest to bardzo prosta funkcja, wczytująca 1 znak z klawiatury. W wielu przypadkach dane mogą być buforowane przez co wysyłane są do programu dopiero, gdy bufor zostaje przepełniony lub na wejściu jest znak przejścia do nowej linii. Z tego powodu po wpisaniu danego znaku należy nacisnąć klawisz enter, aczkolwiek trzeba pamiętać, że w następnym wywołaniu zostanie zwrócony znak przejścia do nowej linii. Funkcja zwraca typ int int getc(file *stream); Gdy nastąpił błąd lub nie ma już więcej danych funkcja zwraca wartość EOF (która ma jednak wartość logiczną 1 toteż zwykła pętla while (getchar()) nie da oczekiwanego rezultatu): int main(void) int c; while ((c = getchar())!=eof) if (c==' ') c = '_'; putchar(c); Funkcja gets Funkcja gets służy do wczytania pojedynczej linii. Przyjmuje ona jeden argument adres pierwszego elementu tablicy, do którego należy zapisać odczytaną linię. Z tego powodu nie ma żadnej możliwości przekazania do tej funkcji rozmiaru bufora podanego jako argument. Podobnie jak w przypadku scanf() może to doprowadzić do przepełnienia bufora, co może mieć tragiczne skutki. Zamiast tej funkcji należy używać funkcji fgets(). char *gets(char *str); Funkcja gets() czyta linię ze standardowego wejścia (usuwa ją stamtąd) i umieszcza ją w tablicy znakowej wskazywanej przez str. Ostatni znak linii (znak nowego wiersza - '\n') zastępuje zerem (znakiem '\0'). Funkcja fgets
Funkcja fgets() jest bezpieczną wersją funkcji gets(), która dodatkowo może operować na dowolnych strumieniach wejściowych. Jej użycie jest następujące: fgets(tablica_znaków, rozmiar_tablicy_znaków, stdin); int main(void) char buffer[128], whole_line = 1, *ch; while (fgets(buffer, sizeof buffer, stdin)) /* 1 */ if (whole_line) /* 2 */ putchar('>'); if (buffer[0]!='>') putchar(' '); fputs(buffer, stdout); /* 3 */ for (ch = buffer; *ch && *ch!='\n'; ++ch); /* 4 */ whole_line = *ch == '\n'; if (!whole_line) putchar('\n');
Czytanie i pisanie do plików Nazwy funkcji z pierwszej grupy zaczynają się od litery f (np. fopen(), fread(), fclose()), a identyfikatorem pliku jest wskaźnik na strukturę typu FILE. Owa struktura to pewna grupa zmiennych, która przechowuje dane o danym pliku jak na przykład aktualną pozycję w nim. Szczegółami nie musisz się przejmować, funkcje biblioteki standardowej same zajmują się wykorzystaniem struktury FILE, programista może więc zapomnieć, czym tak naprawdę jest struktura FILE i traktować taką zmienną jako uchwyt, identyfikator pliku. Dane znakowe #include <stdlib.h> int main () FILE *fp; /* używamy metody wysokopoziomowej */ /* musimy mieć zatem identyfikator pliku, uwaga na gwiazdkę! */ char tekst[] = "Hello world"; if ((fp=fopen("test.txt", "w"))==null) printf ("Nie mogę otworzyć pliku test.txt do zapisu!\n"); exit(1); fprintf (fp, "%s", tekst); /* zapisz nasz łańcuch w pliku */ fclose (fp); /* zamknij plik */ Funkcja fopen zwraca wskaźnik do struktury *FILE w przypadku poprawnego otwarcia pliku, bądź też NULL, gdy plik nie może zostać otwarty. Po zakończeniu korzystania z pliku należy plik zamknąć. Robi się to za pomocą funkcji fclose. Pliki a strumienie Do zapisu do pliku używamy funkcji fprintf, która wygląda bardzo podobnie do printf jedyną różnicą jest to, że w fprintf musimy jako pierwszy argument podać identyfikator pliku. Podobnie jak scanf i fscanf. W rzeczywistości język C traktuje tak samo klawiaturę i plik są to źródła danych, podobnie jak ekran i plik, do których można dane kierować PLIKI NAZYWAMY STRUMIENIAMI Każdy program w momencie uruchomienia otrzymuje od razu trzy otwarte strumienie: stdin (wejście) stdout (wyjście) stderr (wyjście błędów) (aby z nich korzystać należy dołączyć plik nagłówkowy stdio.h)
fprintf (stdout, "Hej, ja działam!") = printf ("Hej, ja działam!"); fscanf (stdin, "%d", &zmienna) = scanf("%d", &zmienna); Przykład: printf("wcisnij Ctrl+D+Enter lub Ctrl+Z+Enter aby zakonczyc\n"); while ( (c = fgetc(stdin))!= EOF) fputc (c, stdout); fputc (c, fp); fclose(fp); Rozmiar pliku Dzięki standardowym funkcjom języka C możemy m.in. określić długość pliku. Do tego celu służą funkcje fsetpos, fgetpos oraz fseek. Ponieważ przy każdym odczycie/zapisie z/do pliku wskaźnik niejako przesuwa się o liczbę przeczytanych/zapisanych bajtów. Możemy jednak ustawić wskaźnik w dowolnie wybranym miejscu. int fseek(file *file, long offset, int mode); Funkcja fseek ustawia pozycję w pliku file na offset w zależnośći od wartości argumentu mode. Jeśli mode jest równy zero, to offset liczony jest od początku. Jeśli 1, to offset przesuwany od aktualnej pozycji, a 2 przesuwany o offset od końca pliku (wskaźnik pliku jest przesuwany do pozycji będącej sumą rozmiaru pliku i parametru offset). Zwraca: Zero gdy funkcja wykonała się pomyślnie, w przypadku błędu wartość niezerowa. int fsetpos (FILE* file, fpos_t* pos); Funkcja fsetpos zmienia aktualną pozycję wskaźnika do pliku file na pos. Zwaraca: Zero gdy funkcja wykonała się pomyślnie, EOF w przypadku wystąpienia błędu, k int fgetpos (FILE* file, fpos_t* pos); Funkcja fgetpos umieszcza w pos aktualną pozycję wskaźnika do pliku file. Zwaraca: Zero gdy funkcja wykonała się pomyślnie, EOF w przypadku wystąpienia błędu int main (int argc, char **argv) FILE *fp = NULL; int dlugosc; if ((fp=fopen( plik.txt, "rb"))==null) printf ("Błąd otwarcia pliku: %s!\n", plik.txt ); return 1; fseek (fp, 0, SEEK_END); /* ustawiamy wskaźnik na koniec pliku */
Pliki binarne np: pliki graficzne fgetpos (fp, &dlugosc); printf ("Rozmiar pliku: %d\n", dlugosc); fclose (fp); Do zapisu : nagłówka pliku używana jest funkcja fprintf, tablicy do pliku używana jest funkcja fwrite. Do odczytu: nagłówka pliku używana jest funkcja fscanf, tablicy do pliku używana jest funkcja fread. size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream); Argumenty: ptr - wskaźnik na tablicę size - rozmiar elementu tablicy nitems - liczba elementów do zapisu stream - plik, na którym wykonywana jest operacja Opis Funkcja fwrite kopiuje nitems elementów z poddanej tablicy do pliku. Kopiowanie kończy się w przypadku wystąpienia błędu lub po skopiowaniu podanej liczby elementów. Wskaźnik pliku jest przesuwany, tak by wskazywał pierwszy element po ostatnim zapisanym. Wartość zwracana Liczba faktycznie zapisanych elementów. size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream); Argumenty: ptr - wskaźnik na tablicę size - rozmiar elementu tablicy nitems - liczba elementów do odczytu stream - plik, na którym wykonywana jest operacja Opis Funkcja fread kopiuje nitems elementów z podanego pliku do tablicy. Kopiowanie kończy się w przypadku wystąpienia błędu, końca pliku lub po skopiowaniu podanej liczby elementów. Wskaźnik pliku jest przesuwany, tak by wskazywał pierwszy nieodczytany element. Wartość zwracana Liczba faktycznie wczytanych elementów. int main() const int dimx = 800; const int dimy = 800; int i, j; FILE * fp = fopen("first.ppm", "wb"); /* b - tryb binarny */ fprintf(fp, "P6\n%d %d\n255\n", dimx, dimy);
for(j=0; j<dimy; ++j) for(i=0; i<dimx; ++i) static unsigned char color[3]; color[0]=i % 255; /* red */ color[1]=j % 255; /* green */ color[2]=(i*j) % 255; /* blue */ fwrite(color,1,3,fp); fclose(fp); Inne przydatne funkcje: long ftell(file *file); Funkcja ftell zwraca aktualną pozycję wskaźnika pliku. //... - mamy otwarty plik i czytamy z niego dane long offset = ftell(file); // 'file' to nasz plik printf("pozycja w pliku: %d\n", offset); //... int feof(file *stream); Funkcja zwraca wartość niezerową jeżeli napotka koniec pliku tekstowego. int main() int i=0; int nr[32]; FILE *plik; plik=fopen("numery.txt", "r"); while (feof(plik)==0) fscanf(plik, "%d\n", &nr[i]); printf("%d %d\n", i+1, nr[i]); ++i; fclose(plik);