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
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.
Para comenzar a utlizar C se necesitan dos cosas:
Tipo | Tamaño |
---|---|
int |
2 o 4 bytes |
float |
4 bytes |
double |
8 bytes |
char |
1 byte |
bool |
1 byte (<stdbool.h> ) |
#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 /* ... */
gcc -o mi_primer_programa mi_primer_programa.c
./mi_primer_programa
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}"
}
"$@"
runc mi_primer_programa.c
Hola Pianola!
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
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
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
#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;
}
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");
}
#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;
}
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;
}
Mientras
while (condicion){
...
}
int i = 0;
while (condicion){
printf("%d\n", i);
i++;
}
Hacer mientras
do {
...
} while (condicion);
int i = 0;
do {
printf("%d\n", i);
i++;
} while (i < 5);
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(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;
}
}
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
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;
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);
Array de arrays
int matrix[2][3] = { {1, 4, 2}, {3, 6, 8} };
Col 0 | Col 1 | Col 2 | |
---|---|---|---|
Fila 0 | 1 | 4 | 2 |
Fila 1 | 3 | 6 | 8 |
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]);
}
}
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));
Escape | Resultado |
---|---|
\' |
' |
\" |
" |
\\ |
\ |
\n |
nueva linea |
\0 |
null |
char str1[20] = "Hola";
char str2[] = "Mundo!";
strcat(str1, str2);
printf("%s\n", str1);
char str3[20] = "Hola Mundo!";
char str4[20];
strcpy(str4, str3);
printf("\n%s\n", str4);
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)
int num;
printf("Ingresa un número: \n");
scanf("%d", &num);
printf("%d\n", num);
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);
int edad = 43;
printf("El valor de var edad: %d\n", edad);
printf("La dirección en memoria de var edad: %p\n", &edad);
int
) del mismo
tipo, y es creada con el operador *
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í:
int* ptr
, crea una variable punteroExisten 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.
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
.
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.