Prefacio
CAPÍTULO 1
Instalando un entorno de desarrollo para el libro
1.1. ¿Qué es un entorno de desarrollo?
1.1.1. ¿Qué es un entorno de desarrollo?
1.1.2. ¿Qué nos proporciona un entorno de desarrollo?
1.1.3. Compiladores de C/C++
1.1.4. Herramientas de virtualización
1.1.4.1. Configuración del networking entre sistemas virtuales y físicos
1.1.5. Escoger herramientas para cada lector
1.1.6. La herramienta de Visual Studio Code
1.2. Instalación del entorno de desarrollo aconsejado
1.2.1. Orden de instalación de los elementos de entorno de desarrollo
1.2.2. Paso 1: descargar los ejemplos de código fuente del libro
1.2.3. Paso 2: instalar el compilador MinGW
1.2.3.1. Comprobar que MinGW está bien instalado
1.2.4. Paso 3: instalar Visual Studio Code (VSCode)
1.2.4.1. Acoplando los plugins a VSCode
1.2.5. Comprobando el funcionamiento de VSCode
1.2.6. Paso 4: instalar VirtualBox
1.2.7. Paso 5: obtener una versión de Ubuntu Linux
1.2.7.1. Comprobar que funciona la máquina virtual Linux
1.2.8. Paso 6: instalar Eclipse
1.2.9. Paso 7: instalando Visual Studio 2022 Community Edition
1.3. Conclusión del capítulo 1
CAPÍTULO 2
Nuestro primer programa en lenguaje C
2.1. HolaMundo: nuestro primer programa en C
2.1.1. Las librerías de include
2.1.2. Sumario de la función main
2.1.3. La función printf
2.1.4. ¿Qué cambios tenemos en este nuevo código fuente?
2.1.5. Cómo imprimir los parámetros de línea de comando
2.1.5.1. ¿Qué novedades vemos?
2.1.5.2. ¿Qué es el código spaghetti?
2.1.6. Depurar programas en C
2.1.7. En depuración, ¿qué significa un breakpoint?
2.1.8. ¿Cómo se pone en marcha la depuración (debugging)?
2.1.9. ¿Cómo se configura la depuración en VSCode?
2.1.9.1. Arrancando el modo depuración
2.1.10. La barra de herramientas de debug
2.1.11. La configuración de ventanas del modo debug
2.1.12. Cambios en el punto del breakpoint
2.1.13. Cómo enviar argumentos de línea de comando al depurar
2.1.14. En el próximo capítulo
CAPÍTULO 3
Variables alfanuméricas
3.1. Tipos de datos alfanuméricos
3.1.1. El tipo de variable char
3.1.2. Cadenas de caracteres y sus punteros
3.1.2.1. Errores típicos y catastróficos con las cadenas de texto
3.1.2.2. Cómo inicializar cadenas de texto
3.1.2.3. ¿Qué novedades tenemos en este programa?
3.1.2.4. Un programa para pasar de mayúsculas a minúsculas
3.1.2.5. Una página de códigos equivale a ¡una margarita!
3.1.2.6. Las impresoras de margarita y las páginas de códigos
3.1.2.7. Trabajar con caracteres en chino con UTF-16
3.1.3. Idiomas y culturas: el ejemplo chino
3.1.4. Representar pictogramas con caracteres occidentales
3.1.4.1. La escritura Wade-Giles
3.1.4.2. El sistema de escritura Pinyin
3.1.5. Ventajas del sistema de pictogramas
3.1.6. El área CJKV
3.1.6.1. La escritura en Japón
3.1.6.2. La escritura en Corea
3.1.6.3. La escritura en Vietnam
3.1.6.4. Las diásporas históricas desde Asia
3.1.7. La simplificación o reforma de los caracteres chinos
3.1.8. Y llegó la tecnología Unicode con los 32 bits
3.1.8.1. Diferencias prácticas con Unicode entre chino simplificado y chino tradicional
3.1.9. Culturas y programación informática
3.1.10. ¿En qué año vives?
3.1.11. La función setlocale
3.1.11.1. Conversión de UTF-16 a UTF-8
3.1.11.2. Llegaron las cadenas de caracteres Unicode
3.1.11.3. Recapitulando sobre los punteros a caracteres
3.1.11.4. Stack y heap, ¿dónde guardamos nuestras variables?
3.1.11.5. Pilas contra montones
3.1.12. ¿Veis cómo los montones son mejores?
3.1.12.1. Cómo declarar, inicializar y asignar cadenas de caracteres dinámicas
3.1.12.2. Dos formas de recorrer una cadena de texto
3.1.12.3. Función de búsqueda de texto mediante puntero-cursor
3.1.13. Stack y heap: funciones y procesadores
CAPÍTULO 4
Tipos de datos numéricos. Coma flotante y binarios
4.1. Los tipos básicos numéricos
4.1.1. Enteros, punteros a enteros y copias de enteros
4.1.1.1. Límites de cálculo de los números enteros de diferentes formatos
4.1.1.2. El tipo numérico entero sin signo
4.1.1.3. Anécdota de un regulador de velocidad. ¿Con signo o sin signo?
4.1.2. Modificadores
4.1.2.1. El modificador unsigned
4.1.2.2. El modificador const
4.1.2.3. El modificador constexpr
4.1.2.4. El modificador static
4.1.3. El tipo float y los números decimales
4.1.3.1. Coma fija y coma flotante
4.1.3.2. Estructura de un coma flotante en memoria
4.1.4. El tipo long double o doble precisión
4.1.5. El tipo long double o cuádruple precisión
4.1.6. Anécdota histórica: fallo en el cálculo de coma flotante del Pentium de Intel
4.1.7. Tipos numéricos máscara binaria: BYTE, WORD y DWORD
4.1.7.1. El sistema binario de numeración
4.1.7.2. Conversiones a hexadecimal
4.1.7.3. Álgebra de Bool para números binarios
4.1.8. La operación NOT
4.1.9. La operación OR
4.1.10. La operación NOR
4.1.11. La operación AND
4.1.12. La operación NAND
4.1.13. La operación XOR
4.1.14. Aplicación de puertas XOR y AND para un semisumador de 1 bit
4.1.14.1. La operación de desplazamiento SHL (multiplicación por 2)
4.1.14.2. La operación de desplazamiento SHR (división por 2)
4.1.15. Transformación de puertas OR en puertas AND y viceversa
4.1.15.1. Puerta NOR construida con transistores
4.1.15.2. Puerta AND construida con transistores
4.1.16. La tecnología TTL y cómo esto nos influyó desde los años 60
4.1.17. Orden Endian de los bytes
4.1.17.1. Endianidad en el procesador
4.1.18. Cómo dividir un WORD en byte alto y byte bajo
4.1.19. La resta, el signo y el complemento a 1
4.1.19.1. Investigando cómo se hace la resta
4.1.20. El complemento a 1
4.1.21. Operadores de máscara de bits en C
4.1.22. Función en C para hallar el complemento a 1
4.1.22.1. El programa de resta binaria con máscaras binarias en lenguaje C
4.1.23. La directiva asm y las máscaras binarias
4.1.23.1. La arquitectura escalada de Intel y su influencia en los sistemas operativos
4.1.23.2. Memoria y multitarea mejoradas
CAPÍTULO 5
Structs, unions y typedefs
5.1. El tipo de dato struct y su complementario union
5.1.1. Ejemplo básico de un struct
5.1.2. Ejemplo de creación de un nuevo tipo de dato con typedef struct
5.1.3. Ejemplo de ordenación de una matriz de clientes
5.1.3.1. Ahora, ¿qué vamos a hacer con esta matriz de 10 clientes?
5.1.3.2. ¿Cómo queda la función de ordenación?
5.1.3.3. Función de liberación de cadenas de texto
5.1.3.4. Función de impresión de listado
5.1.3.5. El cuerpo de programa principal
5.1.4. Ejemplo de struct y unión: un emulador de 2 procesadores a la vez
5.1.4.1. ¡Que vuelven los indios!
5.1.4.2. La instrucción MOV en ensamblador
5.1.4.3. Codificando MOV en lenguaje máquina
5.1.4.4. Simulando un MOV paso a paso
5.1.4.5. ¿Qué hemos conseguido?
5.1.4.6. El programa de prueba de structs y unions
5.1.4.7. La tentación vive abajo
5.1.4.8. Importancia de unions y emuladores en sistemas operativos
5.1.4.9. Del sistema operativo a la virtualización y la nube (Cloud Computing)
5.1.5. El struct como base para crear las clases en C++
5.1.5.1. La necesidad era manejar ordenadamente la creciente complejidad
CAPÍTULO 6
Creando funciones: ámbitos, parámetros y retorno
6.1. ¿Para qué sirven las funciones?
6.1.1. Librerías de funciones
6.1.2. ¿Qué es un prototipo de función?
6.1.2.1. El orden de las funciones sí que altera el producto
6.1.2.2. Declaraciones de prototipo
6.1.3. Creando una librería externa
6.1.4. ¿Cómo fusionar todos estos archivos en un proyecto?
6.1.4.1. Solucionando errores de gestión de proyecto
6.1.4.2. Cómo pasar parámetros por valor a las funciones
6.1.5. Dos enfoques para el valor de retorno de una función
6.1.5.1. Bajando hasta los infiernos de la excepción
6.1.5.2. ¿Cómo llamar al desensamblador de Visual Studio Code?
6.1.6. Conclusión sobre las funciones que retornan punteros nulos
6.1.7. Protegiendo las funciones que reciben punteros
6.1.8. Aclaración sobre los valores de retorno válidos
6.1.9. Prácticas poco ortodoxas para salvar un puntero loco
6.1.9.1. La función definida como static
6.1.9.2. Cómo asustar al compilador para que no libere una variable local
6.1.10. Arreglando el diseño de la función ObtenerTextoIdioma
6.1.11. Pasando parámetros por referencia
6.1.12. La función ObtenerTextoIdiomaExt arreglada
6.1.13. ¿Cómo quedaría ahora el programa principal?
CAPÍTULO 7
Librerías de funciones clásicas de entrada/salida (I/O)
7.1. Tres grupos de funciones de entrada/salida
7.1.1. ¿Por qué estos tipos de funciones de entrada/salida?
7.1.2. ¿Dónde se encuentran las librerías de estas funciones?
7.1.3. Un ejemplo de entrada/salida para pantalla y teclado
7.1.4. Función printf (#include )
7.1.5. La función scanf
7.1.5.1. Controlar la longitud de una cadena de texto
7.1.6. Funciones de entrada de caracteres individuales
7.1.7. Entrada de caracteres dobles
7.1.7.1. Captura de las teclas de función
7.1.8. La función getch()
7.1.9. La función getche()
7.1.10. La función putch()
7.1.11. El teclado
7.1.11.1. El buffer (o memoria) de teclado
7.1.11.2. Características del buffer de teclado
7.1.11.3. El error de buffer overrun
7.1.12. Las lecturas de teclado a muy bajo nivel desaparecen
CAPÍTULO 8
Blockchain como librería de funciones externas
8.1. Un ejemplo de librería de funciones Blockchain
8.1.1. Introducción
8.1.2. ¿Vamos a vender criptomonedas?
8.1.3. ¿Qué es Blockchain?
8.2. Características de Blockchain
8.2.1. Características de las Blockchain a nivel político
8.2.2. El dilema de las modificaciones y cómo se soluciona
8.3. El universo Blockchain
8.3.1. Activos digitales, criptoactivos, tokens fungibles y NFT
8.4. Uso de los criptoactivos a nivel financiero y de negocio
8.4.1. ¿Por qué son interesantes a nivel financiero/contable?
8.4.2. A nivel de contabilización y control de activos
8.4.3. Como moneda de cambio entre empresas de grupos y de terceros
8.4.3.1. Como incremento de solidez financiera de filiales
8.4.3.2. Ejemplo de desacople financiero mediante activos digitales
8.5. De vuelta al mundo tecnológico
8.5.1. La encriptación como requisito de ciberseguridad
8.6. Hashes y la librería externa de encriptación SSL
8.6.1. La librería OpenSSL como librería externa
8.6.2. ¿Qué es un hash? ¿Qué es un bloque?
8.6.3. Similitudes y relaciones entre hashes y encriptaciones
8.6.4. Comprobación de propiedad: demostrar ser el owner
8.6.5. Hashes truculentos o Hecha la ley, hecha la trampa
8.6.6. ¿Qué es un bloque?
8.6.7. Concatenación o encabalgamiento de hashes
8.6.8. Blockchain es relativamente caro
8.6.9. Tipos de cadenas Blockchain y costes por transacción
8.6.10. Sobre el volumen de transacciones
8.6.11. La figura del minador de criptoactivos
8.6.12. Minadores y Fintechs diversas
8.6.13. Empresas más tranquilas basadas en Blockchain
8.6.14. Tamaños de redes Blockchain y recursos de implementación
8.6.14.1. Recursos necesarios en empresas Fintech globales
8.6.14.2. Recursos necesarios en energéticas y telecos
8.6.14.3. Recursos necesarios en empresas logísticas grandes
8.6.14.4. Oficinas de notarías y servicios legales
8.7. Los objetivos del capítulo
8.8. Ejercicio único de este capítulo: la blockchain
8.8.1. Entendiendo las listas dinámicas
8.8.2. De elementos a bloques de Blockchain
8.8.3. Funcionamiento del programa de ejemplo de Blockchain
8.8.3.1. Niveles de funciones:
8.8.3.2. Reparto de las funciones por niveles
8.8.4. Repaso de las opciones de programa
8.8.4.1. Dar de alta nuevo bloque
8.8.4.2. Generar N bloques aleatorios
8.8.4.3. Contar bloques
8.8.4.4. Falsificar bloque N
8.8.4.5. Listado de todos los bloques
8.8.4.6. Verificar blockchain
8.8.4.7. Reconstruir todo el blockchain recalculando bloques falsos
8.8.4.8. Imprimir el hash de un bloque
8.8.4.9. Imprimir solo los bloques falsos
8.8.4.10. Salir (y, sobre todo, liberar bloques con free)
8.8.4.11. Indiana Jones en busca de la memoria perdida
8.8.4.12. La función LiberarBlockchain
8.8.5. Conclusión
CAPÍTULO 9
Librerías de funciones de entrada/salida para consola de Windows
9.1. Aplicación de ejemplo para pantallas de texto avanzadas
9.2. Funciones de entrada/salida propias de la Consola de Windows
9.2.1. MS-DOS ya no existe: es una emulación de consola
9.2.2. ¿Cuándo programar con printf y cuándo usar consola de Windows?
9.2.3. Construyendo aplicaciones de Consola de Windows
9.2.4. La tabla de caracteres semigráficos
9.2.5. Escribiendo una función para entrada de texto: EntraString
9.2.5.1. Sintaxis de EntraString Código fuente de EntraString
9.2.6. Uso de EntraString en el contexto del programa
9.2.6.1. El resto de las funciones auxiliares, de mayor a menor
9.2.6.2. La función GestionarTeclasEspeciales
9.2.6.3. La función GoToXY
9.2.6.4. ¿Y cómo se obtiene el handle del buffer de consola?
9.2.6.5. La función SetFGColor para cambiar colores de texto
9.2.7. Funciones de transformación de códigos de página de texto
9.2.7.1. Código fuente de la función UnicodetoAnsi
9.2.7.2. Código fuente de la función AnsiToUnicode
9.2.7.3. La función PrintCPLabel
9.2.8. Gestionar ventanas indoloras y pintar recuadros
9.2.8.1. Cómo pintar una ventana con la función PintarVentana
9.2.8.2. La función PintarVentana
9.2.8.3. Implementando ventanas indoloras (painless Windows)
9.2.9. Posibles mejoras para copiar y restaurar ventanas
9.3. Lectura de ratón y eventos especiales
9.3.1. El bucle de mensajes
9.3.2. Los manejadores de eventos
9.3.2.1. El manejador de teclado
9.3.2.2. El manejador de ratón
9.3.2.3. El manejador de redimensionamiento de ventana
9.3.2.4. El manejador de eventos de paso de foco
9.3.2.5. El manejador de eventos de menú
9.3.3. El programa principal del testeador de eventos
9.3.4. Descargar el código fuente del testeador de eventos
9.3.5. En el siguiente capítulo
CAPÍTULO 10
Librerías de funciones de entrada/salida para ficheros (archivos)
10.1. Añadiendo funciones para gestión de ficheros
10.2. Construyendo la parte de grabación de archivos
10.2.1. La persistencia
10.2.2. Persistencia mediante bases de datos
10.2.3. Persistencia mediante archivos
10.2.4. Archivos secuenciales
10.2.5. Registros y campos
10.2.6. Algoritmo típico para un sistema de acceso secuencial
10.2.7. ¿Se usan mucho los ficheros secuenciales hoy día?
10.2.7.1. Ficheros secuenciales como archivos de configuración
10.2.7.2. El formato CSV: un archivo secuencial de datos compatible con Excel
10.2.7.3. Los archivos de Log como archivos de acceso secuencial
10.2.7.4. El formato XML como archivo secuencial
10.2.7.5. El tipo JSON como archivo secuencial
10.2.7.6. El formato DBF de dBase III, Clipper y FoxPro
10.2.7.7. Más y más formatos secuenciales
10.2.8. Los archivos de acceso aleatorio (random)
10.2.8.1. Cálculo del posicionamiento random
10.2.8.2. Randoms con cabecera y sin cabecera
10.2.9. Los archivos de acceso indexado
10.2.9.1. El número de accesos para encontrar una clave
10.2.9.2. El árbol binario equilibrado B+ o AVL
10.2.9.3. Árboles y sarmientos
10.2.9.4. El mecanismo de equilibrado
10.2.9.5. El equilibrado on demand
10.2.9.6. El equilibrado automático
10.3. Función para crear logs en ficheros secuenciales
10.3.1. Llamando a la función de Logging
10.3.2. Explicación de la función WriteLog
10.3.3. Escritura del fichero de datos de acceso aleatorio
10.3.4. La solución del registro de cabecera en registro = 0
10.3.4.1. Planteamiento del registro 0
10.3.4.2. El cálculo de espacio y el alineamiento de structs
10.3.4.3. Un problema típico del alineamiento
10.3.4.4. La opción del modo de alineamiento del compilador
10.3.4.5. El operador alignof()
10.3.5. La misión del archivo secuencial de configuración
10.3.5.1. El sistema clave à valor
10.3.5.2. Las funciones de trimado
10.3.6. La función GetConfigParamValue
10.3.6.1. Inicialización del Registro 0
10.3.6.2. La función CreateEmptyDataFile
10.3.6.3. Funciones importantes empleadas para el fichero
10.3.6.4. Verificar carga de registro 0 y usar metadatos
10.3.7. Grabación de un registro de datos en fichero random
10.3.7.1. Modos de edición de registro
10.3.8. Funciones de cursorización
10.3.9. Borrado, compactación y truncado de registros
10.3.9.1. Qué hay que hacer antes de borrar un registro
10.3.9.2. Qué hay que hacer después de borrar un registro
10.3.9.3. La función de truncado
10.3.9.4. La función de compactación
10.3.9.5. Gestión de la petición de borrado con F5
10.3.10. Lo que hemos visto son las operaciones CRUD
CAPÍTULO 11
Listas dinámicas persistentes con Blockchain y ficheros
11.1. Persistencia de Blockchain en ficheros
11.1.1. Repaso introductorio
11.2. Dos nuevas formas de hackear Blockchain
11.2.1. El hacking por inserción de punteros
11.2.2. El hacking por escritura directa o recifrado del fichero de Blockchain
11.2.3. Analizando el problema de la inserción de un bloque falso
11.3. Funciones de la capa de persistencia Blockchain
11.3.1. ExistsFile
11.3.2. CrearFicheroBlockchain
11.3.3. ContarBloquesDesdeFichero
11.3.4. LeerBloque
11.3.5. LeerCadenaBloquesEnteraDesdeFichero
11.3.6. EscribirBloque
11.3.7. EscribirCadenaBloquesEnteraHaciaFichero
11.4. Código fuente comentado del programa principal
11.5. Conclusión
CAPÍTULO 12
Recursividad, árboles binarios, traversas y punteros a funciones
12.1. Introducción a los procesos recursivos
12.1.1. ¿Todos los procesos se pueden hacer recursivos?
12.1.2. El cálculo de factorial como ejemplo básico
12.1.3. Código fuente de la factorial de coma flotante, 64 bits
12.1.4. Dónde se encuentra el código fuente de las factoriales
12.2. Programación recursiva de determinantes
12.2.1. ¿Qué es un determinante?
12.2.2. Organizar las tareas del determinante
12.2.2.1. El acceso bidimensional a los elementos de la matriz
12.2.3. El programa principal
12.3. Introducción a los árboles binarios
12.3.1. ¿Qué son los árboles binarios?
12.3.2. Comparación de listas con árboles
12.3.3. Listas doblemente enlazadas
12.3.4. El árbol binario de búsqueda (BST o Binary Search Tree)
12.3.5. Los árboles en Prolog
12.4. Un ejemplo de diseño de árbol en C
12.5. Insertando datos en un árbol
12.5.1. Preparar el árbol
12.5.2. Insertamos una clave y un valor en un árbol vacío
12.5.3. Insertamos clave y valor en un árbol con datos preexistentes
12.5.3.1. Creamos la función de inserción de tipo recursivo
12.5.4. Experimentando con la secuencia de inserción
12.6. Introducción a las rotaciones
12.6.1. Paso 1
12.6.2. Paso 2
12.6.2.1. Transición del paso 2 al paso 3
12.6.3. Paso 3
12.7. Insertando todos los elementos de prueba
12.8. Buscando elementos dentro del árbol
12.8.1. Código fuente de BuscarNodo
12.8.2. Comprobación del número de comparaciones
12.9. Traversa In Order y punteros a funciones
12.9.1. Los métodos de traversas (traversal)
12.9.2. La traversa in order
12.9.3. Punteros a funciones
12.9.3.1. Cómo declarar un prototipo de puntero a función
12.9.3.2. Asignar una función genérica a este puntero
12.9.4. Función para contar elementos basada en traversa
12.10. Función para liberar nodos y el árbol en sí
12.11. La traversa post order para eliminar el árbol
12.11.1. Código fuente de la traversa post order
12.11.2. La función LiberarNodo
12.12. Código fuente final
12.13. Conclusión
¿Se ha preguntado en qué lenguaje están programados los sistemas que gobiernan nuestra tecnología moderna? Tiene a su alcance la puerta de entrada a uno de los lenguajes más poderosos y versátiles del mundo de la programación, el lenguaje C. Si quiere descubrir el potencial de este lenguaje desde un nivel inicial, ha llegado al libro indicado. El lenguaje C llega a todo tipo de ámbitos, pues es compatible con los sistemas operativos más populares, como Linux y Windows, con los videojuegos, los índices del buscador de Google, las aplicaciones complejas en el ámbito de la física cuántica y la aeronáutica (como Dassault, Lockheed-Martin Aero), los sistemas de telecomunicaciones de Nokia, Alcatel, T-Mobile, Ericsson e incluso con los modelos financieros como Bloomberg y Morgan Stanley. Escrita con un enfoque práctico y una orientación maker, esta guía le permitirá sumergirse en el desarrollo real desde el primer momento. Con ejemplos descargables y aplicaciones en tecnologías avanzadas como Blockchain, sistemas embebidos y más, tendrá las herramientas necesarias para aprender con la práctica, el método más efectivo para dominar el arte de la programación. Aprender C no es solo un paso fundamental para cualquier programador, sino que es la clave para comprender los lenguajes que forman la base de las innovaciones tecnológicas actuales y futuras. Con este libro, descubrirá los secretos de un lenguaje que ha sido esencial en el desarrollo de sistemas y aplicaciones críticas durante décadas. Prepárese para explorar el lenguaje que impulsa la tecnología que emplea cada día. ¡Aprenda C y forme parte del presente y del futuro de la programación!