Wstęp do programowania w języku C/Wskaźniki: Różnice pomiędzy wersjami
m Zastępowanie tekstu – „,...,” na „,\ldots,” |
|||
Linia 173: | Linia 173: | ||
for ( i = 1; i < n; i++) | for ( i = 1; i < n; i++) | ||
/* Nzm.: | /* Nzm.: | ||
*max = MAX(a[0], | *max = MAX(a[0],\ldots,a[i-1]), | ||
*min = MIN(a[0], | *min = MIN(a[0],\ldots,a[i-1]). | ||
*/ | */ | ||
if ( a[i] > *max ) | if ( a[i] > *max ) | ||
Linia 240: | Linia 240: | ||
for ( i = 2; i < n-1; i += 2){ | for ( i = 2; i < n-1; i += 2){ | ||
/* Nzm.: | /* Nzm.: | ||
*max = MAX(a[0], | *max = MAX(a[0],\ldots,a[i-1]), | ||
*min = MIN(a[0], | *min = MIN(a[0],\ldots,a[i-1]). | ||
*/ | */ | ||
Aktualna wersja na dzień 21:57, 15 wrz 2023
Wprowadzenie
Z punktu widzenia programisty pamięć komputera to jednowymiarowa tablica bytów. Każda zmienna w programie zajmuje jeden lub więcej bytów w pamięci.
- Adres (indeks) pierwszego z tych bytów jest adresem zmiennej.
- Wskaźnik (ang. pointer) to adres w pamięci.
- Zmienna wskaźnikowa to zmienna, na której przechowuje się adresy.
Oto przykłady deklaracji zmiennych wskaźnikowych.
int *p_i;
char *p_c;
double *p_d;
Wartościami zmiennej p_i są wskaźniki (adresy) do obiektów typu int. Wartościami zmiennej p_c są wskaźniki (adresy) do obiektów typu char. Wartościami zmiennej p_d są wskaźniki (adresy) do obiektów typu double.
Podstawowymi operatorami wykorzystywanymi w działaniach na zmiennych wskaźnikowych są operator pobrania adresu & i odwołania do zmiennej wskazywanej *. Jeśli x jest zmienną, to &x jest adresem tej zmiennej. Operator * umożliwia dostęp do obiektu wskazywanego przez wskaźnik.
int i, *p; /* p na nic nie wskazuje */
...
p = &i; /* p wskazuje na i*/
i = 5;
printf("%d\n", *p);
/* zostanie wypisana wartosc zmiennej
wskazywanej przez p, czyli 5 */
*p = 6; /* wartoscia i jest teraz 6 */
Tak długo jak p wskazuje na i, *p jest synonimem i.
Operator * jest operatorem odwrotnym" do &, tzn.:
j = *&i;
jest równowżne
j = i};
Ostrzeżenie: Nigdy nie stosuj operatora * do nie zainicjowanej zmiennej wskaźnikowej, w szczególności nie wykonuj przypisania *p = ...; jeżeli p nie jest zainicjalizowana.
Przypisywanie wskaźników
int i, j, *p, *q;
p = &i;
q = p; /* obie zmienne p i q wskazuja na i */
*p = 1;
printf("%d\n",*q); /* wypisuje wartosc zmiennej i, czyli 1 */
*q = 2;
printf("%d\n",*p); /* wypisuje wartosc zmiennej i, czyli 2 */
Przypisanie q = p nie jest tym samym, co *q = *p.
p = &i;
q = &j;
i = 1;
/* p i q wskazuja na rozne zmienne */
*q = *p;
/* wartoscia j jest teraz 1 */
Zastosowanie wskaźników do przekazywania parametrów
Przekazywanie wskaźników do zmiennych jako parametrów funkcji umożliwia zmienianie wartości tych zmiennych podczas wykonywania funkcji. Oto przykład funkcji dekomponującą liczbę rzeczywistą na część całkowitą i ułamkową.
void dekom(float x, int *czesc_calk, float *czesc_ulamk)
{
*czesc_calk = (int) x;
*czesc_ulamk = x - *czesc_calk;
}
Prototypem funkcji dekomp może być zarówno
void dekom(float x, int *czesc_calk, float *czesc_ulamk);
jak i
void dekom(float, int *, float *);
Oto przykład wywołania funkcji dekom.
...
int i;
float f;
...
dekom(3.14, &i, &f);
/* wartoscia i jest 3,
wartoscia f jest .14 */
Wskaźniki można zwracać jako wartości funkcji:
int *max(int *a, int *b)
{
if (*a > *b)
return a;
else
return b;
}
Oto przykładowe użycie funkcji max:
int *p, x, y;
...
p = max(&x,&y);
Jednoczesne znajdowanie maksimum i minimum w ciągu.
Przedstawimy dwa algorytmy znajdowania maksimum i minimum w ciągu liczb. W pierwszym algorytmie wejściowy ciąg jest przeglądany od lewej do prawej, po jednym elemencie. Aktualnie oglądany element jest porównywany z dotychczasowym maksimum lub minimum, i w razie potrzeby jedna z tych wartości jest aktualizowana. W tym algorytmie, w pesymistycznym przypadku wykonuje się 2n-1 porównań między elementami ciągu wejściowego. W algorytmie drugim zawsze bierzemy dwa kolejne elementy i porównujemy je ze sobą. Następnie większy z nich porównujemy z dotychczasowym maksimum, a mniejszy z dotychczasowym minimum, aktualizując je, gdy jest taka potrzeba. Ta prosta sztuczka pozwala na zredukowanie liczby porównań do co najwyżej .
/*
* Nazwa programu: maxmin1.c
*/
#include <stdio.h>
#define Max_d 100
/* maksymalna dlugosc ciagu wejsciowego */
void max_min(int a[], int n, int *max, int *min);
/* znajduje max i min w tablicy
a[0..n-1] i ich wartosci
zwraca na zmiennych *max i *min
*/
main()
{
int d, najw, najm;
/* d - dlugosc wejsciowego ciagu
najw, najm - najwieksza i najmniejsza
wartosc w ciagu wejsciowym.
*/
int ciag[Max_d]; /* ciag wejsciowy*/
int i;
printf("Dlugosc ciagu wejsciowego (0<.<%d) : ",Max_d);
scanf("%d", &d);
for (i = 0; i < d; i++)
scanf("%d", &ciag[i]);
max_min(ciag, d, &najw, &najm);
printf("Max = %d, Min = %d\n", najw, najm);
return 0;
}
void max_min(int a[], int n, int *max, int *min)
{
int i;
*max = a[0];
*min = a[0];
for ( i = 1; i < n; i++)
/* Nzm.:
*max = MAX(a[0],\ldots,a[i-1]),
*min = MIN(a[0],\ldots,a[i-1]).
*/
if ( a[i] > *max )
*max = a[i];
else if ( a[i] < *min )
*min = a[i];
}
/*
* Nazwa programu: maxmin2.c
*/
#include <stdio.h>
#define Max_d 100
/* maksymalna dlugosc ciagu wejsciowego */
void max_min(int a[], int n, int *max, int *min);
/* znajduje max i min
w tablicy a[0..n-1] i ich wartosci
zwraca na zmiennych *max i *min
*/
main()
{
int d, najw, najm;
/* d - dlugosc wejsciowego ciagu
najw, najm - najwieksza i najmniejsza
wartosc w ciagu wejsciowym.
*/
int ciag[Max_d]; /* ciag wejsciowy*/
int i;
printf("Dlugosc ciagu wejsciowego (0<.<%d) : ",Max_d);
scanf("%d", &d);
for (i = 0; i < d; i++)
scanf("%d", &ciag[i]);
max_min(ciag, d, &najw, &najm);
printf("Max = %d, Min = %d\n", najw, najm);
return 0;
}
void max_min(int a[], int n, int *max, int *min)
{
int i, l_min, l_max;
if ( n == 1 ){
*max = a[0];
*min = a[0];
}
else{
if ( a[0] < a[1] ){
*min = a[0];
*max = a[1];
}
else{
*min = a[1];
*max = a[0];
}
for ( i = 2; i < n-1; i += 2){
/* Nzm.:
*max = MAX(a[0],\ldots,a[i-1]),
*min = MIN(a[0],\ldots,a[i-1]).
*/
if ( a[i] < a[i+1] ){
l_min = a[i];
l_max = a[i+1];
}
else{
l_min = a[i+1];
l_max = a[i];
}
if ( *max < l_max )
*max = l_max;
if ( *min > l_min )
*min = l_min;
}
/* n jest nieparzyste, nalezy jeszcze sprawdzic
ostatni element
*/
if ( i == (n - 1) )
if ( *max < a[i] )
*max = a[i];
else if ( *min > a[i] )
*min = a[i];
}
}