C/Zmienne

Z Wikibooks, biblioteki wolnych podręczników.
< C

Procesor komputera stworzony jest tak, aby przetwarzał dane, znajdujące się w pamięci komputera. Z punktu widzenia programu napisanego w języku C (który jak wiadomo jest językiem niskiego poziomu) dane umieszczane są w postaci tzw. zmiennych, stałych i literałów. Zmienne ułatwiają programiście pisanie programu. Dzięki nim programista nie musi się przejmować gdzie w pamięci owe zmienne się znajdują, tzn. nie operuje fizycznymi adresami pamięci, jak np. 0x14613467, tylko prostą do zapamiętania nazwą zmiennej.

Koncepcje C 1999 ISO

Czym są zmienne?[edytuj]

Zmienna jest to pewien fragment pamięci o ustalonym rozmiarze, który posiada własny identyfikator (nazwę) oraz może przechowywać pewną wartość, zależną od typu zmiennej.


Deklaracja, definicja zmiennej[1]

Typ zmiennej[edytuj]

Typ zmiennej[2]

Typy wg złożoności

Deklaracja zmiennych[edytuj]

Aby móc skorzystać ze zmiennej należy ją przed użyciem zadeklarować, to znaczy poinformować kompilator, jak zmienna będzie się nazywać i jaki typ ma mieć. Zmienne deklaruje się w sposób następujący:

typ nazwa_zmiennej;

Oto deklaracja zmiennej o nazwie "wiek" typu "int" czyli liczby całkowitej:

int wiek;

Zmiennej w momencie zadeklarowania można od razu przypisać wartość:

int wiek = 17;
{
   int wiek = 17;
   printf("%d\n", wiek);
   int kopia_wieku; /* tu stary kompilator C zgłosi błąd - deklaracja występuje po instrukcji (printf). */
   kopia_wieku = wiek;
}

Według nowszych standardów (C99) możliwe jest deklarowanie zmiennej w dowolnym miejscu programu (podobnie jak w języku C++), ale wtedy musimy pamiętać, aby zadeklarować zmienną przed jej użyciem. To znaczy, że taki kod jest niepoprawny:

{
   printf ("Przeliczam wiek...\n");
   printf ("Mam %d lat\n", wiek);
   int wiek = 17; /* deklaracja po użyciu - kompilator nigdy tego nie dopuści */
}

Należy go zapisać tak:

{
   printf ("Przeliczam wiek...\n");
   int wiek = 17; /* deklaracja w środku bloku - dopuszczalna w C99 */
   printf ("Mam %d lat\n", wiek);
}


Jak czytać deklarację ?[edytuj]

  • zasada spirali prawoskrętnej ( ang. The Clockwise/Spiral Rule)[3]
  • zasady wg Steve Friedl'a[4]
  • użyć programu cdecl: konwersja z c do języka angielskiego i w odwrotnym kierunku

Nazwa zmiennej[edytuj]

Zasady nazywania zmiennych (ang. Rules for Constructing Variable Names in C Language) [5]

  • zestaw dopuszczalnych znaków
  • pierwszy znak : litera lub podkreślenie ( nie zalecane z uwagi na używanie ich w nazwach zmiennych systemowych)[6]
  • nie używamy słów kluczowych ( już są użyte ). Uwaga: po zmianie wielkości liter będą dopuszczalne
  • wielkość liter odróżnia nazwy ( ang. case sensitive)
  • długość nazwy
    • do pierwszych 8 znaków
    • do pierwszych 31 znaków
    • niektóre kompilatory/OS pozwalają na użycie do 247 znaków[7]

Przykłady niedopuszczalnych nazw:[8][9]

  1x  // zaczyna się od cyfry
  char // słowo zarezerwowane ( ang. reserved word ) 
  x+y //  znak specjalny
  addition of program // spacji używać nie wolno
  

Cel i zasady nadawania nazw:[10]

  • Wybierz słowo mające znaczenie (podaj kontekst): jednoznacznie i precyzyjnie opisywać koncept który nazywają[11]
  • Unikaj nazw ogólnych (takich jak tmp)
  • nazwa zmiennej nie może być taka sama jak słowo kluczowe języka C oraz jak nazwa innej zmiennej, która została wcześniej zdefiniowana w programie[12]
  • Dołącz dodatkowe informacje do nazwy (użyj sufiksu lub prefiksu)
  • Dołącz dodatkowe informacje do nazwy (użyj sufiksu lub prefiksu), zobacz notacja węgierska[13]
  • Nie rób zbyt długich ani zbyt krótkich imion
  • Używaj spójnego formatowania

Zasięg zmiennej[edytuj]

Zmienne mogą być dostępne dla wszystkich funkcji programu - nazywamy je wtedy zmiennymi globalnymi. Deklaruje się je przed wszystkimi funkcjami programu:

#include <stdio.h>

int a,b; /* nasze zmienne globalne */

void func1 ()
{
 /* instrukcje */
 a=3;
 /* dalsze instrukcje */
}
 
int main ()
{
 b=3;
 a=2;
 return 0;
}

Specyfikacja języka C mówi, że zmienne globalne, jeśli programista nie przypisze im innej wartości podczas definiowania, są inicjalizowane wartością 0.

Zmienne, które funkcja deklaruje do "własnych potrzeb" nazywamy zmiennymi lokalnymi. Nasuwa się pytanie: "czy będzie błędem nazwanie tą samą nazwą zmiennej globalnej i lokalnej?". Otóż odpowiedź może być zaskakująca: nie. Natomiast w danej funkcji da się używać tylko jej zmiennej lokalnej. Tej konstrukcji należy, z wiadomych względów, unikać.

int a=1; /* zmienna globalna */ 

int main()
{
 int a=2;         /* to już zmienna lokalna */
 printf("%d", a); /* wypisze 2 */
}

Czas życia[edytuj]

Czas życia to czas od momentu przydzielenia dla zmiennej miejsca w pamięci (stworzenie obiektu) do momentu zwolnienia miejsca w pamięci (likwidacja obiektu).

Zakres ważności to część programu, w której nazwa znana jest kompilatorowi.

main()
{
 int a = 10;
 {                            /* otwarcie lokalnego bloku */
   int b = 10;
   printf("%d %d", a, b);
 }                            /* zamknięcie lokalnego bloku, zmienna b jest usuwana */

 printf("%d %d", a, b);       /* BŁĄD: b juz nie istnieje */
}                               /* tu usuwana jest zmienna a */

Zdefiniowaliśmy dwie zmienne typu int. Zarówno a i b istnieją przez cały program (czas życia). Nazwa zmiennej a jest znana kompilatorowi przez cały program. Nazwa zmiennej b jest znana tylko w lokalnym bloku, dlatego nastąpi błąd w ostatniej instrukcji.

Możemy świadomie ograniczyć ważność zmiennej do kilku linijek programu (tak jak robiliśmy wyżej) tworząc blok. Nazwa zmiennej jest znana tylko w tym bloku.

{
  ...
}

Stałe[edytuj]

Stała, różni się od zmiennej tylko tym, że nie można jej przypisać innej wartości w trakcie działania programu. Wartość stałej ustala się w kodzie programu i nigdy ona nie ulega zmianie.

W przeciwieństwie do języka C++, w C stała to cały czas zmienna, której kompilator pilnuje, by nie zmieniła się.

Stałą deklaruje się:

  • z użyciem słowa kluczowego const
  • dyrektywy preprocesora #define

Użycie stałej zapobiega używaniu magicznych liczb ( ang. Magic number or Unnamed numerical constants)

const[edytuj]

const typ nazwa_stałej=wartość;

Dobrze jest używać stałych w programie, ponieważ unikniemy wtedy przypadkowych pomyłek a kompilator może często zoptymalizować ich użycie (np. od razu podstawiając ich wartość do kodu).

const int WARTOSC_POCZATKOWA=5;
int i=WARTOSC_POCZATKOWA;
WARTOSC_POCZATKOWA=4;  /* tu kompilator zaprotestuje */
int j=WARTOSC_POCZATKOWA;

Przykład pokazuje dobry zwyczaj programistyczny, jakim jest zastępowanie umieszczonych na stałe w kodzie liczb stałymi. W ten sposób będziemy mieli większą kontrolę nad kodem - stałe umieszczone w jednym miejscu można łatwo modyfikować, zamiast szukać po całym kodzie liczb, które chcemy zmienić.

Nie mamy jednak pełnej gwarancji, że stała będzie miała tę samą wartość przez cały czas wykonania programu, możliwe jest bowiem dostanie się do wartości stałej (miejsca jej przechowywania w pamięci) pośrednio - za pomocą wskaźników. Można zatem dojść do wniosku, że słowo kluczowe const służy tylko do poinformowania kompilatora, aby ten nie zezwalał na jawną zmianę wartości stałej. Z drugiej strony, zgodnie ze standardem, próba modyfikacji wartości stałej ma niezdefiniowane działanie (tzw. undefined behaviour) i w związku z tym może się powieść lub nie, ale może też spowodować jakieś subtelne zmiany, które w efekcie spowodują, że program będzie źle działał.

define[edytuj]

Podobnie do zdefiniowania stałej możemy użyć dyrektywy preprocesora #define (opisanej w dalszej części podręcznika). Tak zdefiniowaną stałą nazywamy stałą symboliczną. W przeciwieństwie do stałej zadeklarowanej z użyciem słowa const stała zdefiniowana przy użyciu #define jest zastępowana daną wartością w każdym miejscu, gdzie występuje, dlatego też może być używana w miejscach, gdzie "normalna" stała nie mogłaby dobrze spełnić swej roli.

Literały[edytuj]

Literały[14], czyli stałe dosłowne.

Zawsze w programie, w którym określasz wartość jawnie zamiast odnosić się do zmiennej lub innej formy danych, ta wartość jest określana jako literał.

Literały mogą przybierać formę zdefiniowaną przez ich typ :

  • całkowity
  • zmiennopozycyjny
  • znakowy
  • napisowy
  • złożony[15]
int ilosc = 23; // 23 to literał calkowity
double wysokosc = 88.2; // 88.2 to literał zmiennopozycyjny
char znak = 'c'; // 'c' jest literałem znakowym
string napis = "Napis"; // "Napis" to literał napisowy
int *p = (int []){2, 4, 6}; // literał złożony

Można użyć notacji szesnastkowej (szesnastkowej), aby bezpośrednio wstawić dane do zmiennej niezależnie od jej typu.

Podstawowe typy zmiennych[edytuj]

Każdy program w C operuje na zmiennych - wydzielonych w pamięci komputera obszarach, które mogą reprezentować obiekty nam znane, takie jak liczby, znaki, czy też bardziej złożone obiekty. Jednak dla komputera każdy obszar w pamięci jest taki sam - to ciąg zer i jedynek, w takiej postaci zupełnie nieprzydatny dla programisty i użytkownika. Podczas pisania programu musimy wskazać, w jaki sposób ten ciąg ma być interpretowany.

Typ zmiennej wskazuje właśnie sposób, w jaki pamięć, w której znajduje się zmienna będzie wykorzystywana. Określając go przekazuje się kompilatorowi informację, ile pamięci trzeba zarezerwować dla zmiennej, a także w jaki sposób wykonywać na niej operacje.

Każda zmienna musi mieć określony swój typ w miejscu deklaracji i tego typu nie może już zmienić. Lecz co jeśli mamy zmienną jednego typu, ale potrzebujemy w pewnym miejscu programu innego typu danych? W takim wypadku stosujemy konwersję (rzutowanie) jednej zmiennej na inną zmienną. Rzutowanie zostanie opisane później, w rozdziale Operatory.



W języku C wyróżniamy następujące typy zmiennych ( wg wielkości ) :

  • 4 podstawowe :
    • char - jednobajtowe liczby całkowite, służy do przechowywania znaków;
    • int- typ całkowity, o długości domyślnej dla danej architektury komputera;
    • float - typ zmiennopozycyjny (zwany również zmiennoprzecinkowym), reprezentujący liczby rzeczywiste (4 bajty); Są dokładnie opisane w IEEE 754.
    • double - typ zmiennopozycyjny podwójnej precyzji (8 bajtów);
  • dodatkowe :
    • typ logiczny : bool (tylko C99) (wymaga dołączenia stdbool.h) - typ logiczny
    • typy złożone


Wg lokalizacji definicji typy dzielimy na :

  • wbudowane, które zna kompilator; są one w nim bezpośrednio "zaszyte"
  • zdefiniowane przez użytkownika typy danych. Należy je kompilatorowi opisać. Więcej informacji znajduje się w rozdziale Typy złożone.

Wg zastosowania typy możemy podzielić na :


Rozmiar zmiennych można sprawdzić za pomocą prostego programu


Pojęcia związane z typami:[16]

  • rodzaje typów
  • grupy typów
  • zgodność
  • konwersje
  • rozmiar



int[edytuj]

Ten typ przeznaczony jest do liczb całkowitych. Liczby te możemy zapisać na kilka sposobów:

  • System dziesiętny
12 ; 13 ; 45 ; 35 itd
  • System ósemkowy (oktalny)
010    czyli 8
016    czyli 8 + 6 = 14
018    BŁĄD

System ten operuje na cyfrach od 0 do 7. Tak wiec 8 jest niedozwolona. Jeżeli chcemy użyć takiego zapisu musimy zacząć liczbę od 0.

  • System szesnastkowy (heksadecymalny)
0x10   czyli 1*16 + 0 = 16
0x12   czyli 1*16 + 2 = 18
0xff   czyli 15*16 + 15 = 255

W tym systemie możliwe cyfry to 0...9 i dodatkowo a, b, c, d, e, f, które oznaczają 10, 11, 12, 13, 14, 15. Aby użyć takiego systemu musimy poprzedzić liczbę ciągiem 0x. Wielkość znaków w takich literałach nie ma znaczenia.

W pliku inttypes.h są (od C99) zdefiniowane makra dla liczb całkowitych o stałej szerokości ( ang. Fixed width integer types ) [17]. Podstawowe typy:

  • int8_t
  • int16_t
  • int32_t
  • int64_t
  • uintptr_t = typ liczby całkowitej bez znaku, który może pomieścić wskaźnik[18]

Użycie typów o stałej szerokości zwiększa przenośność programów[19]

Zobacz:

float[edytuj]

Ten typ oznacza liczby zmiennoprzecinkowe czyli ułamki. Istnieją dwa sposoby zapisu:

  • System dziesiętny
  3.14 ; 45.644 ; 23.54 ; 3.21 itd
  • System "naukowy" - wykładniczy
  pek = p*10^k = p*pow(10.0, k) 

przykłady:

  6e2 czyli 6 * 102 czyli 600
  1.5e3 czyli 1.5 * 103 czyli 1500
  3.4e-3 czyli 3.4 * 10(-3) czyli 0.0034

Należy wziąć pod uwagę, że reprezentacja liczb rzeczywistych w komputerze jest niedoskonała i możemy otrzymywać wyniki o zauważalnej niedokładności.[20]

double[edytuj]

Double - czyli "podwójny" - oznacza liczby zmiennoprzecinkowe podwójnej precyzji. Oznacza to, że liczba taka zajmuje zazwyczaj w pamięci dwa razy więcej miejsca niż float (np. 64 bity wobec 32 dla float), ale ma też dwa razy wyższą dokładność.

Domyślnie ułamki wpisane w kodzie są typu double. Możemy to zmienić dodając na końcu literę "f":

  1.5f   (float)
  1.5    (double)


Specjalne wartości[edytuj]

Można[21] wyświetlić wewnętrzną reprezentację ( binarną i 16-ową) wartości specjalnych[22] ( dla porównania kilka niespecjalnych):

0.5:
0 01111111110 0000000000000000000000000000000000000000000000000000
0 3FE 0

0.1:
0 01111111011 1001100110011001100110011001100110011001100110011010
0 3FB 999999999999A

0.0:
0 00000000000 0000000000000000000000000000000000000000000000000000
0 0 0

NaN:
1 11111111111 1000000000000000000000000000000000000000000000000000
1 7FF 8000000000000

+infinity:
0 11111111111 0000000000000000000000000000000000000000000000000000
0 7FF 0

2^-1074:
0 00000000000 0000000000000000000000000000000000000000000000000001
0 0 1

char[edytuj]

Jest to typ znakowy, umożliwiający zapis znaków ASCII. Może też być traktowany jako liczba z zakresu 0..255. Znaki zapisujemy w pojedynczych cudzysłowach (czasami nazywanymi apostrofami), by odróżnić je od łańcuchów tekstowych (pisanych w podwójnych cudzysłowach).

   'a' ; '7' ; '!' ; '$'

Pojedynczy cudzysłów ' zapisujemy tak: '\'' a null (czyli zero, które między innymi kończy napisy) tak: '\0'. Więcej znaków specjalnych.

Warto zauważyć, że typ char to zwykły typ liczbowy i można go używać tak samo jak typu int (zazwyczaj ma jednak mniejszy zakres). Co więcej literały znakowe (np. 'a') są traktowane jako liczby i w języku C są typu int (w języku C++ są typu char).

Program[23] drukuje znaki drukowalne ASCII:

// https://en.cppreference.com/w/c/language/ascii
// printtable ASCII
#include <stdio.h>
 
int main(void)
{
    puts("Printable ASCII:");
    for (int i = 32; i < 127; ++i) {
        putchar(i);
        putchar(i % 16 == 15 ? '\n' : ' ');
    }
}


Wynik:

Printable ASCII:
  ! " # $ % & ' ( ) * + , - . /
0 1 2 3 4 5 6 7 8 9 : ; < = > ?
@ A B C D E F G H I J K L M N O
P Q R S T U V W X Y Z [ \ ] ^ _
` a b c d e f g h i j k l m n o
p q r s t u v w x y z { | } ~


Wewnętrzna reprezentacja znaku:[24]

  printf( "%c = %hhu\n", c, ( unsigned char )c );

void[edytuj]

Słowa kluczowego void można w określonych sytuacjach użyć tam, gdzie oczekiwana jest nazwa typu. void nie jest właściwym typem, bo nie można utworzyć zmiennej takiego typu; jest to "pusty" typ (ang. void znaczy "pusty"). Typ void przydaje się do zaznaczania, że funkcja nie zwraca żadnej wartości lub że nie przyjmuje żadnych parametrów (więcej o tym w rozdziale Funkcje). Można też tworzyć zmienne będące typu "wskaźnik na void"

Specyfikatory[edytuj]

Specyfikatory to słowa kluczowe, które postawione przy typie danych zmieniają jego znaczenie.

signed i unsigned[edytuj]

Na początku zastanówmy się, jak komputer może przechować liczbę ujemną. Otóż w przypadku przechowywania liczb ujemnych musimy w zmiennej przechować jeszcze jej znak. Jak wiadomo, zmienna składa się z szeregu bitów. W przypadku użycia zmiennej pierwszy bit z lewej strony (nazywany także bitem najbardziej znaczącym) przechowuje znak liczby. Efektem tego jest spadek "pojemności" zmiennej, czyli zmniejszenie największej wartości, którą możemy przechować w zmiennej.

Signed oznacza liczbę ze znakiem, unsigned - bez znaku (nieujemną). Mogą być zastosowane do typów: char i int i łączone ze specyfikatorami short i long (gdy ma to sens).

Jeśli przy signed lub unsigned nie napiszemy, o jaki typ nam chodzi, kompilator przyjmie wartość domyślną czyli int.

Przykładowo dla zmiennej char(zajmującej 8 bitów zapisanej w formacie uzupełnień do dwóch) wygląda to tak:

signed char a;      /* zmienna a przyjmuje wartości od -128 do 127 */
unsigned char b;    /* zmienna b przyjmuje wartości od 0 do 255    */
unsigned short c;
unsigned long int d;

Jeżeli nie podamy żadnego ze specyfikatora wtedy liczba jest domyślnie przyjmowana jako signed (nie dotyczy to typu char, dla którego jest to zależne od kompilatora).

signed int i = 0;
// jest równoznaczne z:
int i = 0;

Liczby bez znaku pozwalają nam zapisać większe liczby przy tej samej wielkości zmiennej - ale trzeba uważać, by nie zejść z nimi poniżej zera - wtedy "przewijają" się na sam koniec zakresu, co może powodować trudne do wykrycia błędy w programach.

size_t[edytuj]

Typ size_t jest zdefiniowany w nagłówku stddef.h[25][26] jako alias do liczby całkowitej bez znaku


typedef unsigned int size_t;

Użycie size_t może poprawić przenośność, wydajność i czytelność kodu.[27]

Możemy to sprawdzić :[28]

echo | gcc -E -xc -include 'stddef.h' - | grep size_t

przykładowy wynik :

typedef long unsigned int size_t;

short i long[edytuj]

Short i long są wskazówkami dla kompilatora, by zarezerwował dla danego typu mniej (odpowiednio — więcej) pamięci. Mogą być zastosowane do dwóch typów: int i double (tylko long), mając różne znaczenie.

Jeśli przy short lub long nie napiszemy, o jaki typ nam chodzi, kompilator przyjmie wartość domyślną czyli int.

Należy pamiętać, że to jedynie życzenie wobec kompilatora - w wielu kompilatorach typy int i long int mają ten sam rozmiar. Standard języka C nakłada jedynie na kompilatory następujące ograniczenia:

int - nie może być krótszy niż 16 bitów;
int - musi być dłuższy lub równy short a nie może być dłuższy niż long;
short int - nie może być krótszy niż 16 bitów;
long int - nie może być krótszy niż 32 bity;

Zazwyczaj typ int jest typem danych o długości odpowiadającej wielkości rejestrów procesora, czyli na procesorze szesnastobitowym ma 16 bitów, na trzydziestodwubitowym - 32 itd.[29] Z tego powodu, jeśli to tylko możliwe, do reprezentacji liczb całkowitych preferowane jest użycie typu int bez żadnych specyfikatorów rozmiaru.

Modyfikatory[edytuj]

volatile[edytuj]

volatile znaczy ulotny. Oznacza to, że kompilator wyłączy dla takiej zmiennej optymalizacje typu zastąpienia przez stałą lub zawartość rejestru, za to wygeneruje kod, który będzie odwoływał się zawsze do komórek pamięci danego obiektu. Zapobiegnie to błędowi, gdy obiekt zostaje zmieniony przez część programu, która nie ma zauważalnego dla kompilatora związku z danym fragmentem kodu lub nawet przez zupełnie inny proces.

volatile float liczba1;
float liczba2;
{ 
 printf ("%f\n%f\n", liczba1, liczba2);
 /* instrukcje nie związane ze zmiennymi */ 
 printf ("%f\n%f", liczba1, liczba2);
}

Jeżeli zmienne liczba1 i liczba2 zmienią się niezauważalnie dla kompilatora to odczytując:

  • liczba1 - nastąpi odwołanie do komórek pamięci. Kompilator pobierze nową wartość zmiennej.
  • liczba2 - kompilator może wypisać poprzednią wartość, którą przechowywał w rejestrze.

Modyfikator volatile jest rzadko stosowany i przydaje się w wąskich zastosowaniach, jak współbieżność i współdzielenie zasobów oraz przerwania systemowe. Często jest stosowany przy tworzeniu programów na mikrokontrolery. Kompilatory często tak optymalizują kod, aby wszystkie operacje wykonywały się w rejestrach, przez co wartość zmiennej w pamięci może być przez dłuższy czas nieuaktualniana. Zastosowanie volatile zmusi kompilator do każdorazowego odwołania do pamięci w przypadku operowania na zmiennych.

register[edytuj]

Jeżeli utworzymy zmienną, której będziemy używać w swoim programie bardzo często, możemy wykorzystać modyfikator register. Kompilator może wtedy umieścić zmienną w rejestrze, do którego ma szybki dostęp, co przyśpieszy odwołania do tej zmiennej

register int liczba;

W nowoczesnych kompilatorach ten modyfikator praktycznie nie ma wpływu na program. Optymalizator sam decyduje czy i co należy umieścić w rejestrze. Nie mamy żadnej gwarancji, że zmienna tak zadeklarowana rzeczywiście się tam znajdzie, chociaż dostęp do niej może zostać przyspieszony w inny sposób. Raczej powinno się unikać tego typu konstrukcji w programie.

static[edytuj]

Pozwala na zdefiniowanie zmiennej statycznej. "Statyczność" polega na zachowaniu wartości pomiędzy kolejnymi definicjami tej samej zmiennej. Jest to przede wszystkim przydatne w funkcjach. Gdy zdefiniujemy zmienną w ciele funkcji, to zmienna ta będzie od nowa definiowana wraz z domyślną wartością (jeżeli taką podano). W wypadku zmiennej określonej jako statyczna, jej wartość się nie zmieni przy ponownym wywołaniu funkcji. Na przykład:

void dodaj(int liczba)
{
 int zmienna = 0;     /* bez static*/
 zmienna = zmienna + liczba;
 printf ("Wartosc zmiennej %d\n", zmienna);
}

Gdy wywołamy tę funkcję np. 3 razy w ten sposób:

 dodaj(3);
 dodaj(5);
 dodaj(4);

to ujrzymy na ekranie:

Wartosc zmiennej 3
Wartosc zmiennej 5
Wartosc zmiennej 4

jeżeli jednak deklarację zmiennej zmienimy na static int zmienna = 0, to wartość zmiennej zostanie zachowana i po ponownym wykonaniu funkcji powinnyśmy ujrzeć:

Wartosc zmiennej 3
Wartosc zmiennej 8
Wartosc zmiennej 12


Zupełnie co innego oznacza static zastosowane dla zmiennej globalnej. Jest ona wtedy widoczna tylko w jednym pliku. Zobacz też: rozdział Biblioteki.

extern[edytuj]

Przez extern oznacza się zmienne globalne zadeklarowane w innych plikach - informujemy w ten sposób kompilator, żeby nie szukał jej w aktualnym pliku. Zobacz też: rozdział Biblioteki.

auto[edytuj]

Zupełnym archaizmem jest modyfikator auto, który oznacza tyle, że zmienna jest lokalna. Ponieważ zmienna zadeklarowana w dowolnym bloku zawsze jest lokalna, modyfikator ten nie ma obecnie żadnego zastosowania praktycznego. auto jest spadkiem po wcześniejszych językach programowania, na których oparty jest C (np. B).

Konwersje typów[edytuj]

Konwersje typów zmiennych :[30][31] [32]

Przypisy

  1. stackoverflow question: what-is-the-difference-between-a-definition-and-a-declaration
  2. the C data model by Jens Gustedt
  3. The ``Clockwise/Spiral Rule By David Anderson
  4. Reading C type declarations by Steve Friedl
  5. c4learn c-variable-nameing-rules
  6. Recommended C Style and Coding Standards
  7. Recommended C Style and Coding Standards
  8. about c by weebly
  9. Naming guidelines for professional programmers Copyright ©2017 by Peter Hilton and Felienne Hermans
  10. how-to-better-name-your-functions-and-variables by Friskovec Miha
  11. Nazwy zmiennych, notacje i konwencje nazewnicze - Mateusz Skalski
  12. Kurs języka C. Autor artykułu: mgr Jerzy Wałaszek
  13. Hungarian Notation by Charles Simonyi Microsoft Corporation Reprinted November 1999
  14. Literał w wikipedii
  15. cppreference: c language: compound literal
  16. cpp reference : c language - type
  17. cppreference: c types integer
  18. cppreference: integer c types
  19. Fixed-width_integer_types in english wiki
  20. The Floating-Point Guide
  21. | Displaying the Raw Fields of a Floating-Point Number By Rick Regan (Published May 20th, 2009)
  22. wartości specjalne liczbn zmiennoprzecinkowych w wiki[edii
  23. cppreference : ascii
  24. stackoverflow question: how-to-find-the-length-of-a-character
  25. opis size_t w cpp0x
  26. About size_t and ptrdiff_t, Andrey Karpov
  27. Why size_t matters, Dan Saks
  28. stackoverflow question : what-is-size-t-in-c
  29. Wiąże się to z pewnymi uwarunkowaniami historycznymi. Podręcznik do języka C duetu K&R zakładał, że typ int miał się odnosić do typowej dla danego procesora długości liczby całkowitej. Natomiast jeśli procesor mógł obsługiwać typy dłuższe lub krótsze stosownego znaczenia nabierały modyfikatory short i long. Dobrym przykładem może być architektura i386, która umożliwia obliczenia na liczbach 16-bitowych. Dlatego też modyfikator short powoduje skrócenie zmiennej do 16 bitów.
  30. wikipedia : Konwersja typu
  31. C++ and simple type conversion - University of CambridgeDepartment of Engineering
  32. frama-c : Overflow-float-integer