15 CLA 6 Functions

Funkcje

dekompozycja - rozbijanie problemu na mniejsze częsci


kompilator musi mieć następujące informacje o funkcji:
nazwę
ile parametrów i jakiego typu
jaki zwraca typ

kompilator może to odkryć przy pierwszym uruchomieniu funkcji (implicit declaration)
albo wcześniej z prototypu, prototyp niezbędny gdy definicja pod main.

deklaracja funkcji (prototyp)zakończona ;  nie zawiera ciała
definicja funkcji  ciało w {}


wywołanie funkcji nazwa();

jeśli funkcja nic nie zwraca void, nie można wywołać tak:

int i=hello();

jeśli funkcja zwraca konkretny typ to return expression

bloki funkcji {  } określają zakres działania zmiennych w nich zainicjowanych

zmienna zadeklarowana poza blokami (main czy funkcji) będzie zmienna globalną
dostępną dla każdej funkcji


parametry funkcji - specjalny rodzaj zmiennej zadeklarowanej w nawiasach, dostępnej wewnątrz F.

parametry funkcji moga zawierać działanie
np:
hello (2*x);   //jeśli tylko wynik zgadza się z typem określonym w deklaracji/prototypie


parametry funkcji przez wartość tworzą kopię więc zmiany wew. funkcji nie wpływają na wartość

przekazywanie przez wskaźnik wpłynie na wynik:

void functionx(int *ptr) {
    *ptr = *ptr + 100;
}

albo:
void incr(int *value) {
     (*value)++;                    //w nawiasach musi byc !!!
}


PARAMETRY FUNKCJI i STRUKTURY

struktury  przekazywane są jako wartość

ale możemy zastosować wskaźnik do struktury (wtedy wywołujemy struturę przez adres &)


struct STR {
    int     Int;
    char    Char;
};

void funx(struct STR *p) {
    p -> Int = 2;                             //uwaga, konieczne odwolanie przez ->
    p -> Char = 'B';
}

int main(void) {
    struct STR str = { 1, 'A' };

    funx(&str);                                 //uwaga przekazanie przez & zeby powstał wskaznik



PARAMETRY FUNKCJI I TABLICE

tablice zawsze są przekazywane jako wskaźnik do pierwszego elementu
#include <stdio.h>

void mul2(int *arrptr) {
    int i;

    for(i = 0; i < 5; i++)
       arrptr[i] *= 2;
}

int main(void) {
    int arr[5] = { 1, 2, 3, 4, 5 };
    int i;

    for(i = 0; i < 5; i++)
        printf("%d ", arr[i]);
    printf("\n");
    mul2(arr);
    for(i = 0; i < 5; i++)
        printf("%d ", arr[i]);
    printf("\n");
    return 0;
}

i pomimo tego, ze są przekazane jako wskaznik, to mozna nimi operować jak tablicą (ideksując [])

nawet jak przekazujemy przez void funkcja (int a[]);  to przekazuje przez wkaśnik i nie ma informacji o wielkości tablicy, sizeof pokaze wewnatrz funkcji tylko wielkosc wskaxnika, zeby wiedziec o wielkosci tablicy przekazanej do funkcji stosuje się kilka metod, jedna z nich to przekazanie dodatkowej wartosci o długości tablicy.

String jest specjalnym rodzajem tablicy (typu char) bo kończy się \0
dzięki czemu możemu szukać \0 i policzyć dlugosc ciagu (wielkosc tablicy)

int mystrlen(char *str) {
    int counter = 0;

    while(*str != '\0') {          //mozemy zamienic na while(*str)
        counter++;
        str++;               //a zeby pozbyc się te lini na while(*str++)
    }
    return counter;
}

powiększamy str++ bo ma zmieniać się sam wskaźnik i przeskakiwać na następne pola(a nie wartosc)

a tutaj wersja zoptymalizowana do pętli for:
int mystrlen(char *str) {
    int counter;

    for(counter =0; *str++; counter++)
        ;
    return counter;
}


i jeszcze jedna wersja bez zmiennej counter (wspolna zmienna str) ale za to z dodanym wskaznikiem

{
char *begin;

for(begin=str;*str;str++)
;
return str-begin;
}

poniżej własna wersja strcpy:
char *mystrcpy(char *destination, char *source) {
    char *res = destination;

    for( ; ; )  {             /* a finite infinite loop */
          *destination = *source;
        if(*source == '\0')
            break;
        destination++;
        source++;
    }
    return res;
}


znak  =  ma pewną właściwość, nie tylko przypisuje wartość, ale ja zwraca !
dlatego możemy uprościc i zapisać tak, czyli jak w source bedzie 0 zwroci poza () tez 0
for( ; ; )  {             /* a finite infinite loop */
        if(!(*destination = *source))
            break;


generalnie :

i = j = k = 0;
 i = (j = (k = 0));
czyli:
k = 0;
j = 0;
i = 0;

forma najkrótsza:
char *mystrcpy(char *destination, char *source) {
    char *res;

    for(res = destination; (*destination = *source);) {
        destination++;
        source++;
    }
    return res;
}

mega skrócone:
 for(res = destination; (*destination++ = *source++); ) ;


TABLICE WIELOWYMIAROWE jako PARAMETR FUNKCJI
potrzebujemy informacji o ilosci kolumn, zeby wiedziec co ile skakać

void printarr(int t[3][3]);

w praktyce wystarczy taka informacja


void printarr(int t[][3]);


TABLICA WSKAŹNIKÓW
inne rozwiązanie to tablica wskaźników
int *arrptr[3];              //tak zwany fake array

w takiej sytuacji musimy alokować pamięć i ją potem zwolnić

for(i = 0; i < 3; i++) {
        arrptr[i] = (int *) malloc(3 * sizeof(int));
        for(j = 0; j < 3; j++)
            arrptr[i][j] = (3 * i) + j + 1;
    }

zwolnienie:
for(i = 0; i < 3; i++)
        free(arrptr[i]);

całość:

#include <stdio.h>
#include <stdlib.h>
void printarrptr(int **t) {
    int i,j;
    for(i = 0; i<3; i++) {
        for(j = 0; j<3; j++) 
            printf("%d\t",t[i][j]);
        printf("\n");
    }
}
int main(void) {
    int *arrptr[3];
    int i,j;

    for(i = 0; i < 3; i++) {
        arrptr[i] = (int *) malloc(3 * sizeof(int));
        for(j = 0; j < 3; j++)
            arrptr[i][j] = (3 * i) + j + 1;
    }
    printarrptr(arrptr);
    for(i = 0; i < 3; i++)
        free(arrptr[i]);
    return 0;
}



PARAMETRY FUNKCJI MAIN

int main(int argc,char *argv[])

argc- counter, licznik argumentów, kiedy 1 to bez parametrów
argv - tablica wskaźników do stringów zawierających argumenty

argv[0] contains the name of the running program
     argv[1] contains the string passed to the program as the first argument
     argv[n] contains the string passed to the program as the n-th argument

wydruk argumentów w kolumnie:
#include <stdio.h>

int main(int argc, char *argv[]) {
    int i;

    for(i = 0; i < argc; i++)
        printf("%s\n", argv[i]);
    return 0;
}


REKURENCJA

funkcja rekurencyjna n!

int factorial(int n) {
    if(n == 1)
        return 1;
    else
        return n * factorial(n – 1);
}




OPERATOR    EX1  ?  EX2  :  EX3


jeśli EX1 prawda  to  EX2  jesli nie to EX3



EXTERN

extern int factorial(int n);

the purpose of a header file can be twofold:

firstly, the compiler finds out how to compile the external function invocation;
secondly, the programmer can learn how to use the functions in the program.

przykładowy:
/***********************************************************
factorial version 1.0, 24 July 2012
author: sauron@mordor.com
the function computes the factorial of its argument
acceptable range of the parameter is [1..20]
the correctness of the parameter isn't checked – be careful!
************************************************************/

teraz funkcja  factorial w osobnym pliku (dlatego extern) nazwanym  factorial.h

w głównym programie go dołączamy przez include ale piszemy w " " (bo plik w tym samym katalogu)
przykład całości:
#include <stdio.h>
#include "factorial.h"

int main(int argc, char *argv[]) {
    int n, result;

    printf("Enter n value:");
    scanf("%d", &n);
    if(n <= 0 || n > 20) {
        printf("Bad news: you've entered an invalid value.\n");
        return 1;
    }

    result = factorial(n);

    printf("Factorial of %d is %d\n", n, result);
    return 0;
}

gdzie zawartość factorial.h to:

int factorial(int n) {
return n == 1 ? 1 : factorial (n - 1) - n;
}



ZADANIA

Zad1:

#include <stdio.h>
    int i = 0;
    void f(void) {
        int i = 1;
    }
    int main(void) {
        f();
        printf("%d",i);
        return 0;
    }

wynik 0, zamiana w funkcji z int i=1 na i=1 sprawi ze nie stworzy nowej ale zmieni globalna

Zad2

#include <stdio.h>
    int i = 1;
    int *f(void) {
        return &i;
    }
    int main(void) {
        int i = 0;
        i = *f();
        printf("%d",i);
        return 0;
    }

Wynik 1, mamy stworzenie kolejnej zmiennej i w zakresie maina {}, ale funkcja odwola sie do globalnej



Zad3
    #include <stdio.h>
    int i = 0;
    int *f(int *i) {
        (*i)++;
        return i;
    }
    int main(void) {
        int i = 1;
        i = *f(&i);
        printf("%d",i);
        return 0;
    }

Wynik 2, bo w tym przypadku wpisujemy parametr funkcji w obszarze main {} a tam mamy inna zmienna i o wartosci 1 a nie 0 jak w globalnym

Zad 4
 #include <stdio.h>
    int f(int t[][]) {
        return t[0][0] + t[1][0];
    }
    int main(void) {
        int i,a[2][2] = { {-2,-1},{1,2} };
        i = f(a + 2);
        printf("%d",i);
        return 0;
    }

Wynik: błąd kompilacji, bo jeśli [][] jako parametr funkcji to musi mieć ilość kolumn

Zad5

 #include <stdio.h>
    int f(char t[]) {
        return t[1] - t[0];
    }
    int main(void) {
        int i = 2;
        i -= f("ABDGK" + 1);
        printf("%d",i);
        return 0;
    }

Wynik 0, bo D-B =2

Zad 6


#include <stdio.h>
    #include <string.h>
    void f(char *s,int i) {
        *(s + i) = '\0';
    }
    int main(void) {
        char a[] = { 'a','b','c','d' };
        f(*a[1],1);
        printf("%d",strlen(a));
        return 0;
    }

Wynik błąd kompilacji, nie może być  *a[1]

Zad7
to samo zadanie co 6 ale poprawne

    #include <stdio.h>
    #include <string.h>
    void f(char *s,int i) {
        *(s + i) = '\0';
    }
    int main(void) {
        char a[] = { 'a','b','c','d' };
        f(a+1,1);
        printf("%d",strlen(a));
        return 0;
    }

Wynik 2