Metody Programowania - Lista 9


Zadanie 1

Poniższy program dla dużych wartości `n' powoduje przepełnienie stosu:
#include <stdlib.h>
#include <stdio.h>

unsigned int
zjadaj_stos(int n, unsigned k)
{
    if (n > 0) {
        k+=n;
        return k + zjadaj_stos(n - 1, k);
    } else {
        return 0;
    }
}

int
main(int argc, char * * argv)
{
    int n=1;
    if (argc != 2) {
        printf("Użycie: %s głębokość_rekursji\n", argv[0]);
    } else {
        n = atol(argv[1]);
    }
    printf("wynik (bez sensu) %ud\n", zjadaj_stos(n, 0));
    return 1;
}
Domyślne ograniczenie na wielkość stosu pod Linuxem to 8192 kB. Zmieniając wartość `n' i sprawdzając czy program da się wykonać ustalić zapotrzebowanie (jednej generacji) procedury `zjadaj_stos'. Porównać to z kodem asemblerowym (z `gcc -S').

Zadanie 2

Wykonanie poniższego programu kończy się błędem. Dlaczego?

#include <stdio.h>

typedef struct { char t[20000000];} sa;

sa x;

void 
fun(sa y)
{
    putchar(y.t[0]);
}

int
main(void)
{
    x.t[0] = '\n';
    fun(x);
    return 0;
}

Zadanie 3

Poniższa funkcja rekursywna może być wywołana z dużą wartością `k' bez przepełnienia stosu (użyć opcję `-O' przy kompilacji). Dlaczego?

unsigned int
rec_sum(unsigned int a, int k)
{
    if (k>0) {
        return rec_sum(a+k, k-1);
    } else {
	return a;
    }
}

Zadanie 4

Funkcja:

void
przerob_zlepek(char * s1, char * s2)
{
    char bufor[500];
    sprintf(bufor, "%s (i %s)");
    rob_cos(bufor);
}
jest niebezpieczna (zakładamy że `rob_cos' jest zadeklarowana i poprawna). Przerobić tą funkcję tak by albo wykonała się poprawnie, albo wezwała `exit'. Wskazówka: przeczytać opis `snprintf'.