Sunteți pe pagina 1din 12

PCLP.

Laborator 8 (la Cursurile 6 și 7)


Descompunerea programelor, recursivitatea şi preprocesarea

1. Proiecte cu descompunerea programului calculator (vezi Cursul 6) în mai multe fișiere sursă

Aplicație propusă 1. Scrieți un proiect (vezi Laboratorul 7) care citește un număr pe linie, precedat opțional de
un semn și-l adună la toate numerele anterioare, tipărind suma după fiecare intrare folosind trei fișiere sursă:
getline.c pe baza funcției getline(), main.c pe baza funcției main() şi atof.c pe baza funcției atof(), funcții
definite mai jos:
#include <stdio.h>

/* getline: get line into s, return length */


int getline(char s[], int lim)
{
int c, i;

i = 0;
while (--lim > 0 && (c=getchar()) != EOF && c != '\n')
s[i++] = c;
if (c == '\n')
s[i++] = c;
s[i] = '\0';

return i;
}

#include <stdio.h>
#define MAXLINE 100

/* rudimentary calculator */
int main()
{
double sum, atof(char []);
char line[MAXLINE];
int getline(char line[], int max);

sum = 0;
while (getline(line, MAXLINE) > 0)
printf("\t%g\n", sum += atof(line));
return 0;
}

#include <ctype.h>
/* atof: convert string s to double */
double atof(char s[])
{
double val, power;
int i, sign;

for (i = 0; isspace(s[i]); i++) /* skip white space */


;
sign = (s[i] == '-') ? -1 : 1;
if (s[i] == '+' || s[i] == '-')
i++;
for (val = 0.0; isdigit(s[i]); i++)
val = 10.0 * val + (s[i] - '0');
if (s[i] == '.')
i++;
for (power = 1.0; isdigit(s[i]); i++) {
val = 10.0 * val + (s[i] - '0');
power *= 10;
}
return sign * val / power;
}
1
Aplicaţie rezolvată 1*. Extindeţi - în proiectul de la Aplicația propusă 1 - funcţia atof astfel încât ea să
recunoască şi să convertească şi notaţia ştiinţifică de forma:
-6
123.45e-6 (reprezentând numărul 123.45*10 )

în care un număr real virgulă mobilă poate fi urmat de e sau E şi de un exponent cu semn. Apoi scrieţi
programul complet care primind pe intrare un şir de caractere reprezentând un număr real virgulă mobilă fie în
notaţie ştiinţifică, fie cu punct zecimal îl converteşte în număr real în reprezentarea cu parte întreagă, punct
zecimal şi parte fracţionară.
#include <stdio.h>
#include <ctype.h>

#define MAXLINE 1000

int getchars(char s[], int max);


double atof(char s[]);
int main(void)
{
char s[MAXLINE];
printf("Dati nr real cu punct zecimal sau in notatie stiintifica, apoi Enter:\n");
while (getchars(s, MAXLINE) == 0)
;

printf("Numarul este: %lf\n", atof(s));


return 0;
}

int getchars(char s[], int max)


{
int c, i, l;

for (i = 0, l = 0; (c = getchar()) != EOF && c != '\n'; ++i)


if (i < max - 1)
s[l++] = c;
s[l] = '\0';
return l;
}

/* atof: converteste un sir s la double */


double atof(char s[])
{
double val, power, base, epower;
int i, sign, exponent;

for (i = 0; isspace(s[i]); i++) /* sare spatiile albe */


;
sign = (s[i] == '-') ? -1 : 1;
if (s[i] == '+' || s[i] == '-')
i++;
for (val = 0.0; isdigit(s[i]); i++)
val = 10.0 * val + (s[i] - '0');
if (s[i] == '.')
i++;
for (power = 1.0; isdigit(s[i]); i++) {
val = 10.0 * val + (s[i] - '0');
power *= 10;
}
epower = 1;
if (s[i] == 'e' || s[i] == 'E') {
i++;
base = s[i] == '-' ? 0.1 : 10.0;
if (s[i] == '-' || s[i] == '+')
i++;
for (exponent = 0; isdigit(s[i]); i++) {
exponent = 10 * exponent + (s[i] - '0');
2
}
while (exponent-- > 0)
epower *= base;
}
return sign * val / power * epower;
}

Aplicație rezolvată 2*. Extindeți programul calculator prezentat la Cursul 6,


adăugând operatorul modulo (%) - pentru calcularea restului împărțirii a două numere
întregi - și posibilitatea de a lucra cu numere negative. Descompuneți programul
construind un proiect.
#include <stdio.h>
#include <stdlib.h> /* pentru atof() */
#include <math.h>

#define MAXLINE 1000


#define MAXOP 100 /* dimensiunea maxima a unui operand sau a unui operator */
#define NUMBER '0' /* semnal ca a fost gasit un numar */

int getop(char []);


void push(double);
double pop(void);

int main(void)
{
int type;
double op2;
char s[MAXOP];

while ((type = getop(s)) != EOF) {


switch (type) {
case NUMBER:
push(atof(s));
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
op2 = pop();
push(pop() - op2);
break;
case '/':
op2 = pop();
if (op2 != 0.0)
push(pop() / op2);
else
printf("eroare: impartire la zero\n");
break;
case '%':
op2 = pop();
if (op2 != 0.0)
push(fmod(pop(), op2));
else
printf("eroare: impartire la zero\n");
break;
case '\n':
printf("= %g\n", pop());
break;
default:
printf("eroare: comanda necunoscuta %s\n", s);
break;
}
}
return 0;
3
}

#define MAXVAL 100 /* adancimea maxima a stivei */

int sp = 0; /* urmatoarea pozitie libera in stiva */


double val[MAXVAL]; /* stiva cu valori */

/* push: pune f pe stiva cu valori */


void push(double f)
{
if (sp < MAXVAL)
val[sp++] = f;
else
printf("eroare: stiva plina, push imposibil%g\n", f);
}

/* pop: scoate si returneaza valoare din varful stivei */


double pop(void)
{
if (sp > 0)
return val[--sp];
else {
printf("eroare: stiva vida\n");
return 0.0;
}
}

#include <ctype.h>
int getch(void);
void ungetch(int);
/* getop: preia urmatorul caracter sau un operand numeric */
int getop(char s[])
{
int i, c, c2;
while ((s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0';
if (!isdigit(c) && c != '.' && c != '-')
return c; /* nu este numar */
i = 0;
if (c == '-') {
c2 = getch();
if (c2 != EOF)
ungetch(c2);
if (!isdigit(c2) && c2 != '.')
return c;
}
if (isdigit(c) || c == '-') /* colecteaza partea intreaga */
while (isdigit(s[++i] = c = getch()))
;
if (c == '.') /* colecteaza partea fractionara */
while (isdigit(s[++i] = c = getch()))
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
return NUMBER;
}
#define BUFSIZE 100

char buf[BUFSIZE]; /* bufer pentru ungetch */


int bufp = 0; /* urmatoarea pozitie libera in buf */
int getch(void) /* preia un posibil caracter pus inapoi */
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
4
void ungetch(int c) /* pune caracterul inapoi in intrare */
{
if (bufp >= BUFSIZE)
printf("ungetch: prea multe caractere\n");
else
buf[bufp++] = c;
}

Aplicație rezolvată 3*. Adăugați programului calculator


comenzi pentru:
 afișarea elementelor din vârful stivei fără a apela
funcția pop,
 duplicarea elementului din vârful stivei,
 interschimbarea cele două elemente din vârful stivei și
 golirea stivei (vezi imaginea).
Descompuneți programul construind un proiect.
#include <stdio.h>
#include <stdlib.h> /* pentru atof() */
#include <math.h>

#define MAXLINE 1000


#define MAXOP 100 /* dimensiunea maxima a unui
operand sau a unui operator */
#define NUMBER '0' /* semnal ca a fost gasit
un numar */

int getop(char []);


void push(double);
double pop(void);
void printtop(void);
void printstiva(void);
void duplicate(void);
void swap(void);
void clear(void);

int main(void)
{
printf("pun -3.981 in stiva\n");
push(-3.981);
printf("\n stiva=\n");
printstiva();
printf("\n pun 44.152 in stiva\n");
push(44.152);
printf("\n stiva=\n");
printstiva();
printf("\n interschimb cele 2 elemente din varful stivei\n");
swap();
printf("\n stiva=\n");
printstiva();
printf("\n duplic elementul din varful stivei\n");
duplicate();
printf("\n stiva=\n");
printstiva();
printf("\n elementul din varful stivei=\n" );printtop();
printf("\n golesc stiva\n" );
clear();
printf("\n elementul din varful stivei=\n" );printtop();
printf("\n stiva=\n");
printstiva();
return 0;
}
#define MAXVAL 100 /* adancimea maxima a stivei */
int sp = 0; /* urmatoarea pozitie libera in stiva */
double val[MAXVAL]; /* stiva cu valori */
5
/* push: pune f pe stiva cu valori */
void push(double f)
{
if (sp < MAXVAL)
val[sp++] = f;
else
printf("error: stack full, can't push %g\n", f);
}

/* pop: scoate si returneaza valoare din varful stivei */


double pop(void)
{
if (sp > 0)
return val[--sp];
else {
printf("error: stack empty\n");
return 0.0;
}
}

/* printtop: afiseaza elementul din varful stivei */


void printtop(void)
{
if (sp > 0)
printf("%g\n", val[sp - 1]);
else
printf("eroare: stiva vida\n");
}
/* printstiva: afiseaza stivei */
void printstiva(void)
{
int i;
if (sp > 0)
for (i = sp - 1; i >= 0; --i)
printf("%g\n", val[i]);
else
printf("eroare: stiva vida\n");
}
/* duplicate: duplica elementul din varful stivei */
void duplicate(void)
{
double top = pop();
push(top);
push(top);
}

/* swap: interschimba cele doua elemente din varful stivei */


void swap(void)
{
double top1 = pop();
double top2 = pop();
push(top1);
push(top2);
}
/* clear: curata stiva */
void clear(void)
{
sp = 0;
}

Aplicație propusă 2*. Adăugați la programul calculator posibilitatea calculării unor funcții precum sinus,
exponențială şi putere pe baza accesului la funcțiile de bibliotecă sin, exp şi pow (pentru ele utilizați
<math.h>). Descompuneți programul construind un proiect.

Indicații: Singurele funcţii care se modifică sunt main şi getop. În plus, apare o constantă MATHLIB pentru a
semnaliza apariția uneia din funcțiile de bibliotecă sin, exp şi pow.
6
#include <math.h>
#include <string.h>
#define MATHLIB '1' /* semnal ca se apeleaza o functie din biblioteca math.h */

int getop(char []);


void push(double);
double pop(void);

int main(void)
{
int type;
double op2;
char s[MAXOP];

while ((type = getop(s)) != EOF) {


switch (type) {
case NUMBER:
push(atof(s));
break;
case MATHLIB:
if (strcmp(s, "sin") == 0)
push(sin(pop()));
else if (strcmp(s, "cos") == 0)
push(cos(pop()));
else if (strcmp(s, "pow") == 0) {
op2 = pop();
push(pow(pop(), op2));
} else
printf("eroare: comanda necunoscuta %s\n", s);
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
op2 = pop();
push(pop() - op2);
break;
case '/':
op2 = pop();
if (op2 != 0.0)
push(pop() / op2);
else
printf("eroare: impartire la zero\n");
break;
case '%':
op2 = pop();
if (op2 != 0.0)
push(fmod(pop(), op2));
else
printf("eroare: impartire la zero \n");
break;
case '\n':
printf("= %g\n", pop());
break;
default:
printf("eroare: comanda necunoscuta %s\n", s);
break;
}
}

return 0;
}
#include <ctype.h>

int getch(void);
7
void ungetch(int);

int getop(char s[])


{
int i, c, c2;

while ((s[0] = c = getch()) == ' ' || c == '\t')


;
s[1] = '\0';

i = 0;
if (isalpha(c)) {
while (isalpha(s[++i] = c = getch()))
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
return MATHLIB;
}

if (!isdigit(c) && c != '.' && c != '-')


return c;
if (c == '-') {
c2 = getch();
if (c2 != EOF)
ungetch(c2);
if (!isdigit(c2) && c2 != '.')
return c;
}
if (isdigit(c) || c == '-')
while (isdigit(s[++i] = c = getch()))
;
if (c == '.')
while (isdigit(s[++i] = c = getch()))
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
return NUMBER;
}

2. Recursivitatea şi preprocesarea
Aplicaţie rezolvată 4. Rulaţi cele două variante de mai jos, ale generării şirului Fibonacci, observând diferenţa
între timpii de execuţie de la cele două variante.

Prima este varianta cu o funcţie recursivă:


#include <stdio.h>

long fibonacci(int);

int main()
{
int n=47, i;

printf("Primii %d termeni ai sirului Fibonacci sunt: \n",n);


for ( i = 0 ; i < n ; i++ )
printf("%d\n", fibonacci(i));
return 0;
}

long fibonacci(int n)
8
{
if ( n == 0 )
return 0;
else if ( n == 1 )
return 1;
else
return ( fibonacci(n-1) + fibonacci(n-2) );
}
A doua este varianta iterativă:
#include<stdio.h>

int main()
{
int n=47, i;
long f1 = 0, f2 = 1, f3;

printf("Primii %d termeni ai sirului Fibonacci sunt: \n",n);


for ( i = 0 ; i < n ; i++ ){
if ( i <= 1 )
f3 = i;
else {
f3 = f1 + f2;
f1 = f2;
f2 = f3;
}
printf("%d\n",f3);
}
return 0;
}

Aplicaţie rezolvată 5. Definiţi un macro swap(t, x, y) care interschimbă două argumente de tipul de dată t.

#include <stdio.h>

#define swap(t, x, y) {t tmp; tmp = x; x = y; y = tmp;}

int main(void)
{
char cx = 'x', cy = 'R';
printf("inainte de interschimbare: %c, %c\n\n", cx, cy);
swap(char, cx, cy)
printf("dupa interschimbare : %c, %c\n\n\n", cx, cy);

int ix = 7, iy = 12;
printf("inainte de interschimbare: %d, %d\n\n", ix, iy);
swap(int, ix, iy)
printf("dupa interschimbare : %d, %d\n\n\n", ix, iy);

double dx = -9.731, dy = 0.257;


printf("inainte de interschimbare: %6g, %6g\n\n", dx, dy);
swap(double, dx, dy)
printf("dupa interschimbare : %6g, %6g\n\n\n", dx, dy);

return 0;
}

9
REZOLVĂRI

Aplicație propusă 2*. Adăugați la programul calculator posibilitatea calculării unor funcții precum sinus,
exponențială și putere pe baza accesului la funcțiile de bibliotecă sin, exp şi pow.
#include <stdio.h>
#include <stdlib.h> /* for atof() */
#include <math.h>
#include <string.h>

#define MAXLINE 1000


#define MAXOP 100 /* max size of operand or operator */
#define NUMBER '0' /* signal that a number was found */
#define MATHLIB '1' /* signal that a library function in math.h was found */

int getop(char []);


void push(double);
double pop(void);

int main(void)
{
int type;
double op2;
char s[MAXOP];

while ((type = getop(s)) != EOF) {


switch (type) {
case NUMBER:
push(atof(s));
break;
case MATHLIB:
if (strcmp(s, "sin") == 0)
push(sin(pop()));
else if (strcmp(s, "cos") == 0)
push(cos(pop()));
else if (strcmp(s, "pow") == 0) {
op2 = pop();
push(pow(pop(), op2));
} else
printf("error: unknown command %s\n", s);
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
op2 = pop();
push(pop() - op2);
break;
case '/':
op2 = pop();
if (op2 != 0.0)
push(pop() / op2);
else
printf("error: zero divisor\n");
break;
case '%':
op2 = pop();
if (op2 != 0.0)
push(fmod(pop(), op2));
else
printf("error: zero divisor\n");
break;
case '\n':
printf("= %g\n", pop());
break;
10
default:
printf("error: unknown command %s\n", s);
break;
}
}

return 0;
}

#define MAXVAL 100 /* maximum depth of val stack */

int sp = 0; /* next free stack position */


double val[MAXVAL]; /* value stack */

/* push: push f onto value stack */


void push(double f)
{
if (sp < MAXVAL)
val[sp++] = f;
else
printf("error: stack full, can't push %g\n", f);
}

/* pop: pop and return top value from stack */


double pop(void)
{
if (sp > 0)
return val[--sp];
else {
printf("error: stack empty\n");
return 0.0;
}
}

#include <ctype.h>

int getch(void);
void ungetch(int);

/* getop: get next character or numeric operand */


int getop(char s[])
{
int i, c, c2;

while ((s[0] = c = getch()) == ' ' || c == '\t')


;
s[1] = '\0';

i = 0;
if (isalpha(c)) {
while (isalpha(s[++i] = c = getch()))
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
return MATHLIB;
}

if (!isdigit(c) && c != '.' && c != '-')


return c; /* not a number */

if (c == '-') {
c2 = getch();
if (c2 != EOF)
ungetch(c2);
if (!isdigit(c2) && c2 != '.')
return c;
}

11
if (isdigit(c) || c == '-') /* collect integer part */
while (isdigit(s[++i] = c = getch()))
;
if (c == '.') /* collect fraction part */
while (isdigit(s[++i] = c = getch()))
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
return NUMBER;
}

#define BUFSIZE 100

char buf[BUFSIZE]; /* buffer for ungetch */


int bufp = 0; /* next free position in buf */

int getch(void) /* get a (possibly pushed-back) character */


{
return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c) /* push character back on input */


{
if (bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}

12

S-ar putea să vă placă și