// primer contacte, part 2

Primers passos en C (II)

Llegir dades amb scanf(), nombres amb decimals i la biblioteca math.h, i com formatar la sortida — encara sense condicionals ni bucles.

Llegint dades de l'usuari: scanf()

Igual que printf() escriu amb un especificador de format per variable, scanf() en fa servir els mateixos per llegir-les — però amb una diferència important: cal el caràcter & davant del nom de la variable (excepte per a cadenes, com veurem).

Exemple

int edat;
printf("Quants anys tens? ");
scanf("%d", &edat);

&edat vol dir "l'adreça de memòria d'edat": scanf() necessita saber on ha de desar el valor llegit, no el valor en si mateix.

El parany del buffer

Quan prems Intro després d'escriure un número, aquest salt de línia (\n) es queda esperant al buffer del teclat. %d el salta automàticament, però %c no — llegeix literalment el primer caràcter que troba.

El problema

int edat;
char inicial;
scanf("%d", &edat);      // l'usuari escriu 16 i prem Intro
scanf("%c", &inicial);   // llegeix el '\n' pendent, no la lletra!

El programa mai arriba a esperar que escriguis la lletra: es queda amb el salt de línia que ja hi havia. Ho veuràs en detall a la pestanya d'execució.

La solució

scanf(" %c", &inicial);   // l'espai davant de %c salta qualsevol blanc pendent

Un espai en blanc dins del format de scanf() (excepte davant de %c) ja es salta sol; aquí l'afegim expressament per forçar-ho abans de llegir el caràcter.

Cadenes de caràcters, de moment senzilles

En C encara no hi ha un tipus "text" com str en Python: una cadena és una taula (array) de caràcters. De moment en farem prou amb l'ús bàsic, sense entrar en com funcionen les taules.

char nom[30];              // espai per fins a 29 caràcters + el final
printf("Com et dius? ");
scanf("%s", nom);          // sense & !

Amb %s no es posa & davant del nom: una taula ja es comporta com una adreça de memòria. Compte: %s s'atura al primer espai, així que noms compostos ("Sant Cugat") es tallarien pel mig — és un límit que superarem més endavant.

Nombres amb decimals: double i <math.h>

Per a càlculs amb decimals que necessiten precisió, double és el tipus habitual (més precís que float). La biblioteca <math.h> hi afegeix funcions com sqrt(), pow(), log()...

Exemple

#include <stdio.h>
#include <math.h>

int main() {
    double x = 4.0;

    printf("L'arrel de %.2f és %.2f\n", x, sqrt(x));

    return 0;
}

Important: per compilar un programa que fa servir <math.h> cal afegir l'opció -lm: gcc programa.c -o programa -lm. Sense aquesta opció el compilador no trobarà les funcions matemàtiques.

Formatar la sortida

Dos recursos molt habituals: \t (tabulador, per alinear en columnes) i %.2f (decimals amb precisió fixa).

printf("x\tx^2\tsqrt(x)\n");
printf("%.2f\t%.2f\t%.2f\n", x, x*x, sqrt(x));

El número entre el punt i la f indica quants decimals es mostren. Sense el .2, printf en mostraria 6 per defecte.

Taula de referència: seqüències d'escapament
CodiSignificatCodiSignificat
\nnova línia\ttabulador horitzontal
\rretorn de carro\\diagonal invertida
\'cometa simple\"cometa doble
\acaràcter d'alarma\0caràcter nul (final de cadena)
Taula de referència: especificadors de format
CodiTipusÚs habitual
%dintenter amb signe
%ffloat / doubledecimal (amb scanf, double necessita %lf)
%ccharun sol caràcter
%schar[]cadena (sense espais amb scanf)

bonus C++: cout i cin

C++ és un superconjunt de C i permet fer entrada/sortida d'una altra manera, amb els objectes cout i cin (de la biblioteca <iostream>). No és el focus d'aquest curs, però val la pena saber que existeix.

#include <iostream>
using namespace std;

int main() {
    int edat;

    cout << "Quants anys tens? ";
    cin >> edat;
    cout << "Tens " << edat << " anys" << endl;

    return 0;
}

Amb << (operador d'inserció) envies dades a la pantalla i amb >> (operador d'extracció) en llegeixes del teclat — sense especificadors de format com %d. Els fitxers C++ acaben en .cc en lloc de .c.

Mira el programa executar-se pas a pas

Encara de dalt a baix, sense condicions ni bucles — però ara amb entrada de l'usuari simulada.

Entrada de dades

Sortida i format

Codi

Variables

NomValor

Terminal

Pas 1 / 1

Exercicis

Aquí no hi ha solució ni comprovació automàtica: són per escriure, compilar i provar tu mateix.

1. Municipi i codi postal

Fes un programa que demani el nom d'un municipi, un caràcter qualsevol i el seu codi postal, i després mostri les tres dades juntes en una sola línia.

Necessitaràs %s per al nom, %c per al caràcter i %s per al codi postal (amb %d es perdria el primer zero d'un codi com 08037). Pensa on pot caldre un espai davant de %c.

2. Resistències en paral·lel

Calcula la resistència equivalent de dues resistències en paral·lel: Req = (R1 · R2) / (R1 + R2). Demana R1 i R2 com a double.

Compte amb la jerarquia d'operadors: R1*R2/(R1+R2) no és el mateix que R1*R2/R1+R2.

3. Fahrenheit a Celsius

Demana una temperatura en graus Fahrenheit i mostra l'equivalent en graus Celsius, amb la fórmula C = (F − 32) / 1.8.

Totes dues variables han de ser double perquè el resultat tingui decimals.

4. Taxa Anual Equivalent (TAE)

Donat un interès nominal anual i (per exemple 0.05) i un nombre de pagaments n (per exemple 12), calcula la TAE amb la fórmula TAE = (1 + i/n)n − 1.

Per elevar a una potència fes servir pow(base, exponent) de <math.h> (i recorda compilar amb -lm).

5. Mitjana de tres nombres

Demana tres nombres reals i mostra'n la mitjana aritmètica.

Pots llegir els tres alhora amb una sola crida: scanf("%f %f %f", &a, &b, &c); — separa'ls amb espais en escriure'ls.

6. Equació de segon grau

Demana els coeficients a, b i c d'una equació ax² + bx + c = 0 i calcula les seves dues solucions amb la fórmula general. Encara no cal comprovar si l'equació té solució real.

disc = b*b - 4*a*c;
x1 = (-b + sqrt(disc)) / (2*a);
x2 = (-b - sqrt(disc)) / (2*a);
Recorda: la funció principal sempre és int main(), no void main().