Katedra Informatyki Stosowanej
Politechniki Łódzkiej
mgr inż. Tomasz Jaworski
Programowanie w języku
ANSI C
Al. Politechniki 11, 90-924 Łódź
ul. Stefanowskiego 18/22, 90-924 Łódź
http://tjaworski.kis.p.lodz.pl
e-mail:
tjaworski@kis.p.lodz.pl
Programowanie w języku ANSI C
2
1.
Podstawowe informacje o kodzie źródłowym.
W C/C++ tworzenie programu odbywa się w dwóch etapach:
- opracowanie kodu źródłowego
- generowanie kodu wynikowego
Pierwszy etap to zapisanie algorytmu za pomocą instrukcji języka. W efekcie
uzyskujemy kod źródłowy programu, który jest plikiem tekstowym. W drugim etapie zapis w
języku wysokiego poziomu (C++) tłumaczony jest na rozkazy procesora, a program
doprowadzany jest do postaci wykonywalnej w danym systemie operacyjnym. Taki proces
tłumaczenia składa się z dwóch faz: kompilacji i łączenia.
Z punktu widzenia kompilatora kod źródłowy traktowany jest jako ciąg znaków
ASCII. Z punktu widzenia programisty jest on podzielony na wiersze, które zawierają
różnego rodzaju deklaracje, definicje, instrukcji i inne elementy programu. Podstawowe
elementy, z których zbudowany jest program, nazywane są jednostkami leksykalnymi. Są one
porozdzielane znakami spacji, tabulatorów lub sekwencjami końca wiersza.
Do podstawowych jednostek leksykalnych języka C++ zaliczamy: słowa kluczowe,
identyfikatory, stałe, literały łańcuchowe, operatory znaki przestankowe Identyfikator może
składać się z liter małych i wielkich, cyfr oraz znaku podkreślenia. Słowa kluczowe są
specjalnymi identyfikatorami zarezerwowanymi dla ściśle określonych celów. Oto ich
zestawienie:
asm
auto
brake
case
cdecl
_cdecl
__cdecl
char
class
const
continue
_cs
__cs
default
delete
do
double
__ds
else
enum
__es
__export
extern
far
__fastcall
float
for
friend
goto
huge
if
inline
int
interrupt
__loadds
long
near
new
operator
pascal
private
protected
public
register
return
__saveargs
__seg
short
signed
sizeof
__ss
static
struct
switch
template
this
typedef
union
unsigned
virtual
void
volatile
while
Znakami przestankowymi w języku C++ są: [ ] ( ) { } , ; : ... * = #.
2.
Struktura programu w języku C++
Cechą charakterystyczną języka C/C++ jest standardowa możliwość budowy programu
z wielu funkcjonalnych modułów. Program zbudowany jest z funkcji. Każda z nich może
przyjmować dowolną ilość parametrów oraz zwracać jedną wartość. Aby można było
wygenerować wykonywalny kod wynikowy programu, w jednym i tylko w jednym
z modułów musi znajdować się funkcja główna main, od której rozpocznie się wykonywanie
programu. Najprostszy wykonywalny program w języku C może wyglądać następująco:
int main(int)
{
return 0;
}
Powyższy program składa się z bezparametrowej funkcji main. Funkcja zwraca wartość typu
całkowitego. Ciało funkcji, otoczone nawiasami {}, zbudowane jest z instrukcji.
W powyższym przykładzie instrukcja return zwraca wartość 0.
Poniższy przykład demonstruje podstawowe funkcje biblioteczne obsługujące standardowe
wejście i wyjście. Aby móc stosować te funkcje należy włączyć do programu plik stdio.h
instrukcją #include.
#include <stdio.h>
int main(void)
{
char imie[20];
int i;
Programowanie w języku ANSI C
3
printf(„\nPodaj swoje imie: „);
// wypisz na ekranie
gets(imie);
// pobierz wartość łańcuchową
puts(„Ile masz lat? „);
scanf(„%d”, &i);
// pobierz wartość liczbową
printf(“\n%s ma %d lat.”, imie, i);
return 0;
}
3.
Typy danych, deklaracje zmiennych i stałych
Typy danych dostępne w języku C można podzielić zasadniczo na typy proste i strukturalne.
Typy proste są niepodzielne i wykorzystywane są do tworzenia typów strukturalnych. Typy
proste to:
Arytmetyczne: całkowite, zmiennoprzecinkowe i znakowe
a. Wskaźnikowe
b. Referencyjne
Natomiast typy strukturalne to:
• Tablice
• Struktury i unie
• Klasy
Typy i zmienne całkowite
Słowo kluczowe
Znaczenie
char
int
long
signed
short
unsigned
Typ znakowy
Typ całkowity
Typ tzw. długich liczb całkowitych
Liczby ze znakiem
Typ tzw. krótkich liczb całkowitych
Liczby bez znaku
W/w słów kluczowych zwykle używa się w połączeniu. Poniższa tabela demonstruje takie
połączenia i ich rozmiar w pamięci oraz zakres przyjmowanych wartości.
Typ
Rozmiar
w bitach
Min
Max
unsigned char
signed char
unsigned int
short signed int
signed int
long unsigned int
long signed int
8
8
16
16
16
32
32
0
-128
0
-32768
-32768
0
-2 147 483 648
255
127
65535
32767
32767
4 294 967295
2147 483 647
Typy i zmienne rzeczywiste (zmiennoprzecinkowe)
Typ
Rozmiar
w bitach
Min
Max
float
double
long double
32
64
80
3,4*10
-38
1,7*10
308
3,4*10
-4932
3,4*10
38
1,7*10
308
3,4*10
4932
Programowanie w języku ANSI C
4
Typy i zmienne wskaźnikowe
W języku C/C++ istnieje możliwość definiowania zmiennych zawierających adres jakiegoś
obszaru w pamięci, przy czym obszar ten może być interpretowany jako zmienna określonego
typu. Są to tzw. zmienne wskaźnikowe. Mogą one zawierać adres zmiennych należących do
typów zarówno prostych jak i strukturalnych. Zmienne takie nazywamy wówczas zmiennymi
wskazywanymi
. Jak pokazano na rysunku obok.
Deklaracje zmiennych wskaźnikowych mogą wyglądać następująco:
char *wsk_znaku;
int *wsk_liczby_calk;
double *wsk_liczby_rzecz;
char (*wsk_tablicy)[10];
int **wsk_wsk;
Inny przykład pokazuje zmienne wskazywane i wskaźnikowe. Dostęp do zmiennych
wskazywanych:
void func()
{
char znak = ‘a’, *wsk_znaku = &znak;
int liczba = 100, *wsk_liczby_calk = &liczba;
...
*wsk_znaku = ‘b’;
*wsk_liczby_calk = ‘222’;
...
}
W przykładzie zamieszczonym powyżej zadeklarowano zmienne typu char i int oraz
zmienne wskazujące zmienne wymienionych tu typów. Zadeklarowanym zmiennym
wskaźnikowym przypisano adres (operator & służy do pobierania adresu zmiennej)
zmiennych typów wskazywanych przez te zmienne. W rezultacie przypisanie takie jak:
*wsk_znaku = ‘b’;
operuje na zmiennej wskazywanej przez zmienną wsk_znaku, a więc w tym przypadku na
zmiennej znak. W tej sytuacji jest ono równoważne przypisaniu:
znak = ‘n’;
Wskaźniki w języku C/C++ posiadają ogromne znaczenie, gdyż umożliwiają:
• Tworzenie i przetwarzanie dynamicznych struktur danych,
• Zarządzanie blokami pamięci, łańcuchami i tablicami,
• Przekazywanie parametrów funkcji, w tym także parametrów funkcyjnych.
Typy i zmienne referencyjne (C++)
Poza typem wskaźnikowym język C++ wprowadza tzw. typ referencyjny. Zmienne tego typu
służą do reprezentowania innych zmiennych w programie. Operacje na zmiennej x są
równoważne operacjom na zmiennej referencyjnej związanej ze zmienną. W praktyce
omawiane typy są wykorzystywane podczas przekazywania parametrów do funkcji oraz
zwracania wartości funkcji. Deklaracja zmiennej referencyjnej przedstawia się następująco:
typ &identyfikator = identyfikator_zmiennej;
przy czym znak może wystąpić zarówno przy identyfikatorze zmiennej, jak i przy nazwie
typu. Poniżej zademonstrowano przykład wykorzystania zmiennych referencyjnych.
int n = 10, i, &ri = i;
// zmienna referencyjna ri, związana ze zmienną i
double pos = 10, &r_pos = pos;
//zmienna referencyjna r_pos, związana ze zmienną pos
...
ri = n;
//zmiennej referencyjnej ri przypisz wartość zmiennej n,
//czyli 10, a nie powiąż ze zmienną n, jakby się mogło
//wydawać.
Programowanie w języku ANSI C
5
Ponieważ operacje na zmiennej ri są równoważne operacjom na zmiennej i, więc w wyniku
ostatniego przypisania zmienne i również zyskuje wartość 10.
Tablice i wskaźniki. Łańcuchy
Tablica jest złożoną strukturą danych, składającą się z elementów tego samego typu. Zajmuje
ona ciągły obszar w pamięci o rozmiarze niezbędnym do zapamiętania jej elementów. Dostęp
do kolejnych elementów jest możliwy za pośrednictwem indeksów, liczby określającej
położenie elementu w tablicy. Deklaracja tablicy N-wymiarowej o wymiarach wymiar1,
wymiar2, ..., wymiarN
wygląda następująco. Poniżej zamieszczono przykładowe deklaracje
tablic.
typ ident_tablicy [wymiar1][wymiar2] ... [wymiarN];
char str[30];
//tablica 30 znaków
char *t[12];
//tablica 12 wskaźników znaków
double tabdbl[30][20] //dwuwymiarowa tablica liczb rzeczywistych
int tab1[20] = {10, 20} //inicjowanie tablicy. Wpisywane parametry muszą być wartościami stałymi
int tab2[10][10] = { {3.1}, {-10, 90} };
//tu zainicjowano tylko pierwsze dwa elementy z pierwszych dwóch kolumn.
//Pozostałym domyślnie przypisana zostanie wartość 0.
Najprostszym sposobem dostępu do elementu tablicy jest podanie jego pozycji (od 0 do N-1),
np.
tab1[3] = 0;
//element czwarty (0, 1, 2, 3, .., 19)
tab2[1][1] = 4;
Przydzielanie pamięci
Zadeklarowano zmienną wskaźnikową oraz przydzielono jej pamięć:
#include <stdlib.h>
…
int n = 20;
int *ptr = (int *)malloc(n * sizeof(int));
//rozmiar może być podany jako zmienna
int ptr2[20];
//tu rozmiar musi być podawany jako stała
Odwołania do elementów ptr i ptr2 nie różnią się niczym.
Łańcuchy w języku C++
Łańcuch w języku C/C++ jest tablica znaków zakończoną znakiem o kodzie zero – ‘\0’.
Łańcuch deklarujemy tak samo, jak tablice znaków. Więc np.
char str[100];
Deklarację można połączyć z jego inicjacją:
char a[10] = ”\nRadek”;
char str[20] = {’\n’,’R’,’a’,’d’,’e’,’k’,’\0’};
char *str1 = ”Radek. Autor skryptu”;
Znajdowanie długości takiego łańcucha możliwe jest przy zastosowaniu funkcji strlength() i
tak np.
int len = strlen(str1);
Struktury
Jeżeli wystąpi potrzeba zdefiniowania obiektu i opisania go kilkoma parametrami,
można zgromadzić potrzebne dane Sw jednym miejscu – w strukturze. Składają się one ze
składowych różnych typów, umieszczonych w pamięci jedna za drugą. Rozmiar struktury jest
więc równy sumie rozmiarów jej poszczególnych składowych. Deklaracja struktury wygląda
następująco:
Programowanie w języku ANSI C
6
struct ident_typu_struktury
{
deklaracje-składowych
} [ident_struktury[=inicjator], ...];
Identyfikator typu struktury może zostać pominięty, podobnie jak identyfikatory struktury
i inicjatory. Poniżej podano przykłady praktyczne deklarownia struktur.
struct punkt
{
double x, y;
}
struct pracownik
{
char *nazwisko;
float wyplata;
int czas_pracy;
double efektywnosc;
worker *nastepny;
} w1 = { „Radek”, 1000, 10, 0.22}, tab[10];
W drugim przypadku zdefiniowano typ struktury pracownik’a. Definicję typu struktury
połączono z utworzeniem zmiennej strukturalnej w1 oraz tablicy tab. Zainicjowano też
strukturę w1. Na uwagę może zwrócić jedna składowa typu pracownik. Służy ona do
wskazywania na następny obiekt typu pracownik będący w liście wszystkich obiektów typu
pracownik
.
Dostęp do składowych struktury umożliwiają operatory . i ->. Pierwszy wykorzystywany
w przypadku
struktur
reprezentowanych
przez
zmienne
strukturalne,
drugi
przez wskaźnikowe. I tak np.
pracownik pr1, *pr2;
...
pr1.wyplata = 1000;
pr2->wyplata = 2000;
Zasięg deklaracji i widoczność zmiennych
Zasięg deklaracji zmiennych może obejmować albo określony blok programu (otoczony
nawiasami klamrowymi), albo cały plik kodu źródłowego, począwszy od miejsca deklaracji.
Deklaracja zmiennej obejmuje cały plik, jeśli znajduje się ona poza wszystkimi blokami
programu. Zmienne takie nazwami zmiennymi globalnymi. Zmienna zadeklarowana
wewnątrz bloku programu jest zmienna lokalną i nie jest widoczna poza tym blokiem.
Natomiast jest ona widoczna we wszystkich blokach znajdujących się wewnątrz danego bloku
macierzystego.
Programowanie w języku ANSI C
7
4.
Instrukcje
Jednym z najważniejszym elementów każdego języka programowania sa instrukcje.
UmożliSwiają one zapis algorytmu, a co za tym idzie – służą do sterowania przebiegiem
programu.
Instrukcje warunkowe
Gdy wystąpi problem sprawdzenia, czy zachodzi dana zależność i w zależności od tego
wykonanie takich czy innych czynności.
Ogólna postać instrukcji warunkowej „jeżeli” przedstawia się następująco:
if (wyrażenie-warunkowe)
{
instrukcje składowe
}
else if (wyrażenie-warunkowe)
{
instrukcje składowe
}
else
{
instrukcje składowe
}
Instrukcja wyboru
Instrukcja wyboru ma następującą postać:
switch (wyrażenie-sterujące)
{
case wyrażenie-stałe-typu-całkowitego: instrukcje składowe;
[break];
default: wyrażenie-stałe-typu-całkowitego: instrukcje składowe;
}
Etykieta default jest nazywana domyślną etykietą wyboru.
Instrukcje iteracyjne
Pętla „dla” (for).
for (wyrażenie-inicjujące ; wyrażenie-warunkowe ; wyrażenie-zwiększające)
{
instrukcje składowe
}
Instrukcja „dopóki” (while)
while (wyrażenie-warunkowe)
{
instrukcje składowe
}
Instrukcja „wykonuj .. dopóki” (do .. while)
do
{
instrukcje składowe
} while (wyrażenie-warunkowe)
Instrukcje sterujące
• „przerwij” (break)
• „kontynuuj” (continue)
• „zwróć wartość i powróć” (return)
• „skok do” (goto)
Programowanie w języku ANSI C
8
5.
Funkcje
Podczas zapisu algorytmu często spotykamy się z problemami wielokrotnego wykonywania
tych samych operacji, lecz dla różnych danych, w różnych sytuacjach. W celu ominięcia
powielania kodu źródłowego można wykorzystać funkcje. W obrębie definicji takiej funkcji
można zamknąć pewne operacje wykonywane na podstawie parametrów wejściowych. Każda
funkcja w języku C/C++ posiada określony typ wartości, która jest zwracana po zakończeniu
jej wykonywania.
W praktyce pisząc program buduje się go z wielu funkcji (metod). Ogólne działanie każdej
z nich jest podobne i zilustrowane na rysunku.
Zmienne globalne
Parametry
Wartości
Modyfikacja zmiennych
globalnych i inne efekty
działania funkcji
Funkcja
Rys. 1 Ilustracja działania funkcji w programie
Na podstawie parametrów wejściowych funkcja wykonuje operacje, których rezultatem są
wartości funkcji. Często zdarza się jednak, że parametry funkcji nie są jej jedynymi danymi
wejściowymi, podobnie jak wartości funkcji nie są jej jedynymi rezultatami wykonania.
Funkcja może np. pobierać dane z urządzenia wejściowego (plik, klawiatura) i również je tam
wysyłać lub korzystać ze zmiennych globalnych programu, których wartość może wpływać
na jej działanie.
Zalety stosowania funkcji w konstrukcji programu:
- przejrzystość i bardziej czytelna struktura programu
- oszczędność czasu – raz napisana i skompilowana funkcja może być używana
wielokrotnie w różnych programach
- oszczędność pamięci – funkcja jest umieszczana w jednym miejscu pamięci, do którego
następują odwołania w momencie jej wywołania.
Deklaracja i definicja funkcji
Deklaracja funkcji w odróżnieniu od definicja funkcji jest pojęciem logicznym, gdyż stanowi
tylko informację dla kompilatora, że funkcja o nazwie, typie wartości i parametrów może (ale
nie musi!) zostać użyta gdzieś w danym module programu. Definicja funkcji określa
natomiast, co funkcja właściwie robi. Stanowi ona zapis jakiegoś algorytmu lub jego części.
Definicja funkcji powoduje, w odróżnieniu od deklaracji, przydzielenie obszaru pamięci,
w którym znajdzie się kod wynikowy funkcji.
Deklaracja funkcji zwana też prototypem wygląda zwykle następująco:
<typ> identyfikator_funkcji (lista_deklaracji_typów_parametrów);
Jeżeli pominięty zostanie typ wartości zwracanej, przyjmowany jest on domyślnie jako int.
Również lista deklaracji typów parametrów może być pusta. Oznaczać to będzie, że funkcja
nie przyjmuje żadnych parametrów.
Programowanie w języku ANSI C
9
Dopuszczalne jest również użycie specyfikatora funkcji const. Znaczenie użycia jest zwykle
takie, by zagwarantować niezmienialność zmiennych wskazywanych danym parametrem np.:
int strlen(const char *s);
Powyższa funkcja nie może zmieniać wartości zmiennej wskazywanej parametrem s.
Wywołanie funkcji
Wywołanie funkcji ma postać:
nazwa_funkcji (lista_parametrów_wywołania);
Na listę parametrów wywołania składają się oddzielone przecinkami wyrażenia typu
zgodnego z typem parametru funkcji.
Przeanalizujmy poniższy przykład. Powiedzmy, że mamy zdefiniowaną funkcję następująco:
int funk(int i, int j, char *str)
{
...
}
wówczas wywołanie może mieć postać:
int a = 10, b = 20;
char *napis = ”Programowanie w C++”;
funk(a, b, napis);
//wywołanie funkcji
Funkcje przeciążone, domyślne wartości parametrów (C++)
Funkcjami przeciążonymi (ang. overloaded functions) nazywamy rodzinę funkcji o tej samej
nazwie, lecz różniącej się parametrami (typem i/lub liczbą) i ewentualnie typem wartości
zwracanej. Dwie funkcje przeciążone nie mogą różnić się tylko typem wartości zwracanej.
O tym, która funkcja zostanie wywołana, decydują parametry wywołania. Oto kilka
przykładów funkcji przeciążonych:
int funk(int x);
int funk();
double funk(double x);
double funk(double x, double y);
bool funk(double x);
//to jest zła deklaracja funkcji przeciążonej. Istnieje już
//funkcja o takiej nazwie i o takim parametrze wejściowym
Domyślną wartość parametrów podajemy w deklaracji funkcji, co ilustruje poniższy przykład:
int funk(int i, double x = 10.1, double y = 20.2);
Daje nam to możliwość wywoływania funkcji zarówno w sposób funk(a, b, c) jak i w sposób
funk(a)
– reszta parametrów ma wartości domyślne.
Przekazywanie parametrów i zwracane wartości
Możliwe są trzy rodzaje przekazywania parametrów do funkcji:
1. przez wartość
2. przez wskaźnik (C)
3. przez referencje (C++)
Ad. 1
W wyniku przekazania parametru przez wartość funkcja otrzymuje kopię zmiennej na stosie
procesora. Przekazywany parametr jest traktowany tak samo, jak wszystkie zmienne
zadeklarowane w ciele funkcji tj. istnieje tylko podczas jej wywołania.
Demonstruje nam to poniższy przykład:
Programowanie w języku ANSI C
10
#include <iostream.h>
int funk(int x)
{
x++;
//tu zmieniamy wartość parametru x
return x;
//i go zwracamy
}
void main(void)
{
int liczba = 10, wartosc;
wartosc = funk(liczba);
cout << ”Liczba: ” << liczba << ” Wartość: ” << wartosc;
}
W wyniku działania programu na ekranie zostanie wyświetlony napis: Liczba: 10 Wartość:
11
. Dlaczego? W funkcji funk zmieniliśmy wartość parametru x, do którego przypisana była
wartość parametru liczba. Ale ponieważ x jest zmienna lokalną w funkcji funk, Wartość
zmieniona została zapomniana zaraz po zakończeniu działania funkcji. Zmienioną wartość
mogliśmy tylko otrzymać jako wynik działania (wartość zwracaną) funkcji.
Ad. 2
Przekazywanie parametrów funkcji przez wskaźnik jest w zasadzie odmianą przekazywania
przez wartość. Tu funkcja otrzymuje kopię wskaźnika. Ale ma to jednak głębszy sens.
Wskaźnik przekazywany do funkcji może identyfikować zmienną należącą do innej funkcji.
Przypisanie wartości zmiennej wskazywanej przez parametr wskaźnikowy pozwala więc
zmienić wartość zmiennych utworzonych w innych funkcjach programu. Takie
przekazywanie parametru jest używane zasadniczo w dwóch celach:
- do przekazywania struktur danych o dużych rozmiarach, takich jak tablice czy łańcuchy,
- w celu umożliwienia zwrócenia więcej niż jednej wartości.
Przykład:
#include <sting.h>
#include <iostream.h>
char *funk(char *str)
{
strcat(str, „ dobry“);
return str;
}
void main(void)
{
char *napis = ”Dzień”;
cout << napis << endl;
//napis nie zmodyfikowany
cout << funk(napis) << endl;
//wyświetlona wartość zwracana
cout << napis << endl;
//wyświetlona zmodyfikowana zmienna
//przekazana przez wskaźnik do funkcji
}
W wyniku działania programu otrzymamy wyświetlony na ekranie tekst:
Dzień
Dzień dobry
Dzień dobry
Podsumowując można powiedzieć, że takie rozwiązanie pozwala na ingerencję w zawartość
zmiennych i struktur danych utworzonych poza funkcją, do której parametr wskaźnikowy
został przekazany. Z możliwości tej należy korzystać roztropnie, gdyż niezauważone lub
zakamuflowane oddziaływanie funkcji na wartość zmiennych należących do innych funkcji
programu może doprowadzić do trudnych do wykrycia błędów.
Programowanie w języku ANSI C
11
Ad. 3
W języku C++ dodatkowo występuje typ referencyjny, który umożliwia deklarowani
zmiennych reprezentujące inne zmienne. Ogólnie rzecz ujmując to zmienne referencyjne są
wykorzystywane przy przekazywaniu parametrów do i z funkcji. Operacje są przeprowadzane
bezpośrednio na zmiennej, której referencję przekazano do funkcji.
6.
Wypisywanie danych na ekran
Po załadowaniu biblioteki
#include <iostream.h>
możliwe jest wypisywanie danych na ekranie. Do tego celu służy funkcja cout. Jest to
specyficzne funkcja, które ma zmienną liczbę parametrów wejściowych, które oddzielone są
znakami „<<” i nie są zebrane w nawiasy „()”. Parametrami funkcji mogą być: zwykły tekst
cout << “Witam na kursie”;
zmienne
int val = 1;
double val_d = 1.5;
char *str = “Napis”;
cout << val << str << val_d << endl;
Wartość każdej ze zmiennych zostanie wyświetlona kolejno na ekranie. Ostatni parametr
endl jest znakiem nowej linii.
7.
Pobieranie danych od użytkownika
Po załadowaniu biblioteki
#include <iostream.h>
możliwe jest wczytywanie danych od użytkownika. Do tego celu służy funkcja cin. Jest to
specyficzne funkcja, które ma zmienną liczbę parametrów wejściowych, które oddzielone są
znakami „>>” i nie są zebrane w nawiasy „()”.
int val;
double val_d;
char *str;
cout <<”Podaj liczbe: ”;
cin >> val;
cout >> “Podaj liczbę i napis oddzielając znakiem entera:”;
cin >> str >> val_d;
Zostaną wczytane kolejno wartości do zmiennych odpowiednich typów.
8.
Operacje na plikach
Niezależnie od wykonywanych operacji na plikach, korzystamy zawsze z typu plikowego
FILE*. Aby był one widoczny w programie należy dołaczyć następującą bibliotekę:
#include <stdio.h>
Wczytywanie danych z pliku
Poniżej zamieszczono przykładowy kod programu. Program odczytuje dane z pliku.
#include <stdio.h>
#include <iostream.h>
main()
{
char *NazwaPliku;
//pytamy użytkownika o nazwę pliku
cout << “Podaj nazwę pliku, z którego dane mam przeczytać: “;
cin >> NazwaPliku;
//otwieramy plik w trybie binarnym do odczytu i zapamiętujemy uchwyt do pliku w zmiennej plik
FILE *plik = fopen(NazwaPliku, „rb”);
//możemy pobierać dane do bufora o określonej wielkości, ale nie więcej niż całą linię
char word[100];
Programowanie w języku ANSI C
12
fgets(word, 100, plik);
//lub czytać dane liczbowe bądź łańcuchowe oddzielone określonym separatorem
int zmienna;
fscanf(plik, „%d”, &zmienna);
// %d – oczekiwana liczba całkowita
// %f – oczekiwana liczba rzeczywista
// %s – oczekiwana wartość łańcuchowa
//funkcja sprawdzająca koniec pliku
feof(plik);
//która zwraca 1, gdy napotkano już na koniec pliku i 0, gdy końca pliku jeszcze nie było
//na koniec zamykamy plik
fclose(plik);
}
Zapisywanie danych do pliku
#include <stdio.h>
#include <iostream.h>
main()
{
char *NazwaPliku;
//pytamy użytkownika o nazwę pliku
cout << “Podaj nazwę pliku, gdzie mam dane zapisać: “;
cin >> NazwaPliku;
//otwieramy plik w trybie binarnym do zapisu i zapamiętujemy uchwyt do pliku w zmiennej plik
//jak pliku nie było, to zostanie taki stworzony
FILE *plik = fopen(NazwaPliku, „wb”);
//zapis
char word[100] = „krotkie slowo”;
fputs(word, plik);
//lub
int zmienna = 2;
fprintf(plik, “%d”, zmienna);
//i również zamykamy plik, gdu niepotrzebny
fclose(plik);
}