Programowanie w C (index)


Programowanie w C (6) - wskaźniki, funkcje standardowe

WSKAŹNIK NULL

Wskaźnik NULL jest zdefiniowany jako wartość wskaźnika nie wskazującego na żadną wartość. Często dla uzyskania wskaźnika NULL przypisuje się zmiennej wskaźnikowej wartość zero. Funkcja sizeof() w ANSI C dla NULL daje 4 bajty.

Wiele funkcji zwracających zmienną wskaźnikową w przypadku niepowodzenia zwraca wskaźnik NULL. Dobrym zwyczajem jest jawne inicjalizowanie zmiennych wskaźnikowych wartością NULL oraz podstawianie wartości NULL zmiennym z nieaktualnymi adresami [np. po zwolnieniu obszaru pamięci funkcją free()].

WSKAŹNIKI KONTRA INDEKSY

Przy założeniu, że obie metody będą zastosowane prawidłowo, indeksowanie nigdy nie będzie bardziej efektywne niż wskaźniki, a wskaźniki czasami będą bardziej efektywne niż indeksy.

Indeksy są łatwiejsze do zrozumienia przez większość ludzi, szczególnie w przypadku tablic wielowymiarowych. Wskaźniki są efektywniejsze od indeksowania w sytuacji, gdy przesuwają się po tablicy o stały krok. Mnożenie (zmiana indeksu razy liczba bajtów) jest wykonywane na etapie kompilacji, a więc w czasie działania programu wykonywane jest mniej instrukcji i program jest szybszy.


/* zerowanie tablicy */
const int N = 10;
int t[N], i, *iptr;

for(i = 0; i < N; ++i) t[i] = 0;       /* indeksy */
for(i = 0; i < N; ++i) *(t+i) = 0;       /* wskaźniki, ale sens jw */
for(iptr = t; iptr < t+N; ++iptr) *iptr = 0; /* wskaźniki */

ZADANIE 6.1

Poprawić program getline wykorzystując wersję wskaźnikową funkcji copy() postaci


/*
* Funkcja przepisuje *source do *dest.
* *dest musi byc dostatecznie duze.
* Tablice znakow sa odebrane jako wskazniki.
*/
void copy(char *dest, char *source) 
{
while ((*dest = *source) != '\0') {
    ++source;
    ++dest;
}
return;
}

ZADANIE 6.2

Poprawić program wektory wykorzystując wskaźnikowe wersje funkcji.


void wczytaj(int *v, int n) 
{ 
for ( ; n > 0; ++v, --n) {
    printf("Podaj kolejny element tablicy: ");
    scanf("%d", v);
}
return;
}

void wypisz(int *v, int n) 
{ 
int i;

for (i = 0; i < n; ++i, ++v)
    printf("v[ %d ] = %d\n", i, *v);
/*    printf("v[ %d ] = %d adres %p\n", i, *v, v);  */
return;
}

int suma(int *v, int n) 
{ 
int s;

for (s = 0; n > 0; ++v, --n)   /* v rosnie, n maleje */
    s += (*v);
return s;
}

int minimum(int *v, int n) 
{ 
int min;

min = *v;
for (--n, ++v; n > 0 ; --n, ++v)   /* v rosnie, n maleje */
    if (*v < min)
        min = *v;
return min;
}

ZADANIE 6.3

Zapoznać się z podstawowymi funkcjami z biblioteki standardowej.


#include <stdio.h>  /* wejscie i wyjscie */

/* Formatowane wyjście */
int printf(const char *format, ...)
int sprintf(char *s, const char *format, ...)
int fprintf(FILE *stream, const char *format, ...)

/* Formatowane wejście */
int scanf(const char *format, ...)
int sscanf(char *s, const char *format, ...)
int fscanf(FILE *stream, const char *format, ...)

/* Wyjście znakowe */
int fputc(int c, FILE *stream)
int putchar(int c)     /* fputc(c, stdout) */

/* Wejście znakowe */
int fgetc(FILE *stream)
int getchar(void)       /* fgetc(stdin) */
char *fgets(char *s, int n, FILE *stream)
int ungetc(int c, FILE *stream)

#include <ctype.h>  /* klasyfikowanie znaków */

int isalnum(int c)
int isalpha(int c)
int iscntrl(int c)   /* znak kontrolny */
int isdigit(int c)   /* cyfra dziesiętna */
int isgraph(int c)    /* znak drukowalny bez odstępu */
int islower(int c)    /* mała litera */
int isprint(int c)   /* znak drukowalny */
int ispunct(int c)  /* znak drukowalny bez odstępu, liter i cyfr */
int isspace(int c)
int isupper(int c)  /* wielka litera */
int isxdigit(int c)   /* cyfra szesnastkowa */

int tolower(int c)
int toupper(int c)

#include <string.h>  /* operacje na tekstach */

char *strcpy(char *s, const char *t)
char *strncpy(char *s, const char *t, size_t n)
char *strcat(char *s, const char *t)
char *strncat(char *s, const char *t, size_t n)
int strcmp(const char *s, const char *t)
int strncmp(const char *s, const char *t, size_t n)
size_t strlen(const char *s)  /* size_t jest obszerniejsze niż int */

#include <stdlib.h>  /* funkcje narzędziowe */

double atof(const char *s)
int atoi(const char *s)
long atol(const char *s)
int rand(void)   /* zwraca int z przedziału [0, RAND_MAX] */
void srand(unsigned int seed)   /* np. srand(time(NULL)); */
void exit(int status)
int system(const char *)   /* np. system("clear"); */
int abs(int n)
long labs(long n)

ZADANIE 6.4

W katalogu napisy poprawić funkcje stringlen() i reverse(), aby odbierały wskaźnik. Stworzyć plik itoa.c.


int stringlen(char *s) 
{
char *p = s;

while (*p != '\0')
    ++p;
return (p-s);
}

/*
* itoa.c
*
* Zamiana liczby calkowitej na znaki w tablicy.
*/

#include "main.h"

void itoa(int n, char *s) 
{
int i, znak;

if ((znak = n) < 0)     /* zanotuj znak liczby */
    n = -n;
i = 0;
do {           /* generuj cyfry w odwrotnym porzadku */
    s[i] = n % 10 + '0';  /* wez nastepna cyfre */
    ++i;
} while ((n /= 10) > 0);      /* usun ja */
if (znak < 0) {
    s[i] = '-';
    ++i;
}
s[i] = '\0';
reverse(s);          /* odwoc kolejnosc cyfr */
return;
}

Poprawić odpowiednio pliki main.c, main.h i Makefile. Skompilować i uruchomić program.

ZADANIE 6.5

W katalogu napisy stworzyć plik itob.c z funkcją

void itob(int n, char *s, int b);
/*
* Zamiana n na znakową reprezentację liczby w systemie o podstawie b.
* Wynik zapisywany do tablicy s.
* Przykład: itob(n, s, 16) - zamiana n na postać szesnastkową.
*/

Poprawić odpowiednio pliki main.c, main.h i Makefile. Skompilować i uruchomić program.

ZADANIE 6.6

Zapoznać się z programami z książki S. Oualline: ARRAY, STR (strcpy, drukowanie napisu), FULL (strcat), LENGTH (fgets, strlen), FULL1, FULL2 (wprowadzanie napisów), DOUBLE (wprowadzanie liczb), TRI (znaleźć błąd), FIB (Fibonacci), TOTAL5W (while), TOTAL5F (for), CENT (znaleźć błąd), SEVEN (znaleźć błąd).


Programowanie w C (index)