C/C++

Tema 2 · Variables, tipus, operadors

Introducció

Tot programa necessita emmagatzemar dades. En C, les variables són contenidors amb un tipus definit (enter, decimal, caràcter...). Amb scanf() podem llegir dades de l'usuari i amb printf() les mostrem per pantalla.

Objectius

  • Declarar variables dels tipus int, float, char
  • Utilitzar scanf() per llegir dades del teclat
  • Mostrar resultats amb printf() i caràcters de format
  • Dissenyar un petit conversor d'ADN a ARN

Variables i entrada/sortida

Exemple bàsic amb diferents tipus de dades:

#include <stdio.h>

int main() {
    int edat = 20;
    float pes = 65.5;
    char grup_sanguini = 'A';

    printf("Edat: %d anys\n", edat);
    printf("Pes: %.1f kg\n", pes);
    printf("Grup sanguini: %c\n", grup_sanguini);

    return 0;
}
%d = enter, %f = float, %c = char

Ara llegim dades des del teclat amb scanf():

#include <stdio.h>

int main() {
    char base_nitrogenada;

    printf("Introdueix una base (A, C, G, T): ");
    scanf(" %c", &base_nitrogenada);  // l'espai abans de %c evita problemes

    printf("Has introduït: %c\n", base_nitrogenada);

    return 0;
}
Recorda: & davant la variable en scanf()

Tipus primitius en profunditat

El llenguatge C disposa de diversos tipus primitius per emmagatzemar nombres enters, decimals i caràcters. A més, podem saber quanta memòria ocupa cada variable mitjançant l'operador sizeof(), que retorna el nombre de bytes. Per imprimir aquest valor fem servir el format %zu.

#include <stdio.h>
#include <stdbool.h>

int main() {

    char inicial = 'F';
    unsigned char lletra = 'A';

    short any = 2025;
    int edat = 16;
    long poblacio = 8000000;
    long long estrelles = 900000000000LL;

    float nota = 8.5f;
    double pi = 3.14159265359;
    long double precisio = 3.14159265359L;

    bool aprovat = true;
    bool suspes = false;

    // Mostra els valors
    printf("char = %c\n", inicial);
    printf("unsigned char = %c\n", lletra);

    printf("short = %d\n", any);
    printf("int = %d\n", edat);
    printf("long = %ld\n", poblacio);
    printf("long long = %lld\n", estrelles);

    printf("float = %.1f\n", nota);
    printf("double = %.10f\n", pi);
    printf("long double = %.10Lf\n", precisio);

    printf("aprovat = %d\n", aprovat);
    printf("suspes = %d\n", suspes);

    if(aprovat){
        printf("L'alumne ha aprovat\n");
    }

    if(!suspes){
        printf("L'alumne no ha suspes\n");
    }

    // Mostra les mides amb sizeof i %zu
    printf("\n--- Mides en bytes ---\n");
    printf("sizeof(char)         = %zu\n", sizeof(inicial));
    printf("sizeof(unsigned char)= %zu\n", sizeof(lletra));
    printf("sizeof(short)        = %zu\n", sizeof(any));
    printf("sizeof(int)          = %zu\n", sizeof(edat));
    printf("sizeof(long)         = %zu\n", sizeof(poblacio));
    printf("sizeof(long long)    = %zu\n", sizeof(estrelles));
    printf("sizeof(float)        = %zu\n", sizeof(nota));
    printf("sizeof(double)       = %zu\n", sizeof(pi));
    printf("sizeof(long double)  = %zu\n", sizeof(precisio));
    printf("sizeof(bool)         = %zu\n", sizeof(aprovat));

    return 0;
}
Observa que %zu és el format per a size_t (resultat de sizeof)

Explicació

  • Tipus enters: char (1 byte), short (2), int (4), long (4 o 8 segons plataforma), long long (8). Els unsigned no tenen signe.
  • Tipus reals: float (4), double (8), long double (8, 12 o 16 segons plataforma).
  • Booleans: bool (1 byte) amb valors true (1) o false (0).
  • sizeof és un operador que es calcula en temps de compilació i retorna el nombre de bytes.

Formats per a floats: amplada i precisió

Quan imprimim nombres decimals amb printf(), podem controlar el nombre de decimals (precisió) i l'amplada mínima total del camp. A continuació es mostren els formats més habituals:

#include <stdio.h>

int main() {
    float nota = 8.5f;
    double pi = 3.14159265359;

    printf("Valor original de nota (float): %f\n", nota);
    printf("Amb 3 decimals (%.3f): %.3f\n", nota, nota);
    printf("Amplada mínima 3 sense decimals (%3.f): %3.f\n", nota, nota);
    printf("Amplada 6 i 2 decimals (%6.2f): %6.2f\n", nota, nota);
    printf("Amplada 3 i 3 decimals (%3.3f): %3.3f\n", nota, nota);
    printf("Només amplada sense punt (%3f): %3f\n", nota);  // %3f = amplada 3, decimals per defecte (6)

    printf("\nPer a double (pi):\n");
    printf("Sense formatar: %f\n", pi);
    printf("Amb 5 decimals: %.5f\n", pi);
    printf("Amplada 10 i 4 decimals: %10.4f\n", pi);

    return 0;
}

Què significa cada format?

  • %f → 6 decimals per defecte.
  • %.nfn decimals. Ex: %.3f → 3 decimals.
  • %m.f → amplada mínima m (inclou el signe, el punt i els decimals). Si el nombre ocupa menys, s'omple amb espais a l'esquerra. Ex: %6.2f → mínim 6 caràcters, 2 decimals.
  • %m.f sense precisió (ex: %3.f) equival a %3.0f (0 decimals).
  • %mf (sense punt) → amplada mínima m, però la precisió es manté a 6 decimals. Ex: %3f → amplada 3, 6 decimals.
  • Important: %f3 no és vàlid; el compilador ho interpreta com %f seguit del caràcter '3' literal.

Exemple de sortida (per al primer bloc):

Valor original de nota (float): 8.500000
Amb 3 decimals (%.3f): 8.500
Amplada mínima 3 sense decimals (%3.f):   9
Amplada 6 i 2 decimals (%6.2f):   8.50
Amplada 3 i 3 decimals (%3.3f): 8.500
Només amplada sense punt (%3f): 8.500000

Operadors en C

Els operadors ens permeten realitzar càlculs, comparacions i decisions lògiques. A continuació es mostra un programa que utilitza tots els grups principals: aritmètics, d'assignació, increment/decrement, relacionals, lògics i, per a nivells més avançats, operadors de bits.

#include <stdio.h>
#include <stdbool.h>

int main() {
    // 1. Operadors aritmètics
    int a = 10, b = 3;
    printf("--- Aritmètics ---\n");
    printf("a + b = %d\n", a + b);
    printf("a - b = %d\n", a - b);
    printf("a * b = %d\n", a * b);
    printf("a / b = %d (divisió entera)\n", a / b);
    printf("a %% b = %d (mòdul)\n", a % b);

    // 2. Operadors d'assignació
    int c = 5;
    printf("\n--- Assignació ---\n");
    printf("c = %d\n", c);
    c += 3;  // c = c + 3
    printf("c += 3 -> c = %d\n", c);
    c -= 2;  // c = c - 2
    printf("c -= 2 -> c = %d\n", c);
    c *= 2;  // c = c * 2
    printf("c *= 2 -> c = %d\n", c);
    c /= 3;  // c = c / 3
    printf("c /= 3 -> c = %d\n", c);
    c %= 4;  // c = c % 4
    printf("c %%= 4 -> c = %d\n", c);

    // 3. Increment i decrement
    int d = 7;
    printf("\n--- Increment / Decrement ---\n");
    printf("d = %d\n", d);
    printf("d++ (post-increment) = %d, després d = %d\n", d++, d);
    printf("++d (pre-increment) = %d, després d = %d\n", ++d, d);
    printf("d-- (post-decrement) = %d, després d = %d\n", d--, d);
    printf("--d (pre-decrement) = %d, després d = %d\n", --d, d);

    // 4. Operadors relacionals (comparació)
    int x = 8, y = 12;
    printf("\n--- Relacionals ---\n");
    printf("x = %d, y = %d\n", x, y);
    printf("x == y -> %d\n", x == y);
    printf("x != y -> %d\n", x != y);
    printf("x > y  -> %d\n", x > y);
    printf("x < y  -> %d\n", x < y);
    printf("x >= y -> %d\n", x >= y);
    printf("x <= y -> %d\n", x <= y);

    // 5. Operadors lògics
    bool p = true, q = false;
    printf("\n--- Lògics ---\n");
    printf("p = %d, q = %d\n", p, q);
    printf("p && q  -> %d (AND)\n", p && q);
    printf("p || q  -> %d (OR)\n", p || q);
    printf("!p      -> %d (NOT)\n", !p);
    printf("(x > 5) && (y < 15) -> %d\n", (x > 5) && (y < 15));

    // 6. Operadors de bits (avançat)
    unsigned int mask = 0x0F;  // 0000 1111
    unsigned int valor = 0x3A; // 0011 1010
    printf("\n--- Bits (avançat) ---\n");
    printf("mask = 0x%X, valor = 0x%X\n", mask, valor);
    printf("valor & mask  = 0x%X (AND)\n", valor & mask);
    printf("valor | mask  = 0x%X (OR)\n", valor | mask);
    printf("valor ^ mask  = 0x%X (XOR)\n", valor ^ mask);
    printf("~valor        = 0x%X (NOT)\n", ~valor);
    printf("valor << 2    = 0x%X (desplaçament esquerra)\n", valor << 2);
    printf("valor >> 1    = 0x%X (desplaçament dreta)\n", valor >> 1);

    return 0;
}

Explicació de cada grup

  • Aritmètics: + - * / % (suma, resta, multiplicació, divisió entera, mòdul).
  • Assignació: = i les variants +=, -=, *=, /=, %= (operació i assignació en un sol pas).
  • Increment / Decrement: ++ (augmentar 1), -- (disminuir 1).
    Pre (++x) primer canvia el valor i després l'utilitza; post (x++) primer l'utilitza i després canvia.
  • Relacionals (comparació): ==, !=, >, <, >=, <= retornen 1 (cert) o 0 (fals).
  • Lògics: && (AND), || (OR), ! (NOT). S'usen per combinar condicions.
  • Bits (avançat): & (AND), | (OR), ^ (XOR), ~ (NOT), << (desplaçament esquerra), >> (desplaçament dreta). Treballen a nivell de bits, útil per a màscares i optimitzacions.

En C, el resultat d'una comparació o operació lògica és int (1 o 0), però es pot assignar a bool si s'inclou <stdbool.h>.

Exercicis

  1. Declara una variable int per a l'edat d'un pacient i mostra-la amb printf().
  2. Llegeix el nom del mateix gen del tema 1 (cadena de text) amb scanf() i imprimeix-lo.
  3. Escriu un programa que demani el %GC d'una seqüència (float) corresponent al teu gen anterior i el mostri amb dos decimals.
  4. Fes un programa que, donats dos enters, mostri la suma, la resta, el producte, la divisió entera i el mòdul.

Mini Projecte – Conversor ADN → ARN

Crea un programa que lligi una base nitrogenada d'ADN (A, C, G, T) i mostri la base complementària d'ARN:

  • A (ADN) → U (ARN)
  • CG
  • GC
  • TA

Després amplia el programa per a convertir una seqüència sencera de 3 bases (ex: "ATG" → "UAC").