Progr

Programowanie

nie

w jęz

w ję yku C

zyku C

© 2012

Grzegorz Łukawski & Maciej Lasota

Politechnika Świętokrzyska w Kielcach

Wskaźniki i obsługa plików

w języku C

Wskaźnik – definicja

Wskaźnik – to zmienna przechowująca adres, wskazująca inną zmienną.

Zwykłe zmienne i wskaźniki

ADRES

RAM

0

1

2

int z = 99;

int *w = &z;

1000

1004

99

1008

1012

1016 1004

Operatory związane ze wskaźnikami w = &z

Jednoargumentowy operator tworzący wskaźnik na zmienną. Nie można go stosować do stałych, wyrażeń i zmiennych typu register.

z = *w

Operator wyłuskania – symbolizuje „adresowanie pośrednie”. Zastosowany do wskaźnika daje zawartość obiektu wskazywanego przez ten wskaźnik.

Zmienne wskaźnikowe

Definicja „int *wsk” mówi że „*wsk” jest zmienną typu „int” .

int *wsk;

// wsk = ??

int x=1, y=2, tabela[10];

wsk = &x;

y = *wsk;

// y = 1

*wsk = 0;

// x = 0

wsk = &tabela[3];

UWAGA!

Wskaźnik zawsze wskazuje na obiekty określonego rodzaju – można to zmienić przez rzutowanie. Wskaźnik zawsze na coś wskazuje!

Operacje na zmiennych wskaźnikowych Operacje na zmiennych wskazywanych przez wskaźniki:

*wsk += 100;

printf(”%d”, *wsk);

y = *wsk * 10;

x = tabela[*wsk];

*wsk = *wsk + 88;

(*wsk)++;

Operacje na zmiennych wskaźnikowych Operacje przypisania na wskaźnikach:

int *w1, *w2;

int x = 30;

w1 = &x;

// *w1 = 30

w2 = w1;

// *w2 = *w1 = 30

Wskaźnikowe argumenty funkcji void dodaj_czas(int *godz, int *min, int czas)

{

*min += czas;

if(*min > 59) {

*godz += 1;

*min -= 60;

}

}

Tablice i wskaźniki

int tab[5];

int *wsk, x;

wsk = &tab[0];

x = *wsk;

// x = tab[0]

x = *(wsk+1);

// x = tab[1]

Wartością zmiennej tablicowej jest wskaźnik na zerowy element tej tablicy, zapis równoważny:

wsk = &tab[0];

<=>

wsk = tab;

Przy dodawaniu liczby do adresu, kolejny element wyznaczany jest automatycznie (kompilator bierze pod uwagę typ danej na którą wskazuje dany wskaźnik).

Tablice i wskaźniki

Tablicę można traktować jak wskaźnik i vice versa:

*tab

<=>

tab[0]

*(tab+i)

<=>

tab[i]

wsk[3]

<=>

*(wsk+3)

Nazwa tablicy nie jest zmienną, więc nie można zmieniać jej wartości: tab = wsk+1; tab++;

Wskaźnik jest zmienną, więc można go modyfikować: wsk = tab+1; wsk++;

Tablice i wskaźniki jako parametry funkcji Tablicowy parametr funkcji wskazuje na zerowy element tablicy. Wiedząc o tym, do funkcji można przekazać część tablicy, np.: char tekst[] = ”Ala ma kota”;

puts(tekst + 4);

puts(&tekst[4]);

Deklaracja parametru funkcji może mieć postać: int funkcja(int tab[]) {…}

int funkcja(int *tab)

{…}

Ujemne indeksy tablic?

int tablica[7];

int *polowa = &tablica[3];

(…)

polowa[-3] = 0;

polowa[-2] = 1;

polowa[-1] = 2;

polowa[0] = 3;

polowa[1] = 4;

(…)

Wartości początkowe wskaźników Wartością początkową wskaźnika może być zero (NULL), lub wskaźnik na już zadeklarowaną zmienną, np.:

int elementy[100];

int *koniec = &elementy[99];

int *pusty = NULL;

Wyjątek – wskaźniki znakowe mogą być inicjowane stałymi napisowymi: char *tekst = ”Tekst to jest”;

Język C gwarantuje, że zero nigdy nie będzie prawidłowym adresem. Zero (NULL) służy do oznaczania „pustych” wskaźników, np.: if(pusty)

puts(”Wskaznik OK”);

else

puts(”Wskaznik pusty!”);

Wskaźniki znakowe

Wskaźniki znakowe wzkazują na stałe znakowe zawsze dłuższe o 1 bajt (zero kończące):

char t1[] = ”Abc”;

// Tablica

char *t2 = ”Abc”;

// Wskaźnik

W przypadku wskaźnika nie wolno zmieniać tekstu (stałej napisowej), skutek takiego działania jest nieokreślony. Można za to zmienić wskaźnik i przypisać mu inną stałą napisową, np.:

t2[2] = 'W';

// ZABRONIONE!

t2 = ”Wxyz”;

// OK

W przypadku tablicy znaków można zmieniać tekst. Nie można przypisać innej stałej napisowej (tylko z pomocą funkcji strcpy()), np.: t1[2] = 'W';

// OK

t1 = ”Wxyz”;

// ZABRONIONE!

strcpy(t1, ”Wxyz”);

// OK??

Tablica wskaźników

int i;

char *imiona[] = {”Ania”, ”Ala”, ”Basia”};

for(i=0;i < 3;i++)

puts(imiona[i]);

Tablica wskaźników VS tablica 2-wymiarowa char tab[][] = {…};

A B C 0 ? ? ? X Y Z 1 2 3 0 D 0 ? ? ? ? ?

char *tab[] = {…};

A B C 0

X Y Z 1 2 3 0

D 0

Obsługa plików

#include <stdio.h>

Uchwyt (deskryptor) pliku:

FILE *plik;

Otwarcie pliku:

plik = fopen(nazwa_pliku, tryb_otwarcia);

Wybrane tryby otwarcia pliku:

”r” - odczyt

”w” - zapis (wyczyszczenie/utworzenie pliku)

”r+” - odczyt z zapisem

”w+” - zapis z odczytem

”rb” - odczyt w trybie binarnym

”wb” - zapis w trybie binarnym

Gdy plik nie jest już potrzebny, należy go zamknąć: fclose(plik);

Odczyt i zapis pojedynczych znaków Odczyt jednego (kolejnego) znaku z pliku:

int znak = fgetc(plik);

Jeżeli osiągnięto koniec pliku, funkcja zwraca stałą EOF: if(znak == EOF) puts(”Koniec pliku”);

Zapis jednego znaku do pliku:

fputc(znak, plik);

Odczyt i zapis wierszy tekstu Wczytanie jednego wiersza z pliku tekstowego razem ze znakiem końca linii. Funkcja automatycznie dodaje znak 0 na koniec wczytanego ciągu. Drugi parametr to długość tablicy na znaki (maksymalna długość wczytanego ciągu + 1):

char tekst[32];

fgets(tekst, 32, plik);

Zapis jednego wiersza do pliku, z automatycznym dopisaniem znaku końca linii:

char tekst[] = ”Ala ma kota I psa”;

fputs(tekst, plik);

Odczyt i zapis tekstu z formatowaniem Funkcje fprintf (zapis) i fscanf (odczyt) formatują tekst zgodnie z podanym wzorcem, analogicznie do funkcji printf i scanf: fprintf(plik, ”Wartości x=%d y=%d\n”, x, y); fscanf(plik, ”%d”, &n);

Odczyt i zapis bloków danych Do odczytu i zapisu bloków danych z/do plików binarnych zaleca się zastosować jedną z poniższych funkcji:

x = fread(wsk, size, nobj, plik);

x = fwrite(wsk, size, nobj, plik);

gdzie:

●

wsk – wskaźnik na miejsce w pamięci (bufor danych);

●

size – rozmiar jednego bloku danych;

●

nobj – liczba bloków danych do odczytania/zapisania;

●

plik – uchwyt pliku;

●

x – liczba faktycznie odczytanych/zapisanych bloków danych (do kontroli błędów).

Faktycznie odczytana/zapisania ilość danych to zawsze size*nobj bajtów!

Zmiana pozycji w pliku

Odczyt bieżącego położenia wskaźnika odczytu/zapisu w pliku: off_t poz = ftell(plik);

Zmiana położenia wskaźnika odczytu/zapisu pliku: fseek(plik, offset, origin);

gdzie:

offset – przesunięcie (argument typu off_t); origin – względem czego liczone jest przesunięcie:

●

SEEK_SET – od początku pliku (pierwszy bajt ma indeks 0);

●

SEEK_CUR – względem aktualnej pozycji pliku;

●

SEEK_END – względem końca pliku.

Obsługa błędów związanych z plikami Funkcja sygnalizująca wystąpienie błędu – po wystąpieniu jakiegoś błędu związanego z obsługą plików zwraca wartość różną od zera: ferror();

Funkcja sygnalizująca koniec pliku – wtedy zwraca wartość różną od zera:

feof(plik);

Przykład:

int z;

while(!feof(plik)) {

z = fgetc(plik);

putchar(z);

}

Document Outline

  • Slajd 1
  • Slajd 2
  • Slajd 3
  • Slajd 4
  • Slajd 5
  • Slajd 6
  • Slajd 7
  • Slajd 8
  • Slajd 9
  • Slajd 10
  • Slajd 11
  • Slajd 12
  • Slajd 13
  • Slajd 14
  • Slajd 15
  • Slajd 16
  • Slajd 17
  • Slajd 18
  • Slajd 19
  • Slajd 20
  • Slajd 21
  • Slajd 22
  • Slajd 23