background image

 

 

Programowanie

w języku C

Programowanie

w języku C

© 2012
Grzegorz Łukawski & Maciej Lasota

Politechnika Świętokrzyska w Kielcach

Wskaźniki i obsługa plików

w języku C

background image

 

 

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

Wskaźnik – definicja

background image

 

 

1004

99

Zwykłe zmienne i wskaźniki

0
1
2

1000
1004
1008
1012
1016

ADRES

RAM

int z = 99;
int 

*

w = 

&

z;

background image

 

 

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

Operatory związane ze wskaźnikami

w = 

&

z

z = 

*

w

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

background image

 

 

Zmienne wskaźnikowe

int

 *

wsk

;

// wsk = ??

int

 

x

=1, 

y

=2, 

tabela

[10];

wsk

 = &

x

;

y

 = *

wsk

;

// y = 1

*

wsk

 = 0;

// x = 0

wsk

 = &

tabela

[3];

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

UWAGA!
Wskaźnik zawsze wskazuje na obiekty określonego rodzaju – można to 

zmienić przez rzutowanie. Wskaźnik zawsze na coś wskazuje!

background image

 

 

Operacje na zmiennych wskaźnikowych

*

wsk

 += 100;

printf

(”%d”, *

wsk

);

y

 = *

wsk

 * 10;

x

 = 

tabela

[*

wsk

];

*

wsk

 = *

wsk

 + 88;

(*

wsk

)++;

Operacje na zmiennych wskazywanych przez wskaźniki:

background image

 

 

Operacje przypisania na wskaźnikach:

int

 *

w1

, *

w2

;

int

 

x

 = 30;

w1

 = &

x

;

// *w1 = 30

w2

 = 

w1

;

// *w2 = *w1 = 30

Operacje na zmiennych wskaźnikowych

background image

 

 

void

 dodaj_czas(

int

 *

godz

int

 *

min

int

 

czas

)

{

*

min

 += 

czas

;

if(*

min

 > 59) {

*

godz

 += 1;

*

min

 -= 60;

}

}

Wskaźnikowe argumenty funkcji

background image

 

 

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

Tablice i wskaźniki

int

 

tab

[5];

int

 *

wsk

x

;

wsk

 = &

tab

[0];

x

 = *

wsk

;

// x = tab[0]

x

 = *(

wsk

+1);

// x = tab[1]

Przy  dodawaniu  liczby  do  adresu,  kolejny  element  wyznaczany  jest 

automatycznie  (kompilator  bierze  pod  uwagę  typ  danej  na  którą 
wskazuje dany wskaźnik).

wsk

 = &

tab

[0];

<=>

wsk

 = 

tab

;

background image

 

 

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

Tablice i wskaźniki

*

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

++;

background image

 

 

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

{…}

Tablice i wskaźniki jako parametry funkcji

background image

 

 

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;

(…)

background image

 

 

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!”

);

Wartości początkowe wskaźników

background image

 

 

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??

Wskaźniki znakowe

background image

 

 

Tablica wskaźników

int

 i;

char

 *

imiona

[] = {

”Ania”

”Ala”

”Basia”

};

for(

i

=0;

i

 < 3;

i

++)

puts

(

imiona

[

i

]);

background image

 

 

Tablica wskaźników VS tablica 2-wymiarowa

A B C

0

? ? ?

X Y Z 1 2 3

0

D

0

? ? ? ? ?

A B C

0

X Y Z 1 2 3

0

D

0

char

 

tab

[][] = {…};

char

 *

tab

[] = {…};

background image

 

 

#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

);

Obsługa plików

background image

 

 

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 pojedynczych znaków

background image

 

 

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 wierszy tekstu

background image

 

 

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

);

background image

 

 

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!

Odczyt i zapis bloków danych

background image

 

 

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.

Zmiana pozycji w pliku

background image

 

 

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