Język C Michał Małafiejski

Slides:



Advertisements
Podobne prezentacje
Tablice 1. Deklaracja tablicy
Advertisements

Katarzyna Szafrańska kl. II ti
C++ wykład 2 ( ) Klasy i obiekty.
C++ wykład 4 ( ) Przeciążanie operatorów.
Język C/C++ Funkcje.
Programowanie obiektowe
Wzorce.
Język ANSI C Funkcje Wykład: Programowanie komputerów
Prowadzący: mgr inż. Elżbieta Majka
Kompilator: a) gcc [cc, g++]
Języki programowania C++
PROGRAMOWANIE STRUKTURALNE
Informatyka Stosowana
formatowanie kodu źródłowego
Materiały do zajęć z przedmiotu: Narzędzia i języki programowania Programowanie w języku PASCAL Część 7: Procedury i funkcje © Jan Kaczmarek.
Programowanie imperatywne i język C Copyright, 2004 © Jerzy R. Nawrocki Wprowadzenie.
Programowanie imperatywne i język C
Programowanie imperatywne i język C Copyright, 2005 © Jerzy R. Nawrocki Wstęp.
Programowanie imperatywne i język C Copyright, 2004 © Jerzy R. Nawrocki Wprowadzenie.
Struktury.
Tablice.
1 Dygresja: cztery płyty główne…. 2 Dygresja: osobliwości C /* cos o nieistniejacym typie Boolean */ /* oraz o operatorze przecinkowym */ #include int.
Biblioteki i przestrzenie nazw
Wykład 1: Wskaźniki Podstawy programowania Programowanie w C
Wykład 2 struktura programu elementy języka typy zmienne
Wyrażenia Wyrażenie w Fortranie jest poprawną syntaktycznie kombinacją zmiennych, stałych, operatorów i funkcji. Wyrażenia są jednozdaniowymi przepisami.
Java – programowanie obiektowe
nowe operatory & . (kropka) * operator rzutowy -> , (przecinek)
Podstawy programowania
Podstawy programowania II
Podstawy programowania II Wykład 2: Biblioteka stdio.h Zachodniopomorska Szkoła Biznesu.
Podstawy programowania w języku C i C++
Podstawy programowania
Informatyka I Wykład 5 OPERATORY Priorytety i kolejność obliczeń
Podstawy programowania
Programowanie strukturalne i obiektowe
Podstawy programowania. Język C i C++– podstawy Temat: 1
Podstawy programowania w języku C i C++
© A. Jędryczkowski – 2006 r. © A. Jędryczkowski – 2006 r.
TABLICE C++.
Podstawy programowania
Jerzy F. Kotowski1 Informatyka I Wykład 14 DEKLARATORY.
JAVA c.d.. Instrukcji wyboru SWITCH używamy, jeśli chcemy w zależności od wartości pewnego wyrażenia wykonać jeden z kilku fragmentów kodu. Jest to w.
STEROWANIE Ale nie tylko
Jerzy Kotowski Politechnika Wrocławska
Programowanie strukturalne i obiektowe
Historia Języka C Idea C pochodzi od języka BCPL, opracowanego przez M. Richardsa 1970 – język B stworzony przez K. Thompsona Język C wprowadzono po raz.
Podstawy informatyki 2013/2014
PWSZ Gniezno // codefly 2009 Łukasz Tomczak
Kurs języka C++ – wykład 9 ( )
Podstawy programowania
Podstawy języka Instrukcje - wprowadzenie
Podstawy programowania
Zmienne i typy danych w C#
Kurs języka C++ – wykład 4 ( )
Programowanie proceduralne Podstawy Programowania dla geoinformatyków Wykład 3 Rafał Witkowski, 2015.
Programowanie imperatywne i język C Copyright, 2007 © Jerzy R. Nawrocki Wstęp do.
Seminarium Dyplomowe: Metodyka i Techniki Programowania Autor: Bartłomiej Fornal.
Język C/C++ Instrukcje
Wstęp do programowania Wykład 2 Dane, instrukcje, program.
1 Opisy funkcji Adres strony WWW : html (należy odszukać hyperlink Function Index) (
Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego Matuszyka Podstawy.
K URS JĘZYKA C++ – WYKŁAD 3 ( ) Przenoszenie Składowe statyczne Funkcje wbudowane Argumenty domyślne.
 Formuła to wyrażenie algebraiczne (wzór) określające jakie operacje ma wykonać program na danych. Może ona zawierać liczby, łańcuchy znaków, funkcje,
Programowanie strukturalne i obiektowe Klasa I. Podstawowe pojęcia dotyczące programowania 1. Problem 2. Algorytm 3. Komputer 4. Program komputerowy 5.
Grzegorz Cygan Wstęp do programowania mikrosterowników w języku C
nowe operatory & . (kropka) * operator rzutowy -> , (przecinek)
Przykładowy algorytm geometryczny (geometria płaska)
Założenia projektowe Javy
Język C++ Typy Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego.
Zapis prezentacji:

Michał Małafiejski mima@sphere.pl Język C Michał Małafiejski mima@sphere.pl Nic nie jest tak proste, by nie można było wykonać tego źle Prawo Murphy’ego

Plan wykładu (propozycja) wykład I(6): standard ANSI C, proste programy, podstawowe opcje kompilatora, składnia i semantyka języka C, instrukcje przypisania, bloki instrukcji, instrukcje sterujące (pętle), instrukcje warunkowe wykład II(4): wyrażenia i operatory arytmetyczne, kolejność wykonywania obliczeń w wyrażeniach, typy danych, konwersja typów, definicja struktur wykład III(4): operacje na plikach, formatowane wejście oraz wyjście, funkcje i struktura programu, zasięg nazw, pliki nagłówkowe, preprocesor języka C, kompilacja warunkowa wykład IV(4): wskaźniki i tablice, arytmetyka na adresach, związki tablic i wskaźników, tablice znakowe, wskaźniki do funkcji, struktury i funkcje, skomplikowane deklaracje, unie i pola bitowe wykład V(6): struktury i funkcje rekursywne, abstrakcyjne typy danych i ich implementacje: stos, kolejka, listy, drzewa wykład VI(1)*: przegląd funkcji bibliotek standardowych języka C, biblioteki: wejścia/wyjścia, funkcji matematycznych, operacji na tekstach i łańcuchach *: dla studiów dziennych

Zasady kontakt: email: mima@sphere.pl GG: 2590739 wykład kończy się egzaminem pisemnym (test + zadania) ocena 5.0 z laboratorium zwalnia z egzaminu z oceną 4.0 pomoce: Brian W. Kernighan, Dennis M.Ritchie, Język ANSI C, WNT (2002) kurs oraz opis bibliotek standardowych: http://binboy.sphere.pl dział Programowanie / ANSI C testowanie umiejętności programistycznych (zadania) http://pl.spoj.pl

Plan wykładu I Zasady Historia języka C Standard ANSI C Pierwszy program Struktura programu Kompilacja i uruchomienie Opcje kompilatora Drugi program Biblioteki standardowe Trzeci program Jednostki leksykalne Strukturalizacja Instrukcja warunkowa Instrukcja wyboru Instrukcje powtarzania Przykłady

Historia języka C Poprzednikiem języka C był interpretowany język B który Ritchie rozwinął w język C. Pierwszy okres rozwoju języka to lata 1969-1973. W roku 1973 w języku C udało się zaimplementować jądra (kernel) systemu operacyjnego Unix. W 1978 roku Brian Kernighan i Dennis Ritchie opublikowali dokumentację języka p.t. C Programming Language. C stał się popularny poza Laboratoriami Bella (gdzie powstał) po 1980 roku i stał się dominującym językiem do programowania systemów operacyjnych i aplikacji. Na bazie języka C w latach osiemdziesiątych Bjarne Stroustrup stworzył język C++, który wprowadza możliwość programowania obiektowego.

Standard ANSI C Pierwsze wersje systemu UNIX były rozpowszechniane w szkołach wyższych wraz z pełnym kodem źródłowym napisanym w języku C. Potrzeba stworzenia standardu języka wynikała z jego popularności - coraz więcej osób z niego korzystało (głównie na uniwersytetach). Amerykański standard języka - ANSI C (1983-1988). Stanowił on znaczne rozszerzenie w stosunku do wersji Kernighan'a i Ritchie'go. Kolejna wersja standardu języka: ISO 9899:1990 - modyfikacja standardu ANSI. Język zgodny z tą wersją standardu określany jest nieformalnie jako C89. Od tego czasu powstało wiele uaktualnień tej normy (np. powszechnie obowiązująca C99).

Standard ANSI C (2) W języku C zawarte są podstawowe instrukcje sterujące, niezbędne w programowaniu strukturalnym: „wykonuj jeden po drugim”: grupowanie instrukcji (nawiasy klamrowe { }) „wykonuj dla wszystkich”, „wykonuj aż do”: powtarzanie ze sprawdzeniem warunku zatrzymania (pętle for, while) „wybierz z”: podejmowanie decyzji (if - else) Możliwość tworzenia funkcji w języku C – wydzielanie (powtarzalnych) fragmentów programu – kolejne wsparcie dla strukturalizacji. Język C jest językiem niskiego poziomu: duża część kodu języka C jest bezpośrednio tłumaczona na język wewnętrzny komputera (operacje na adresach, znakach i liczbach).

Standard ANSI C (3) Standard języka C miał na celu zagwarantowanie poprawności (istniejących oraz przyszłych) programów – bez względu na architekturę komputera. Standard definiuje konstrukcje języka, jego składnię oraz zawiera specyfikacje funkcji standardowej biblioteki. W stosunku do pierwszych wersji języka C, standard ANSI C wprowadził kilka istotnych rozszerzeń: deklaracje funkcji mogły zawierać opis parametrów, specyfikacja bibliotek towarzyszących C funkcje odwołujące się do systemu operacyjnego operacje na pamięci funkcje matematyczne operacje na plikach (realizacja wejścia – wyjścia)

Pierwszy program kod źródłowy 1: #include <stdio.h> 2: int main() 3: { 4: printf(„Witaj przyjacielu!\n”); 5: return 0; 6: } kod źródłowy składa się z dyrektyw preprocesora (include), słów kluczowych (int, return) oraz nazw funkcji (main, printf) i ich argumentów (w nawiasach), nawiasy klamrowe grupują wiele instrukcji

Pierwszy program (2) 1: #include <stdio.h> 2: int main() 3: { dyrektywa informująca kompilator o wykorzystaniu funkcji z biblioteki standardowej stdio.h 2: int main() nagłówek funkcji głównej programu (w każdym programie musi znaleźć się funkcja main), typ zwracanej wartości–całkowity (int) 3: { nawias otwierający blok instrukcji – ciało funkcji głównej main 4: printf(„Witaj przyjacielu!\n”); funkcja z biblioteki standardowej stdio.h – wydrukowanie podanego w nawiasie napisu na standardowe wyjście 5: return 0; zwrócenie wartości 0 (funkcja ma typ całkowity int) 6: } nawias zamykający blok instrukcji – ciało funkcji głównej main

Struktura programu Kod programu może zostać umieszczony w jednym bądź kilku plikach. Program składa się z dyrektyw preprocesora, definicji struktur, funkcji oraz zmiennych. Funkcje zbudowane są z instrukcji. Instrukcje składają się ze słów kluczowych, operatorów, nazw zmiennych oraz znaków grupujących i separujących (nawiasy, przecinki, średniki). Program zaczyna działanie od wykonania funkcji main. Pozostałe funkcje mogą być napisane przez programistę lub pochodzić z bibliotek. Przed uruchomieniem program należy skompilować i scalić z funkcjami bibliotecznymi.

Kompilacja i uruchomienie Po skończeniu edycji kodu źródłowego zapisujemy tekst do pliku (nazwa dowolna, rozszerzenie .c): first.c Kompilacja, czyli przetłumaczenie kodu źródłowego na postać binarną zrozumiałą dla komputera (ale jeszcze nie wykonywalną): poleceniem gcc –c first.c tworzymy plik first.o Scalanie, czyli połączenie skompilowanego kodu naszego programu oraz funkcji z bibliotek zewnętrznych (np. standardowych): poleceniem gcc –o first first.o tworzymy plik wykonywalny first kompilację oraz scalanie: jednym poleceniem gcc first.c tworzymy plik wykonywalny a.out

Kompilacja i uruchomienie (2) biblioteki funkcja printf first.c first.o first kompilacja scalanie wykonanie programu: polecenie ./first (lub first) pod Windowsem: first.exe (zamiast first)

Opcje kompilatora składnia polecenia: gcc opcje nazwy_plików brak opcji: kompilacja i scalanie, standardowa nazwa pliku wykonywalnego a.out -c - tylko kompilacja -o name – utworzenie pliku wykonywalnego o nazwie name -ansi – sprawdzenie kodu pod kątem zgodności ze standardem ANSI -Wall – pokazanie wszystkich ostrzeżeń podczas kompilacji (ostrzeżenia (warnings) nie przerywają procesu kompilacji, w przeciwieństwie do błędów (errors))

Drugi program kod źródłowy 1: #include <stdio.h> 2: int main() { /* (i): usuń int */ 3: int a; /* (ii): wstaw: ,b */ 4: scanf(„%d”, &a); 5: printf(„%d * %d = %d\n”, a, a, a * a); 6: return 0; /* (iii): zakomentuj linię */ 7: } kompilacja: -ansi -Wall

Drugi program (2) 1: funkcje biblioteczne scanf oraz printf realizują sformatowane operacje wejścia – wyjścia (odczyt – zapis) 2: format wejścia – czyli kolejność oraz typy danych, które pojawiają się na wejściu – opisany jest w nawiasie, np.: scanf(„%d”, &a) oznacza wczytanie z wejścia liczby całkowitej oraz zapisanie jej wartości do komórki (zmiennej) o nazwie a 3: kolejne opisy pól z formatu wejścia oddzielamy przecinkami, wartość przypisana w danym miejscu może zostać wyznaczona z dowolnego poprawnego wyrażenia (zmienne wraz z operacjami na nich)

Drugi program (3) (i): kompilacja kodu źródłowego z parametrem –ansi –Wall spowoduje wygenerowanie ostrzeżenia: second.c:2: warning: return type defaults to `int' (ii) zmienna b nie jest nigdzie wykorzystana, stąd kompilator zgłosi ostrzeżenie: second.c :3: warning: unused variable `b‘ (iii) brak zwracanej wartości kompilator odnotuje: second.c :7: warning: control reaches end of non-void function

Biblioteki standardowe assert.h – diagnozowanie programów ctype.h – klasyfikacja znaków errno.h – zmienne przechowujące informacje o błędach math.h – funkcje matematyczne signal.h – mechanizmy obsługi zdarzeń wyjątkowych stdio.h – funkcje wejścia oraz wyjścia stdlib.h – funkcje narzędziowe (przekształcanie liczb, operacje na pamięci) string.h – operacje na tekstach time.h – obsługa daty oraz czasu

Biblioteki standardowe (2) Biblioteka math – przykłady funkcji double sin(double x); float sinf(float x); double exp(double x); double log(double x); double pow(double x, double y); Biblioteki stdlib oraz string – przykłady funkcji int atoi(const char *nptr); long atol(const char *nptr); char *strcat(char *dest, const char *src);

Trzeci program kompilacja: -ansi –Wall -lm 1: #include <stdio.h> 2: #include <math.h> 3: #include <stdlib.h> 3: int main() { 4: double a = 2; 5: char* liczba = „123”; 5: printf(„%f\n”, exp(a)); 6: printf(„%d\n”, atoi(liczba)); 7: return 0; 8: } kompilacja: -ansi –Wall -lm

Trzeci program (2) 1: parametr –lm „podpowiada” programowi scalającemu, że powinien wykorzystać bibliotekę matematyczą 2: printf(„%f\n”, exp(a)); wydrukowanie wartości exp(2) 3: printf(„%d\n”, atoi(liczba)); konwersja łańcucha znaków „123” do formatu liczby całkowitej 123

Jednostki leksykalne - identyfikatory Jednostki leksykalne są to niezależne, oddzielone separatorami (spacje, średnik, przecinek) fragmenty kodu źródłowego, np. int (typ zmiennej), scanf (identyfikator – nazwa funkcji), for, while (słowa kluczowe) Identyfikatory są to nazwy zmiennych lub funkcji. Identyfikator jest sekwencją liter i cyfr oraz znaków podkreślenia (‘_’). Rozróżniane sa małe oraz duże litery. Pierwszy znak nie może być cyfrą. Należy unikać stosowania nazw zaczynających się od ‘_’ (zarezerwowane dla bibliotek).

Jednostki leksykalne – słowa kluczowe Podane poniżej identyfikatory są słowami kluczowymi (zarezerwowane dla języka C): char, int, float, double, enum, void long, short, signed, unsigned const, static, volatile, extern, register, struct, union for, while, do, switch, case, default, if, else break, continue, return, goto, inline, sizeof, typedef

Strukturalizacja - sterowanie „wykonuj jeden po drugim”: grupowanie instrukcji (nawiasy klamrowe { }) „wykonuj dla wszystkich”, „wykonuj aż do”: powtarzanie ze sprawdzeniem warunku zatrzymania (pętle for, while) „wybierz z”: podejmowanie decyzji (if - else)

Strukturalizacja Instrukcja: wyrażenie zakończone średnikiem, np. x = 0; printf(„Hello!”); return 1; Nawiasy klamrowe służa do grupowania instrukcji w instrukcję złożoną, czyli blok np. { } instrukcje dzielimy na: instrukcje przypisania (=) instrukcje warunkowe (if-else) instrukcje wyboru (switch-case) instrukcje powtarzania (pętle: for, while)

Instrukcja warunkowa if ( wyrażenie ) instrukcja1 else instrukcja2 Sprawdzana jest wartość wyrażenia, w przypadku gdy jest różna od zera wykonywana jest instrukcja1, w przeciwnym wypadku – instrukcja2 instrukcja1 może być instrukcją prostą lub złożoną

Program Warunek Trójkąta Problem: Napisać program sprawdzający czy z podanych trzech długości można zbudować trójkąt. Wejście: liczby całkowite: a, b, c Wyjście: odpowiedź TAK lub NIE Rozwiązanie: 1. Wczytujemy 3 liczby ze standardowego wejścia 2. Należy sprawdzić warunki: a + b > c a + c > b b + c > a 3. Jeżeli wszystkie warunki są spełnione, drukujemy TAK, w przeciwnym razie drukujemy NIE (na wyjście)

Program Warunek Trójkąta 1: #include <stdio.h> 2: int main() { 3: int a, b, c; 4: scanf(„%d%d%d”, &a, &b, &c); 5: if ( a + b > c ) if ( b + c > a ) if ( a + c > b ) printf(„TAK”); else printf(„NIE”); 7: return 0; 8: }

Program Warunek Trójkąta 1: #include <stdio.h> 2: int main() { 3: int a, b, c; 4: scanf(„%d%d%d”, &a, &b, &c); 5: if (( a + b > c ) && ( b + c > a ) && ( a + c > b )) printf(„TAK”); else printf(„NIE”); 7: return 0; 8: } zastąpienie kolejnych warunków jednym, spójnik logiczny && = AND (logiczne „i”)

Instrukcja wyboru switch ( wyrażenie ) { case etykieta1: instrukcje ........ default instrukcje } Wyrażenie użyte jako selektor wyboru musi przyjmować wartości całkowite, etykiety muszą być stałymi całkowitymi. Wykonanie instrukcji switch-case: Wyrażenie porównywane jest kolejno z etykietami, jeżeli jedna z etykiet ma wartość wyrażenia, to wykonywane są instrukcje po niej następujące. Instrukcje po etykiecie default są wykonywane, jeżeli żadna z etykiet nie ma wartośći równej selektorowi wyboru. Aby uniknąć sprawdzania kolejnych przypadków, stosujemy instrukcję break.

Instrukcja wyboru - przykład 1: #include <stdio.h> 2: int main() { 3: int cyfra_mala = 0, cyfra_duza = 0, inne = 0; 4: char znak; 5: do { /* instrukcja powtarzania */ 6: scanf(„%c”, &znak); 7: switch ( znak ) { /* instrukcja wyboru */ 8: case ‘0’: case ‘1’: case ‘2’: case ‘3’: case ‘4’: 9: cyfra_mala++; break; 10: case ‘5’: case ‘6’: case ‘7’: case ‘8’: case ‘9’: 11: cyfra_duza++; break; 12: default: inne++; 13: } 14: } while ( znak != EOF ); 15: printf(„%d %d %d”, cyfra_mala, cyfra_duza, inne); 16: return 0; 17: }

Instrukcje powtarzania while ( wyrażenie ) instrukcja do for ( W1; W2; W3 )

Instrukcje powtarzania - zadania Napisz program, który wyznacza wartość: n! = 1 · 2 · ... · n Napisz program, który drukuje trójkąt z gwiazdek: * *** ***** ******* 3. Napisz program, który wczytuje ze standardowego wejścia kolejne znaki – cyfry i tworzy z nich liczbę dziesiętną.

Plan wykładu II Proste typy danych Stałe Deklaracje Operatory i wyrażenia Kolejność wykonywania obliczeń w wyrażeniach Proste funkcje Konwersja typów Definicja struktur Odwrotna Notacja Polska* *: dla studiów dziennych (wymagane na egzaminie)

Proste typy danych W języku C wsytępuje tylko kilka podstawowych typów danych: char jeden bajt, typ znakowy int typ cakowity, standard ANSI określa rozmiar na co najmniej dwa bajty float typ zmiennoprzecinkowy pojednycznej precyzji double typ zmiennoprzecinkowy podwójnej precyzji Kwalifikatory short (krótki, nie dłuższy niż int) oraz long (długi, przynajmniej 4 bajty) odnoszą się do obiektów całkowitych, np.: short int a; long int b; lub zmiennoprzecinkowych, np.: long double c; Kwalifikatory signed (ze znakiem liczby) oraz unsigned (bez znaku liczby) można stosować z typem char lub dowolnym typem całkowitym, np.: signed char znak; /* od –128 do 127 */ unsigned char; /* od 0 do 255 */

Tablice oraz wskaźniki (wstęp) Jeżeli chcemy utworzyć zmienną, która będzie przechowywać wiele wartości danego typu prostego deklarujemy tablicę, czyli obszar pamięci złożony z podanej w nawiasie liczby komórek, z którego każda jest zadanego typu prostego (uwaga: można tworzyć tablice tablic) int a[10]; float tab[15]; Jeżeli nie znamy rozmiaru tablicy możemy utworzyć zmienną wskaźnikową int* a; float* b; Uwaga! Deklaracja zmienne wskaźnikowej nie powoduje zarezerwowania dla niej pamięci!

Stałe Każda stała jest jakiegoś typu (np. występująca w wyrażeniach). Stałe całkowite 1234 domyślnie typu int 1234L typu long int 1234U unsigned int 1234UL unsigned long int 012 system ósemkowy = 10 0x12 system szesnastkowy = 18 Stałe zmiennoprzecinkowe notacja dziesiętna z kropką: -314.15 notacja wykładnicza: -3.1415e2 (lub –3.1415E2) domyślnie typu double użycie literki F lub L zmienia typ na float lub long double Stałe znakowe oraz łańcuchowe ‘a’ ujęte w pojedyncze apostrofy, typ char „ala ma psa” ciągi znaków ujęte w apostrofy

Deklaracje Deklaracje zmiennych Deklaracje stałych Wyliczenia int cyfra = 7; char znak; char znak = ‘o’; /* deklaracja zmiennej znak wraz z inicjacją wartości */ double a, b = 3.2e-1; Deklaracje stałych const double pi = 3.1415; const int liczba = 37; Uwaga! Wartość zmiennych poprzedzonych kwalifikatorem const nie może być zmieniona w trakcie działania programu (próba zmiany: zależna od implementacji kompilatora). Wyliczenia enum dni {pn, wt, sr, czw, pt}; /* domyślnie: 0, 1, 2, 3, 4 */ enum rok {smoka = 1, koguta, malpy}; /* kolejne =2, =3, ... */

Operatory i wyrażenia Język C oferuje programiście znaczną liczbę operatorów: operatory arytmetyczne: addytywne (+ -), multiplikatywne (* / %), inkrementacji (++) oraz dekrementacji (--) operatory bitowe (& ^ | ~ << >>) operatory logiczne (&& || !) operatory relacyjne (> < <= >= == !=) operatory przypisania (=) operator warunkowy (? :) operator wyliczeniowy (,) operator wyboru składowych (. ->) operator pobrania adresu oraz dostępu do zmiennej wskazywanej (& *) operator pobrania rozmiaru (sizeof) operator indeksowania ([]) operator konwersji (nazwa-typu)

Operatory i wyrażenia operatory arytmetyczne: addytywne (+ -), multiplikatywne (* /), inkrementacji (++) oraz dekrementacji (--) addytywne dodawanie a + b typy arytmetyczne odejmowanie a – b typy arytmetyczne (a,b – operandy, +,- operatory) musi zachodzić zgodność typów, oba arytmetyczne lub jeden całkowity, a drugi wskaźnikowy multiplikatywne mnożenie a * b typy arytmetyczne dzielenie a / b typy arytmetyczne reszta modulo a % b typy całkowite inkrementacji i dekrementacji przedrostkowe --a ++a przyrostkowe a-- a++ operand musi być typu arytmetycznego lub wskaźnikowego

Operatory i wyrażenia operatory bitowe (& ^ | ~) iloczyn AND a & b typy całkowite suma modulo 2 EXOR a ^ b typy całkowite alternatywa OR a | b typy całkowite negacja NOT ~a typ całkowity przed obliczaniem wartości dokonywane są konwersje arytmetyczne Działania logiczne na bitach a b AND EXOR OR NOT 0 0 0 0 0 1 0 0 1 1 0 0 1 0 1 1 1 1 1 1 0 1 0 operatory przesunięcia bitowego >> << a >> b przesuń liczbę a o b bitów w prawo a << b przesuń liczbę a o b bitów w lewo dla liczb ze znakiem przesunięcie w prawo powiela bit znaku

Operatory i wyrażenia operatory logiczne (&& || !) koniunkcja a && b alternatywa a || b negacja !a wartość wyrażenia logicznego jest zawsze typu int Tabela wartości wyrażeń logicznych a b koniunkcja alternatywa negacja 0 0 fałsz fałsz prawda 0 fałsz prawda fałsz 0 1 fałsz prawda prawda 1 prawda prawda fałsz operatory warunkowy (? :) a ? b : c w pierwszej kolejności obliczana jest wartość a, jeżeli jest ona niezerowa jest obliczana wartość b, natomiast c jest ignorowane, w przeciwnym razie (a jest równa zero) - odwrotnie

Operatory i wyrażenia operatory relacyjne (> < <= >= == !=) a < b a mniejsze niż b a > b a większe niż b a <= b a mniejsze lub równe b a >= b a większe lub równe b a == b a równe b a != b a różne od b Oba operandy muszą być typu arytmetycznego lub oba wskaźnikami zgodnych typów operatory przypisania (= oraz złożone) a = b w przypadku róźnych typów zachodzi konwersja do typu a złożone operatory przypisania a += b -= *= /= %= <<= >>= &= ^= |=

Operatory i wyrażenia operator wyliczeniowy (,) a, b, c; dowolne typy Opracowywanie tego wyrażenia przebiega zgodnie z kolejnością operator wyboru składowych (. ->) w celu odwołania się do struktury lub unii należy posłuzyć się jednym z operatorów wyboru składowej a.x a->x w zależności od typu a operator pobrania adresu oraz dostępu do zmiennej wskazywanej (& *) &a pobranie adresu *a odwołanie do zmiennej wskazywanej przez a operator pobrania rozmiaru (sizeof) sizeof(typ) rozmiar w bajtach typu sizeof(a) rozmiar pamięci zajmowanej przez a operator indeksowania ([]) a[2] (*a+2) dostęp do trzeciej  komórki (liczone od 0)

Kolejność wykonywania obliczeń Każde wyrażenie musi zostać przeanalizowane przez kompilator w celu ustalenia kolejności wykonywanych obliczeń oraz zgodności typów występujących argumentów a + b * c  (a + b) * c ? a + (b * c) 3 / 2  1.5 ? 1 Pierwszą rzeczą jest zatem informacja dla kompilatora, które działania mają wyższy priorytet, drugą rzeczą jest informacja o typach operandów w wyrażeniach Podstawowe pojęcia: priorytet operatorów stanowi o kolejności wykonywanych działań wiązanie sposób łączenia operatora z operandami operatory unarne (jednoargumentowe) i binarne (dwuargumentowe) l-wyrażenia wyrażenia identyfikujące obszar pamięci, specyfikator const powoduje, że l-wartość nie jest modyfikowalna opracowywanie wyrażenia wszystkie obliczenia i inne operacje jakie sa wykonywane podczas przetwarzania wyrażenia

Kolejność wykonywania obliczeń Priorytety operatorów: a + b * c  (a + b) * c ? a + (b * c) wyrażenie zostanie opracowane zgodnie z priorytetami operatorów + oraz *: jeżeli + będzie miał wyższy priorytet niż * wtedy dodawanie zostanie wykonane przed mnożeniem, jeżeli zaś odwrotnie, to mnożenie zostanie wykonane przed dodawaniem Wiązanie operatorów: a + b – c  (a + b) – c ? a + (b – c) jeżeli kolejność obliczeń nie została określona za pomocą nawiasów, zostanie rozstrzygnięta na podstawie wiązania jeżeli wiązanie następuje od lewej do prawej (tak jak w C), to wyrażenie zostanie potraktowane jako (a + b) – c, jeżeli od prawej do lewej, to jako a + (b – c)

Kolejność wykonywania obliczeń Operatory unarne: operatory wymagające jednego operanda (argumentu), np. ~ (negacja binarna), ! (negacja logiczna), & (operator pobrania adresu), * (operator dostępu do zmiennej wskazywanej) Operatory binarne: operatory dwuargumentowe, wymagające dwóch operandów, wiązanie dla wszystkich operatorów zdefiniowane jest od lewej do prawej, poza złożonymi operatorami przypisania oraz operatorem warunkowym

Proste funkcje Podczas pisania programu (implementacji algorytmu) zachodzi potrzeba wielokrotnego wykonywania tych samych operacji (instrukcji) w różnych sytuacjach (dla różnych danych), np. znalezienie najmniejszego elementu w ciągu liczb (w szczególnym przypadku dwóch liczb), posortowanie ciągu liczb, wyznaczenie rozwiązań równania kwadratowego. W obrębie funkcji można zamknąć operacje wykonywane dla zadanych paramtetrów wejściowych, np. ciąg liczb, współczynniki równania kwadratowego a, b, c W praktyce każdy (większy) program jest zbudowany z wielu funkcji (dobry styl programowania, wiele krótkich i czytelnych funkcji), poprawia to przejrzystość i czytelność programu, zapewnia oszczędność czasu (funkcja raz napisana może być wielokrotnie wykorzystana), pozwala wreszcie zaoszczędzić pamięć – funkcja jest umieszczona w jednym miejscu w pamięci podczas wykonywania programu.

Proste funkcje - przykłady Funkcja obliczająca minimum dwóch liczb a oraz b, to znaczy zwraca wartość równą mniejszej z obu liczb 1: int min(int a, int b) { 2: if ( a > b ) return b; 3: else return a; 4: } Wykorzystanie funkcji w programie: wywołanie min(a, b) Napisz funkcje realizujące (poniżej podano deklaracje) liczenie silni: int silnia(int a); znajdującą element minimalny: int min(int* tablica);

Funkcje – deklaracja i definicja Deklaracja funkcji, w odróżnieniu od definicji jest pojęciem logicznym, stanowi informację dla kompilatora, że funkcja o określonej nazwie, typie parametrów może zostać użyta (ale nie musi!) w programie. int min(int a, int b); Definicja funkcji określa natomiast co funkcja robi, stanowi zatem zapis jakiegoś algorytmu, definicja funkcji, w odróżnieniu od deklaracji, powoduje przydzielenie obszaru pamięci, w którym znajduje się kod wynikowy funkcji. 1: int min(int a, int b) { 2: if ( a > b ) return b; 3: else return a; 4: }

Konwersja typów (nazwa-typu) Operand Operator konwersji (jawnej) ma postać (nazwa-typu) Operand Konwersja niejawna zachodzi w sytuacji, gdy operandy danego operatora są różnych typów, ogólna zasada mówi, że automatycznie wykonuje się tylko takie przekształcenia, dla których argument zajmujący mniej pamięci jest zamieniany na argument zajmujący więcej pamięci (char->int, int->float) bez utraty informacji, np.: int a=5/2; float b = a/2; a=? b=?

Typy złożone - definicja tablic i struktur Typy proste służą do opisu jednej cechy (wartości) danej zmiennej, czasami jednak zachodzi potrzeba zgromadzenia większej liczby informacji w ramach danej zmiennej, np. liczby zespolone to pary liczb, współrzędne w przestrzeni to trójki liczb, sekwencje liczb jako ciągi n-elementowe, rekordy w bazach danych grupujące informacje osobowe (wiek, imię, nazwisko, etc..) Tablica 10 liczb całkowitych: int tablica[10]; /* jeden sposób */ int* tablica; /* drugi sposób – bardziej uniwersalny */ Następnie konieczne jest wywołanie funkcji malloc powodującej przydzielenie w pamięci 10 komórek typu int: tablica = (int*) malloc(sizeof(int) * 10);

Typy złożone - definicja tablic i struktur struct Punkt { /* typ zmiennej */ int wsp_x, wsp_y; char kolor; char znak; }; /* możliwe jest stworzenie od razu zmiennej typu Punkt */ Utworzenie zmiennych: struct Punkt a,b; Dostęp do pól zmiennej strukturalnej: a.wsp_x = 1; a.kolor = 0; a.znak = ‘c’;

Plan wykładu III Wskaźniki i adresy Wskaźniki i tablice Wskaźniki i argumenty funkcji Arytmetyka na adresach Złożone tablice (tablice tablic i tablice struktur) Tablice o niejawnie deklarowanych rozmiarach - funkcja malloc Operacje na plikach, formatowane wejście oraz wyjście Struktura programu: metody projektowania złożonych programów Zmienne globalne i zasięg nazw Kilka uwag o stylu programowania

Wskaźniki i adresy Wskaźnik jest zmienną, której wartość jest adresem innej zmiennej, np. int a = 2, *c; c = &a; c=? *c=? ANSI C wprowadza jawne reguły operowania na wskaźnikach Jednoargumentowy operator & zwraca adres obiektu Jednoargumentowy operator * pozwala nam uzyskać wartość obiektu wskazywanego przez wskaźnik c  adres zmiennej a *c  wartość zmiennej a (=2) Organizacja pamięci globalnej - sterta oraz lokalnej (funkcji) - stos

Wskaźniki i tablice W języku C istnieje bezpośrednia zależność pomiędzy wskaźnikami i tablicami, tzn. tablice są jawnie deklarowane jako ciąg bezpośrednio następujących po sobie komórek a zmienna tablicowa jest wskaźnikiem na pierwszy element tablicy (początek tablicy) int a[5] = {0,1,2,3,4}; a = ? a[1] = ? *a = ? *(a+2) = ? Wyraźenie „tablica i indeks” jest równoważne wyrażeniu „wskaźnik i przesunięcie” Tablice do funkcji przekazujemy poprzez wskaźnik na pierwszy jej element, czyli po prostu przez jej nazwę Podobnie jeżeli funkcja zwrócić ma tablicę jako wartość – posługujemy się wskaźnikiem

Wskaźniki i argumenty funkcji W języku C argumenty przekazywane są przez wartość, np.: void zamiana(int a, int b) { int c; c = a; a = b; b = c; } czy wywołanie funkcji zamiana(a,b) spowoduje zamianę wartości zmiennych a oraz b Zmiana wartość zmiennych podanych jako argumenty do funkcji jest możliwa poprzez odwołanie się do nich przez wskaźniki, np. void zamiana(int* a, int* b) { int c; c = *a; *a = *b; *b = c; }

Arytmetyka na wskaźnikach Ogólna zasada Następny element w tablicy (np. tablicy struktur) ma adres większy o liczbę bajtów potrzebnych do przechowania wartości zmiennej w jednej komórce. Jeżeli p jest wskaźnikiem do pewnego elementu tablicy, to po wykonaniu operacji p++ wskazywać on będzie następny element w tablicy (operacje arytmetyczne analogicznie).

Złożone tablice Tablice tablic Tablice struktur int a[2][3]; /* tablica dwuwymiarowa */ a = ? a[1] = ? a[1][2] = ? int a[2][2] = {{1,2}, {3,4}}; int **c; c = &a; c[2][2] = ? Tablice struktur struct Bakteria { int rozmiar; char nazwa[32]; }; struct Bakteria kolonia[10]; kolonia = ? kolonia[0] = ? kolonia[1].nazwa = ?

Plan wykładu IV Unie i pola bitowe Skomplikowane deklaracje Wybrane komputerowe prawa Murphy’ego Abstrakcyjne typy danych i ich implementacje: stos, kolejka, listy Struktury i funkcje rekursywne

Unie i pola bitowe Unie, podobnie jak struktura składa się z pól, z tą różnicą, że zaczynają się one w tej samej komórce pamięci, rozmiar unii jest równy rozmiarowi największej składowej union example { double a; long b; char* c; }; /* średnik jest ważny! */ w programie: union example u = { 1234.5678 }; printf(”%lf\n%d\n%s\n”,u.a, u.b, u.c);

Skomplikowane deklaracje Chcemy stworzyć tablicę 7 wskaźników do tablic o rozmiarach 2 x 3 przechowujących dane typu double: - 7 wskaźników *tablica[7] - wskazują na tablice o rozmiarze 2 x 3 (*tablica[7])[2][3] - typ wskazywany double double (*tablica[7])[2][3] tworzymy elementy (tablice) korzystając z funkcji malloc

Skomplikowane deklaracje Chcemy zadeklarować tablicę dwuelementową wskaźników do funkcji o dwóch parametrach całkowitych i wartości zwracanej typu double: - tablica dwuelementowa tablica[2] - elementami tablicy będą wskaźniki *(tablica[2]) - wskaźniki te będą wskazywać na funkcje o dwóch parametrach typu int oraz wartościach typu double double (*(tablica[2]))(int,int)