Iniciando en C - Parte 1

5 de Mayo de 2024 - ed. hace: 5 meses, 2 semanas


Introducción al lenguaje de programación C, Primera parte. El contenido de este post es una traducción al idioma español de la pagina w3schools.com/c la cual solo se encuentra disponible en inglés


Que es C

C es un lenguaje de programación de proposito general, creado por Dennis Ritchie en los laboratorios Bell en 1972

Es un lenguaje muy popular, a pesar de ser antiguo. La razón principal es por ser un lenguaje fundamental en el campo de las ciencias de la computación.

C está fuertemente relacionado con UNIX, ya que fue desarrollado para escribir este sistema operativo.

¿Por qué aprender C?

  • Es uno de los lenguajes mas populares del mundo
  • Si sabes C, no tendras problemas en aprender otros lenguajes populares como Java, Python, C++, C#, etc, ya que la sintaxis es similar
  • C es muy rápido, comparado con otros lenguajes de programación como Java and Python
  • C es muy versatil; puede ser usado en tecnologías y aplicaciones

Comenzando con C

Para comenzar a utlizar C se necesitan dos cosas:

  • Un editor de texto para escribir el código (vim, notepad, etc)
  • Un compilador, como GCC, para traducir el código C en un lenguaje que la computadora pueda entender

Tipos de datos

Tipo Tamaño
int 2 o 4 bytes
float 4 bytes
double 8 bytes
char 1 byte
bool 1 byte (<stdbool.h>)

Inicio rápido en C

#include <stdio.h>

// funcion main (principal)
int main(){
    printf("Hola Pianola!");
    return 0;
}

/* 
 Comentario
 Multilinea
*/
  • Linea 1: #include <stdio.h> es un ecabezado de librería que nos permite trabajar con funciones de entrada y salida (input & output), como printf() (utilizada en la linea 5). Estos encabezados añaden funcionalidad a los programas en C, al indicar que librerias se van a utilizar

  • Linea 3: Comentarios de una linea //

  • Linea 4: Otra cosa que siempre aparece en programas escritos en C es main(). Este es llamado función. Cualquier código dentro de los 'corchetes {} será ejecutado

  • Linea 5: printf() es una funcion que se utiliza para imprmir texto en la salida standar del terminal (output)

  • Linea 6: return 0 termina la función main()

  • Linea 7: No olvidar agregar el 'corchete' de cierre } para cerrar la función main

  • Line 9: Comentarios multilinea /* ... */


Compilar y ejecutar programa en C

gcc -o mi_primer_programa mi_primer_programa.c

./mi_primer_programa

Script

Script para compilar y ejecutar código C en linux, wsl o cualquier terminal con bash

#!/usr/bin/env bash

WORKDIR="$(pwd)"

# Compilar y ejecutar programa en C en directorio ./out/
function runc() {
    [[ -d ${WORKDIR}/out ]] || mkdir "${WORKDIR}/out"
    gcc -o "./out/${1%%.c}" "${1}" && ./out/"${1%%.c}"
}

"$@"

Primeros programas

runc mi_primer_programa.c
Hola Pianola!

Imprimiendo variables

Tipo Formato
int %d o %i
float %F o %f, %.1f, ...
double %lf
char %c
long unsigned %lu
strings %s
bool %d (<stdbool.h>)
Caracter Unicode
á \u00e1
é \u00e9
í \u00ed
ó \u00f3
ú \u00fa
ñ \u00f1
#include <stdio.h>

// función principal
int main(){
    int x = 5, y = 3;
    printf("%d + %d = %d", x, y, x+y);
    return 0;
}
runc print_vars.c
5 + 3 = 8

Conversión


Conversión implícita

Esta es realizada automáticamente por el compilador cuando se asigna un valor de un tipo a otro. Por ejemplo, si se asigna un valor int a una variable float. En este caso el valor mostrado sería 9.000000.

Esto es riesgoso, se puede perder control sobre valores específicos en algunas situaciones. Especialmente en el caso contrario del ejemplo, el valor entero de 9.99 es 9

Conversión explícita

Esta es realizada de forma manual usando el tipo entre () antes del valor

float sum = (float) 5/2;
printf("%f", sum); // 2.500000

O al frente de la variable

int x = 5, y = 2;
float sum = (float) x / y;
printf("%f", sum); // 2.500000

If else

#include <stdio.h>

int mi_edad = 25;
int edad_votar = 18;

int main(){
    if (mi_edad >= edad_votar) {
        printf("Edad suficiente para votar!\n");
    } else {
        printf("Edad insuficiente para votar!\n");
    }
    return 0;
}

Operador Ternario

Existe un 'atajo' para if-else conocido como operador ternario porque es consistente con los tres operandos. Puede ser usado para reemplazar múltiples lineas de código con una sola. A menudo es usada para reemplazar sentencias if-else

variable = (condition) ? expression_True : expression_False;

Ejemplo

int time = 20;
if (time < 18){
    printf("Buen dia.");
} else {
    printf("Buena tarde");
}

Se puede simplemente escribir:

int time = 20;
(time < 18) ? printf("Buen dia.") : printf("Buena tarde");
}

else if

#include <stdio.h>

int main(){
    int num = 10; // Es un numero positovo o negativo

    if (num > 0) {
      printf("El valor es un numero positivo\n");
    } else if (num < 0) {
      printf("El valor es un numero negativo\n");
    } else {
      printf("El valor es 0\n");
    }

    return 0;
}


Sentencia Switch

En lugar de escribir varias sentencias if-else, se puede usar la sentencia switch. Esta selecciona uno de muchos bloques de código posibles para ser ejecutado

switch (expresion) {
  case x:
    // bloque de códidgo
    break;
  case y:
    // bloque de códidgo
    break;
  default:
    // bloque de códidgo
}

Ejemplo

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(){
    srand(time(NULL));
    int day = 1+rand() % 10;
    switch (day) {
        case 1:
            printf("Lunes\n");
            break;
        case 2:
            printf("Martes\n");
            break;
        case 3:
            printf("Miercoles\n");
            break;
        case 4:
            printf("Jueves\n");
            break;
        case 5:
            printf("Viernes\n");
            break;
        case 6:
            printf("Sabado\n");
            break;
        case 7:
            printf("Domingo\n");
            break;
        default:
            printf("Dia invalido: %d\n", day);
    }

    return 0;
}

While

Mientras

Sintaxis

while (condicion){
    ...
}

Ejemplo

int i = 0;
while (condicion){
    printf("%d\n", i);
    i++;
}

Do While

Hacer mientras

Sintaxis

do {
    ...
} while (condicion);

Ejemplo

int i = 0;

do {
    printf("%d\n", i);
    i++;
} while (i < 5);

Ejemplos

int countdown = 3;

while (countdown > 0){
    printf("%d\n", countdown);
    countdown--;
}

printf("Feliz año nuevo!!\n");
int dice = 1;

while (dice <= 6){
    if (dice < 6){
        printf("No Yatzy\n");
    } else {
        printf("Yatzy!\n");
    }
    dice = dice+1;
}

For

for(expresion 1; expresion 2; expresion 3){
    ...
}
int x;

for(x = 0; x < 5; x++){
    printf("%d\n", x);
}

printf("\n");

int i,j;

for(i = 0; i <= 2; ++i){
    printf("\nExterno: %d\n", i);

    for(j = 0; j <= 3; ++j){
        printf("Interno: %d\n", j);
    }
}

printf("\n");

for(i = 0; i <= 10; i = i + 2){
    printf(" %d ", i);
}

printf("\n\n");

int numero = 2;
for(i = 1; i <= 10; i++){
    printf("%d x %d = %d\n", numero, i, numero * i);
}

printf("\n");

for(i=0;i<10;i++) {
    if (i % 2 == 0){
        printf("%d, continuar\n", i);
        continue;
    }
    if (i == 5){
        printf("%d, detener\n", i);
        break;
    }
}

Arreglos

Los arreglos (arrays) son utilizados para almacenar múltiples valores en una sola variable, en lugar de declarar variables diferentes para cada valor

Para crear un arreglo, se define el tipo de dato (ej. int) y se especifica el nombre del arreglo seguido de paréntesis cuadrados []

Para insertar valores en el, se usa una lista separada por comas, dentro de {}

int numeros[] = { 25, 50, 75, 100};

printf("%d", numeros[0]);
// salida 25

numeros[0] = 33;
printf("%d", numeros[0]);
// salida 33

Establecer el tamaño del arreglo

int numeros[4];
int numeros[] = {10, 15, 20 ,25, 100};
unsigned long peso = sizeof(numeros);
int largo = peso/sizeof(numeros[0]);

printf("Peso del array 'numeros': %lu bytes\n", peso);
printf("Tamaño del array 'numeros': %d\n", largo);

int i;

for(i = 0; i < largo; i++){
    printf("%d\n", numeros[i]);
}

return 0;

Ejemplo

    int edades[] = {20, 22, 18, 35, 48, 26, 87, 70};
    float prom, sum = 0;
    int i;

    int largo = sizeof(edades) / sizeof(edades[0]);

    for(int i = 0; i < largo; i++){
        sum += edades[i];
    }

    prom = sum / largo;

    printf("El promedio de edades es: %.2f\n", prom);
    // El promedio de edades es: 40.75

    int menor_edad = edades[0];

    for(int i=0; i<largo; i++){
        if(menor_edad > edades[i]){
            menor_edad = edades[i];
        }
    }
    printf("\nLa edad menor es: %d\n", menor_edad);

Arreglos mutlidimensionales

Array de arrays

2D Arrays

int matrix[2][3] = { {1, 4, 2}, {3, 6, 8} };

Representación

Col 0 Col 1 Col 2
Fila 0 1 4 2
Fila 1 3 6 8

Recorriendo Array 2D

int matrix[2][3] = { {1, 4, 2}, {3, 6, 8} };

int i, j;
for(i = 0; i < 2; i++){
    for(j = 0; j < 3; j++){
        printf("%d\n", matrix[i][j]);
    }
}

Strings

Cadenas de texto

char saludo[] = "Hola Mundo!";

printf("%s\n", saludo);

printf("%c\n", saludo[0]);

saludo[0] = 'h';
printf("%s\n", saludo);

int i;
int largo = sizeof(saludo) / sizeof(saludo[0]);

for(i=0; i<11; ++i){
    printf("%c\n", saludo[i])
}

Otra forma de crear strings

char saludo[] = {'H','o','l','a',' ','M','u','n','d','o','\0'}
printf("%s\n", saludo);
char alfabeto[] = "ABCDEFGHIJKLMÑOPQRSTUVWXYZ";
printf("%d\n", strlen(alfabeto));
printf("%d\n", sizeof(alfabeto));

char alfabeto2[50] = "ABCDEFGHIJKLMÑOPQRSTUVWXYZ";
printf("%d\n", strlen(alfabeto2));
printf("%d\n", sizeof(alfabeto2));

Caracteres de escape

Escape Resultado
\' '
\" "
\\ \
\n nueva linea
\0 null

Concatenar strings

char str1[20] = "Hola";
char str2[] = "Mundo!";

strcat(str1, str2);

printf("%s\n", str1);

Copy String

char str3[20] = "Hola Mundo!";
char str4[20];

strcpy(str4, str3);

printf("\n%s\n", str4);

Comparar String

Requier librería string.h

char str5[] = "Hola";
char str6[] = "Hola";
char str7[] = "Eh";
// Compara str5 y str6, e imprime el resultado
printf("\n%d\n", strcmp(str5, str6));  // Devuelve 0 (los strins son iguales)
// Compara str5 y str7, e imprime el resultado
printf("%d\n", strcmp(str5, str7));  // Devuelve 3 (los strings son distintos)

Entradas de usuario

int num;

printf("Ingresa un número: \n");
scanf("%d", &num);
printf("%d\n", num);

Múltiples entradas

int num_2;
char char_1;

printf("Ingresa un número y una letra: \n");
scanf("%d %c", &num_2, & char_1);
printf("El número es %d\n", num_2);
printf("El caracter es %c\n", char_1);
char nombre[30];
printf("\nIngresa tu primer nombre: \n");
scanf("%s", nombre);
printf("Hola %s\n", nombre);

scanf tiene la limitación de que considera espacio, tab, etc. como final del string

char nombre_completo[30];
printf("\nIngresa tu nombre y apellido: \n");
scanf("%s", nombre_completo);
printf("Hola %s\n", nombre_completo);

Para evitar inconvenientes se utiliza la función fgets() para leer una linea de texto. Se debe incluir el nombre de la variable, sizeof y stdin

char nombre_full[50];

printf("Ingresa tu nombre completo: \n");
fgets(nombre_full, sizeof(nombre_full), stdin);

printf("Hola %s", nombre_full);

Dirección de memoria - Punteros


Creando punteros

int edad = 43;
printf("El valor de var edad: %d\n", edad);
printf("La dirección en memoria de var edad: %p\n", &edad);
  • Un puntero es una variable que almacena la dirección en memoria de otra variable como valor
  • Una variable puntero apunta a un tipo de dato (como int) del mismo tipo, y es creada con el operador *
  • La dirección de la variable con la que se trabaja es asignada al puntero
int mi_edad = 43;     // Una variable entera
int* ptr = &mi_edad;  // Una variable puntero, de nombre ptr
// que almacena la dirección de 'mi_edad'

// Valor de mi_edad
printf("%d\n", mi_edad);

// Dirección en memoria de mi_edad
printf("%p\n", &mi_edad);

printf("Referencia: ");
printf("La direccion en memoria de var en var puntero : %p\n", ptr);

printf("Desreferenciación: ");
printf("El valor de la variable en la dirección del puntero: %d\n", *ptr);

Nota el signo * puede ser confuso ya que tiene 2 significados diferentes aquí:

  • Cuando es usado en una declaración int* ptr, crea una variable puntero
  • Cuando no es usado en una declaración, actúa como operador de desreferenciación

Existen 2 formas de declarar variables puntero en C:

  • int* mi_edad;
  • int *mi_edad;

Los punteros son una de las principales diferencias que destaca en C sobre otros lenguajes como Python y Java.

Son importantes porque nos permiten manipular los datos en la memoria del computador. Esto puede reducir el código y mejorar el rendimiento. Si estas familiarizado con las estructuras de datos como listas, árboles y grafos, deberias saber que los punteros son especialmente utiles en estas implementaciones. En incluso en ocasiones deberás usar punteros para trabajar, por ejemplo, con archivos.

Pero ten cuidado, los punteros deben manejarse con precaución, ya que, es posible dañar los datos almacenados en direcciones de memoria.


Punteros y arreglos

int numeros[4] = {25, 50, 75, 100};
int i;

for(i=0; i<4; i++){
    printf("%d\n", numeros[i]);
}

printf("\nAhora en vez de imprimir los valores, "
       "se imprimen las direcciones en memoria\n");
for(i=0; i<4; i++){
    printf("%p\n", &numeros[i]);
}

Notar que los últimos números de cada dirección de memoria es diferente, se agregan 4. Esto es porque el tamaño de un int es típicamente 4 bytes.

Recuerda: int mi_entero; printf("%lu", sizeof(mi_entero));, imprime 4 y printf("%lu", sizeof(numeros)); imprime 16.


Como se relacionan los punteros con los arrays

En C el nombre de un array es realmente un puntero al primer elemento de este

La dirección de memoria del primer elemento del array es la misma que la del nombre del array

// Obtener la dirección en memoria del array
printf("%p\n", numeros);

// Obtener la dirección en memoria del primer elemento del array
printf("%p\n", &numeros[0]);

Ambas salidas imprimen el mismo valor

Esto significa que se puede trabajar con arrays a travez de punteros, utilizando el operador *

// Obtener el primer elemento de 'numeros'
printf("%d", *numeros);
// Obtener el segundo elemento de 'numeros'
printf("%d", *(numeros+1);
// Obtener el tercer elemento de 'numeros'
printf("%d", *(numeros+2);
// ...etc
// Usando un ciclo y punteros
int *ptr2 = numeros;
for(i=0; i<4; i++){
    printf("%d  ", *(ptr2 + i));
}
// Cambiando valores de elementos usando punteros
*numeros = 13;
*(numeros+1) = 17;
printf("%d ", *numeros);
printf("%d\n\n", *(numeros+1));

Esta forma de trabajar con arrays pareciera ser un poco excesiva. Especialmente con arreglos simples como los usados en los ejemplos. Sin embargo, para arreglos largos, puede ser mucho mas eficiente acceder y manipularlos con punteros.

Además es considerado mas rápido y fácil acceder a arreglos bidimensionales con punteros.

Ya que los strings son realmente arreglos, puedes usar punteros para acceder a ellos.



Iniciando en C



Tags

  • Categoría(s):
  • Desarrollo

  • Volver al blog