Podstawowe typy danych

<lwrm> „nieee, przeciez nikt nie ma tak długiego nazwiska, damy char[25]...”
<lwrm> i przyszła klientka z podwójnym nazwiskiem
<lwrm> od tej pory wołaliśmy na nią „segmentation fault”

[bash#667850]

1. Zbadaj jak zachowuje się Sigma w sytuacji przepełnienia zmiennej całkowitej, przepełnienia zmiennej zmiennoprzecinkowej i niedomiaru zmiennej zmiennoprzecinkowej.

Zastosuj metodę doświadczalną, czyli napisz programy, w których wystąpią te przepełnienia i niedomiary.

Wskazówka: zajrzyj do plików limits.h oraz float.h w których zdefiniowano stałe symboliczne dla wszystkich rozmiarów danych oraz dla innych właściwości komputera i kompilatora. (Są też strony manuala limits.h i float.h.)

2. Napisz program, który prosi o podanie kodu ASCII, a następnie wypisuje znak odpowiadający temu kodowi.

Przykładowa sesja z tym programem może wyglądać tak:

Podaj kod ASCII: 65
A
Podaj kod ASCII: 0x41
A
Podaj kod ASCII: 0101
A
Podaj kod ASCII: 0
znak niedrukowalny

3. Napisz program, który pobiera Twój wiek w latach, a następnie przelicza go na sekundy.

Do sprawdzania czy rok jest jest przestępny skorzystaj z poniższego kodu (K&R, s. 153):

leap = year%4==0 && year%100!=0 || year%400 == 0

4. Napisz program, który pobiera Twoją datę urodzenia a następnie przelicza ile sekund przeżyłeś do momentu uruchomienia tego programu.

5. Calowi odpowiada 2.54 centymetra. Napisz program, który pyta o podanie Twojego wzrostu i przelicza go na cale, jeśli podałeś wzrost w centymetrach, albo przelicza go na centymetry — jeśli podałeś go w calach.

Przykładowa sesja z tym programem może wyglądać tak (dokładność – jedno miejsce po przecinku):

Podaj Twoj wzrost: 190 cm
74.8 in
Podaj Twoj wzrost: 74.8 in
190.0 cm

6. Napisz program wypisujący dziedziny wartości zmiennych typu: char, short, int, long, opatrzonych kwalifikatorami signed oraz unsigned.

Wynik powinien zawierać odpowiednie wartości ze standardowych plików nagłówkowych lub wartości obliczone bezpośrednio przez program.

Niektóre z wartości podanych w limits.h mozna wyliczyć. Na przykład, największą możliwą wartość typu signed char można wyliczyć tak:

(char)((unsigned char) ~0 >> 1))

Najpierw operator dopełnienia jedynkowego ~ zamienia każdy bit wartości zero na jedynkę a jedynkę na zero; następnie wynik jest przekształcany do typu unsigned char; tak otrzymaną wartość przesuwa się w prawo o jedną pozycję, by wyzerować bit znaku; na koniec przekształcamy całość do typu char.

Fragment programu:

#include <stdio.h>
int main()
{
  char c = (char)((unsigned char) ~0 >> 1);
  printf("signed char max: %d\n", c);
  return 0;
}

7. Poniższa funkcja, K&R, ilustruje operacje bitowe:

unsigned getbits(unsigned x, int n, int p) {
  // wycina n bitow z „x” od pozycji p w prawo
  // zerowa pozycja to skrajnie prawa pozycja
  return ((x>>(p-n+1)) & ~(~0<< n));
}

(a) Zrozumieć i przetestować działanie tej funkcji.

Do testowania, należy napisać i wykorzystać dwie funkcje:

unsigned czytajBity()

czytającej z wejścia ciąg zer i jedynek będący zapisem liczby binarnej i zwracającej wartość tej liczby oraz

void drukujBity(unsigned x)

wypisującej wszystkie bity liczby x.

Wskazówki:

unsigned czytajBity() {
  unsigned w=0;
  int c;
  while ((c=getchar())!=EOF && c!='\n'){
    // przesun w o 1 w lewo
    switch (c){
    case '0': // nic nie trzeba robic
    case '1': // wstawic 1 jako skrajny prawy bit
    default : // kazdy inny znak jest bledem - przerwac
    }
  }
  return w;
}

Przy pisaniu funkcji drukujBity można wykorzystać poniższe informacje i drukować w pętli kolejne bity liczby używając putchar('0') lub putchar('1')

Liczba bitów w liczbie typu unsigned:

8*sizeof(unsigned)

j-ty bit licząc od prawej, tj. bit najmniej znaczący ma numer 0:

(x>>j)&01)

(b) Napisać i przetestować funkcję:

unsigned setbit(unsigned x, int p, char b)

która zwraca wartość taką jak x, ale zastępuje p-ty bit bitem 0 jeżeli b jest równe 0 lub bitem 1 jeżeli b jest różne od 0.