Billy Chandler

Billy Chandler

1664173705

How to Implement a Linked List in C Programming

Learn the basics of linked lists in the C programming language and how to implement a linked list in C programming 

You'll learn:

  • Linked lists structure implementation
  • Algorithms related to linked lists

Learn the basics of linked lists in the C programming language. This course treats the student as a complete beginner to linked lists that has a basic understanding of arrays/pointers and other similar concepts of the C language. What we want is, at the end of this course, for you to be able to use a linked list exactly like a plain old array.

After finishing the course you will be able to

  •    Create the data structure for a singly and doubly linked list
  •    Insert any element wherever in the linked list
  •    Remove an element from the linked list
  •    Understand how the linked list is allocated in memory
  •    Properly deallocate the linked list
  •    And to code other useful algorithms

Requirements

  •    A working computer
  •    C/C++ IDE (Visual Studio, Dev-C++, CodeBlocks etc.)
  •    Basic understanding of the C language (especially pointers and stack/heap memory)


Who this course is for:

  •    Beginner programmers that want to fully understand linked lists and their potential

#algorithms #linkedlists #cplusplus #cpp #cprogramming

How to Implement a Linked List in C Programming
Joshua Yates

Joshua Yates

1660876155

Learn C Programming with the Classic Book by Kernighan and Ritchie

Learn C Programming with the Classic Book by Kernighan and Ritchie

In this complete C programming course, Dr. Charles Severance (aka Dr. Chuck) will help you understand computer architecture and low-level programming through studying the "classic" version of the C Programming language from the 1978 book written by Brian Kernighan and Dennis Ritchie.

In this course we will be reflecting on how C provided an important foundation for the creation of modern programming languages. This is not a good place to start if you do not already have some programming experience. A

✏️ Dr. Charles Severance developed this course. He is a professor at the University of Michigan and one of the most popular software instructors in the world.

⭐️ Course Contents ⭐️
⌨️ (0:00:00) Course Intro
⌨️ (0:03:09) Chapter 0: Introduction
⌨️ (0:20:44) Chapter 1: A Tutorial Introduction
⌨️ (1:59:17) Chapter 2: Types, Operators, and Expressions
⌨️ (3:02:09) Chapter 3: Control Flow
⌨️ (3:49:31) Chapter 4: Functions and Program Structure
⌨️ (5:20:32) Chapter 5: Pointers and Arrays
⌨️ (6:50:30) Chapter 6: Structures
⌨️ (8:16:33) Chapter 7: Input and Output
⌨️ (9:02:02) Chapter 8: The UNIX System Interface

📖 Online C Programming book by Brian Kernighan and Dennis Ritchie: https://www.cc4e.com/book/chap00.md 
🔗 Additional course resources: https://www.cc4e.com/ 
(Unlock Code Hint: View the developer console on the website.)

#cprogramming #developer 

Learn C Programming with the Classic Book by Kernighan and Ritchie
Alfie Mellor

Alfie Mellor

1660179355

Learn C++ Programming for Beginners – Free 1 Hour Course

C++ Tutorial for Beginners - Learn C++ in 1 Hour

This C++ tutorial for beginners shows you how to get started with C++ quickly. Learn C++ basics in 1 hour and get ready to learn more!
 

TABLE OF CONTENT

0:00:00 Course Introduction
0:00:56 Introduction to C++
0:04:14 Popular IDEs
0:06:11 Your First C++ Program
0:13:36 Compiling and Running a C++ Program 
0:16:01 Changing the Theme
0:17:16 Course Structure
0:18:48 Cheat Sheet
0:19:20 Section 1: The Basics
0:19:52 Variables
0:26:00 Constants
0:27:28 Naming Conventions
0:30:25 Mathematical Expressions
0:36:39 Order of Operators
0:39:49 Writing Output to the Console
0:49:06 Reading from the Console
0:53:41 Working with the Standard Library 
0:58:19 Comments
1:00:51 Introduction to Fundamental Data Types 
1:01:41 Section 2: Fundamental Data Types
1:04:45 Initializing Variables
1:09:29 Working with Numbers
1:13:03 Narrowing
1:15:17 Generating Random Numbers

#cprogramming #cplusplus #cpp 

Learn C++ Programming for Beginners – Free 1 Hour Course

Manual Para Principiantes De C En Solo Unas Pocas Horas

Este Manual para principiantes de C sigue la regla 80/20. Aprenderás el 80 % del lenguaje de programación C en el 20 % del tiempo.

Este enfoque le dará una visión completa del idioma.

Este manual no trata de cubrir todo lo relacionado con C. Se enfoca en el núcleo del lenguaje, tratando de simplificar los temas más complejos.

Y nota: puede obtener una versión en PDF y ePub de este Manual para principiantes de C aquí .

¡Disfrutar!

Introducción a C

C es probablemente el lenguaje de programación más conocido. Se utiliza como lenguaje de referencia para los cursos de informática en todo el mundo, y es probablemente el lenguaje que más se aprende en la escuela junto con Python y Java.

Recuerdo que fue mi segundo lenguaje de programación, después de Pascal.

C no es solo lo que los estudiantes usan para aprender a programar. No es un lenguaje académico. Y diría que no es el lenguaje más fácil, porque C es un lenguaje de programación de bajo nivel.

Hoy en día, C se usa ampliamente en dispositivos integrados y alimenta la mayoría de los servidores de Internet, que se construyen con Linux. El kernel de Linux está construido con C, y esto también significa que C impulsa el núcleo de todos los dispositivos Android. Podemos decir que el código C ejecuta una buena parte del mundo entero. En este momento. Bastante notable.

Cuando se creó, C se consideraba un lenguaje de alto nivel porque era portátil entre máquinas. Hoy damos por sentado que podemos ejecutar un programa escrito en una Mac en Windows o Linux, tal vez usando Node.js o Python.

Érase una vez, este no era el caso en absoluto. Lo que C trajo a la mesa fue un lenguaje que era simple de implementar y que tenía un compilador que se podía portar fácilmente a diferentes máquinas.

Dije compilador: C es un lenguaje de programación compilado, como Go, Java, Swift o Rust. Se interpretan otros lenguajes de programación populares como Python, Ruby o JavaScript. La diferencia es consistente: un lenguaje compilado genera un archivo binario que se puede ejecutar y distribuir directamente.

C no es basura recolectada. Esto significa que tenemos que gestionar la memoria nosotros mismos. Es una tarea compleja y que requiere mucha atención para evitar errores, pero también es lo que hace que C sea ideal para escribir programas para dispositivos integrados como Arduino.

C no oculta la complejidad y las capacidades de la máquina subyacente. Tienes mucho poder, una vez que sabes lo que puedes hacer.

Quiero presentar el primer programa en C ahora, al que llamaremos "¡Hola, mundo!"

Hola C

#include <stdio.h>

int main(void) {
    printf("Hello, World!");
}

Describamos el código fuente del programa: primero importamos la stdiobiblioteca (el nombre significa biblioteca estándar de entrada y salida).

Esta biblioteca nos da acceso a las funciones de entrada/salida.

C es un lenguaje muy pequeño en su núcleo, y las bibliotecas proporcionan cualquier cosa que no sea parte del núcleo. Algunas de esas bibliotecas están construidas por programadores normales y están disponibles para que otros las usen. Algunas otras bibliotecas están integradas en el compilador. Me gusta stdioy otros.

stdioes la biblioteca que proporciona la printf()función.

Esta función está envuelta en una main()función. La main()función es el punto de entrada de cualquier programa en C.

Pero, ¿qué es una función, de todos modos?

Una función es una rutina que toma uno o más argumentos y devuelve un solo valor.

En el caso de main(), la función no recibe argumentos y devuelve un número entero. Lo identificamos usando la voidpalabra clave para el argumento y la intpalabra clave para el valor devuelto.

La función tiene un cuerpo, que está envuelto entre llaves. Dentro del cuerpo tenemos todo el código que necesita la función para realizar sus operaciones.

La printf()función se escribe de manera diferente, como puede ver. No tiene un valor de retorno definido, y pasamos una cadena entre comillas dobles. No especificamos el tipo de argumento.

Eso es porque esta es una invocación de función. En algún lugar, dentro de la stdiobiblioteca, printfse define como

int printf(const char *format, ...);

No necesita entender lo que esto significa ahora, pero en resumen, esta es la definición. Y cuando llamamos printf("Hello, World!");, ahí es donde se ejecuta la función.

La main()función que definimos anteriormente:

#include <stdio.h>

int main(void) {
    printf("Hello, World!");
}

será ejecutado por el sistema operativo cuando se ejecute el programa.

¿Cómo ejecutamos un programa en C?

Como se mencionó, C es un lenguaje compilado. Para ejecutar el programa primero debemos compilarlo. Cualquier computadora con Linux o macOS ya viene con un compilador de C incorporado. Para Windows, puede usar el Subsistema de Windows para Linux (WSL).

En cualquier caso, cuando abre la ventana de la terminal puede escribir gcc, y este comando debería devolver un error diciendo que no especificó ningún archivo:

Captura de pantalla-2020-01-29-a-10.10.50

Está bien. Significa que el compilador de C está ahí y podemos empezar a usarlo.

Ahora escriba el programa anterior en un hello.carchivo. Puede usar cualquier editor, pero por simplicidad voy a usar el nanoeditor en la línea de comando:

Captura de pantalla-2020-01-29-a-10.11.39

Escriba el programa:

Captura de pantalla-2020-01-29-a-10.16.52

Ahora presione ctrl-Xpara salir:

Captura de pantalla-2020-01-29-a-10.18.11

Confirme presionando la ytecla , luego presione enter para confirmar el nombre del archivo:

Captura de pantalla-2020-01-29-a-10.18.15

Eso es todo, deberíamos volver a la terminal ahora:

Captura de pantalla-2020-01-29-a-10.13.46

Ahora escriba

gcc hello.c -o hello

El programa no debería darte errores:

Captura de pantalla-2020-01-29-a-10.16.31

pero debería haber generado un helloejecutable. Ahora escribe

./hello

para ejecutarlo:

Captura de pantalla-2020-01-29-a-10.19.20

Antepongo ./el nombre del programa para decirle a la terminal que el comando está en la carpeta actual

¡Impresionante!

Ahora, si llama al ls -al hello, puede ver que el programa solo tiene un tamaño de 12 KB:

Captura de pantalla-2020-01-29-a-10.19.55

Este es uno de los pros de C: está altamente optimizado, y esta es también una de las razones por las que es bueno para dispositivos integrados que tienen una cantidad muy limitada de recursos.

Variables y tipos

C es un lenguaje de tipo estático.

Esto significa que cualquier variable tiene un tipo asociado, y este tipo se conoce en el momento de la compilación.

Esto es muy diferente a cómo trabaja con variables en Python, JavaScript, PHP y otros lenguajes interpretados.

Cuando crea una variable en C, debe especificar el tipo de una variable en la declaración.

En este ejemplo inicializamos una variable agecon tipo int:

int age;

Un nombre de variable puede contener cualquier letra mayúscula o minúscula, puede contener dígitos y el carácter de subrayado, pero no puede comenzar con un dígito. AGEy Age10son nombres de variables válidos, 1ageno lo es.

También puede inicializar una variable en la declaración, especificando el valor inicial:

int age = 37;

Una vez que declara una variable, puede usarla en su código de programa. Puede cambiar su valor en cualquier momento, utilizando el =operador, por ejemplo, como en age = 100;(siempre que el nuevo valor sea del mismo tipo).

En este caso:

#include <stdio.h>

int main(void) {
    int age = 0;
    age = 37.2;
    printf("%u", age);
}

el compilador generará una advertencia en el momento de la compilación y convertirá el número decimal en un valor entero.

Los tipos de datos integrados de C son int, char, short, long, float, double, long double. Averigüemos más sobre ellos.

números enteros

C nos proporciona los siguientes tipos para definir valores enteros:

  • char
  • int
  • short
  • long

La mayoría de las veces, probablemente usará an intpara almacenar un número entero. Pero en algunos casos, es posible que desee elegir una de las otras 3 opciones.

El chartipo se usa comúnmente para almacenar letras del gráfico ASCII, pero se puede usar para contener pequeños enteros desde -128hasta 127. Se necesita al menos 1 byte.

intocupa al menos 2 bytes. shortocupa al menos 2 bytes. longocupa al menos 4 bytes.

Como puede ver, no se nos garantizan los mismos valores para diferentes entornos. Sólo tenemos una indicación. El problema es que los números exactos que se pueden almacenar en cada tipo de datos dependen de la implementación y la arquitectura.

Estamos garantizados que shortno es más largo que int. Y estamos garantizados longque no es más corto que int.

El estándar de especificaciones ANSI C determina los valores mínimos de cada tipo, y gracias a él podemos al menos saber cuál es el valor mínimo que podemos esperar tener a nuestra disposición.

Si está programando C en un Arduino, diferentes placas tendrán diferentes límites.

En una placa Arduino Uno, intalmacena un valor de 2 bytes, que va desde -32,768a 32,767. En un Arduino MKR 1010, intalmacena un valor de 4 bytes, que va desde -2,147,483,648a 2,147,483,647. Una gran diferencia.

En todas las placas Arduino, shortalmacena un valor de 2 bytes, que va desde -32,768a 32,767. longalmacenar 4 bytes, que van desde -2,147,483,648a 2,147,483,647.

enteros sin signo

Para todos los tipos de datos anteriores, podemos anteponer unsignedpara comenzar el rango en 0, en lugar de un número negativo. Esto podría tener sentido en muchos casos.

  • unsigned charvariará de 0a por lo menos255
  • unsigned intvariará de 0a por lo menos65,535
  • unsigned shortvariará de 0a por lo menos65,535
  • unsigned longvariará de 0a por lo menos4,294,967,295

El problema con el desbordamiento

Dados todos esos límites, podría surgir una pregunta: ¿cómo podemos asegurarnos de que nuestros números no excedan el límite? ¿Y qué pasa si superamos el límite?

Si tiene un unsigned intnúmero en 255 y lo incrementa, obtendrá 256 a cambio. Como se esperaba. Si tiene un unsigned charnúmero en 255 y lo incrementa, obtendrá 0 a cambio. Se pone a cero a partir del valor inicial posible.

Si tienes un unsigned charnúmero en 255 y le sumas 10, obtendrás el número 9:

#include <stdio.h>

int main(void) {
  unsigned char j = 255;
  j = j + 10;
  printf("%u", j); /* 9 */
}

Si no tiene un valor firmado, el comportamiento no está definido. Básicamente te dará un número enorme que puede variar, como en este caso:

#include <stdio.h>

int main(void) {
  char j = 127;
  j = j + 10;
  printf("%u", j); /* 4294967177 */
}

En otras palabras, C no lo protege de sobrepasar los límites de un tipo. Tienes que encargarte de esto tú mismo.

Advertencias al declarar el tipo incorrecto

Cuando declara la variable y la inicializa con el valor incorrecto, el gcccompilador (el que probablemente esté usando) debería advertirle:

#include <stdio.h>

int main(void) {
  char j = 1000;
}
hello.c:4:11: warning: implicit conversion 
  from 'int' to
      'char' changes value from 1000 to -24
      [-Wconstant-conversion]
        char j = 1000;
             ~   ^~~~
1 warning generated.

Y también te avisa en asignaciones directas:

#include <stdio.h>

int main(void) {
  char j;
  j = 1000;
}

Pero no si aumenta el número usando, por ejemplo, +=:

#include <stdio.h>

int main(void) {
  char j = 0;
  j += 1000;
}

Números de punto flotante

Los tipos de punto flotante pueden representar un conjunto de valores mucho más grande que los números enteros y también pueden representar fracciones, algo que los números enteros no pueden hacer.

Usando números de coma flotante, representamos números como números decimales multiplicados por potencias de 10.

Es posible que vea números de punto flotante escritos como

  • 1.29e-3
  • -2.3e+5

y en otras formas aparentemente extrañas.

Los siguientes tipos:

  • float
  • double
  • long double

se utilizan para representar números con puntos decimales (tipos de puntos flotantes). Todos pueden representar números tanto positivos como negativos.

Los requisitos mínimos para cualquier implementación de C es que floatpueda representar un rango entre 10^-37 y 10^+37, y normalmente se implementa con 32 bits. doublepuede representar un conjunto mayor de números. long doublepuede contener incluso más números.

Las cifras exactas, al igual que con los valores enteros, dependen de la implementación.

En una Mac moderna, a floatse representa en 32 bits y tiene una precisión de 24 bits significativos. Se utilizan 8 bits para codificar el exponente.

Un doublenúmero se representa en 64 bits, con una precisión de 53 bits significativos. Se utilizan 11 bits para codificar el exponente.

El tipo long doublese representa en 80 bits, tiene una precisión de 64 bits significativos. Se utilizan 15 bits para codificar el exponente.

En su computadora específica, ¿cómo puede determinar el tamaño específico de los tipos? Puedes escribir un programa para hacer eso:

#include <stdio.h>

int main(void) {
  printf("char size: %lu bytes\n", sizeof(char));
  printf("int size: %lu bytes\n", sizeof(int));
  printf("short size: %lu bytes\n", sizeof(short));
  printf("long size: %lu bytes\n", sizeof(long));
  printf("float size: %lu bytes\n", sizeof(float));
  printf("double size: %lu bytes\n", 
    sizeof(double));
  printf("long double size: %lu bytes\n", 
    sizeof(long double));
}

En mi sistema, una Mac moderna, imprime:

char size: 1 bytes
int size: 4 bytes
short size: 2 bytes
long size: 8 bytes
float size: 4 bytes
double size: 8 bytes
long double size: 16 bytes

constantes

Hablemos ahora de las constantes.

Una constante se declara de manera similar a las variables, excepto que se antepone con la constpalabra clave y siempre debe especificar un valor.

Como esto:

const int age = 37;

Esto es C perfectamente válido, aunque es común declarar las constantes en mayúsculas, así:

const int AGE = 37;

Es solo una convención, pero que puede ser de gran ayuda mientras lee o escribe un programa en C, ya que mejora la legibilidad. El nombre en mayúsculas significa constante, el nombre en minúsculas significa variable.

Un nombre constante sigue las mismas reglas para los nombres de variables: puede contener cualquier letra mayúscula o minúscula, puede contener dígitos y el carácter de subrayado, pero no puede comenzar con un dígito. AGEy Age10son nombres de variables válidos, 1AGEno lo es.

Otra forma de definir constantes es usando esta sintaxis:

#define AGE 37

En este caso, no necesita agregar un tipo, y tampoco necesita el =signo igual, y omite el punto y coma al final.

El compilador de C deducirá el tipo del valor especificado, en tiempo de compilación.

Operadores

C nos ofrece una amplia variedad de operadores que podemos usar para operar sobre los datos.

En particular, podemos identificar varios grupos de operadores:

  • operadores aritméticos
  • operadores de comparación
  • operadores logicos
  • operadores de asignación compuesta
  • operadores bit a bit
  • operadores de puntero
  • operadores de estructura
  • varios operadores

En esta sección voy a detallarlos todos, usando 2 variables imaginarias ay bcomo ejemplos.

Mantengo los operadores bit a bit, los operadores de estructura y los operadores de puntero fuera de esta lista, para simplificar las cosas.

Operadores aritméticos

En este grupo de macros voy a separar los operadores binarios y los operadores unarios.

Los operadores binarios funcionan con dos operandos:

OPERADORNOMBREEJEMPLO
=Asignacióna = b
+Sumaa + b
-Sustraccióna - b
*Multiplicacióna * b
/Divisióna / b
%Móduloa % b

Los operadores unarios solo toman un operando:

OPERADORNOMBREEJEMPLO
+más unario+a
-menos unario-a
++Incrementoa++o++a
--Decrementoa--o--a

La diferencia entre a++y ++aes que a++incrementa la avariable después de usarla. ++aincrementa la avariable antes de usarla.

Por ejemplo:

int a = 2;
int b;
b = a++ /* b is 2, a is 3 */
b = ++a /* b is 4, a is 4 */

Lo mismo se aplica al operador de decremento.

Operadores de comparación

OPERADORNOMBREEJEMPLO
==Operador iguala == b
!=Operador no iguala != b
>Más grande quea > b
<Menos quea < b
>=Mayor que o igual aa >= b
<=Menos que o igual aa <= b

Operadores logicos

  • !NO (ejemplo: !a)
  • &&Y (ejemplo: a && b)
  • ||O (ejemplo: a || b)

Esos operadores son geniales cuando se trabaja con valores booleanos.

Operadores de asignación compuestos

Esos operadores son útiles para realizar una asignación y al mismo tiempo realizar una operación aritmética:

OPERADORNOMBREEJEMPLO
+=Asignación de adicióna += b
-=Asignación de restaa -= b
*=Asignación de multiplicacióna *= b
/=Asignación de divisióna /= b
%=Asignación de móduloa %= b

El operador ternario

El operador ternario es el único operador en C que trabaja con 3 operandos, y es una forma corta de expresar condicionales.

Así es como se ve:

<condition> ? <expression> : <expression>

Ejemplo:

a ? b : c

Si ase evalúa como true, entonces se ejecuta la bdeclaración; de lo contrario, se ejecuta c.

El operador ternario tiene la misma funcionalidad que un condicional if/else, excepto que es más corto de expresar y puede incluirse en una expresión.

tamaño de

El sizeofoperador devuelve el tamaño del operando que pasa. Puede pasar una variable, o incluso un tipo.

Ejemplo de uso:

#include <stdio.h>

int main(void) {
  int age = 37;
  printf("%ld\n", sizeof(age));
  printf("%ld", sizeof(int));
}

Precedencia del operador

Con todos esos operadores (y más, que no he cubierto en esta publicación, incluidos los operadores bit a bit, de estructura y de puntero), debemos prestar atención al usarlos juntos en una sola expresión.

Supongamos que tenemos esta operación:

int a = 2;
int b = 4;
int c = b + a * a / b - a;

¿Cuál es el valor de c? ¿Conseguimos que la suma se ejecute antes que la multiplicación y la división?

Hay un conjunto de reglas que nos ayudan a resolver este rompecabezas.

En orden de menos precedencia a más precedencia, tenemos:

  • el =operador de asignación
  • los operadores binarios+ y-
  • los operadores *y/
  • los operadores unarios +y-

Los operadores también tienen una regla de asociatividad, que siempre es de izquierda a derecha excepto para los operadores unarios y la asignación.

En:

int c = b + a * a / b - a;

Primero ejecutamos a * a / b, que, por ser de izquierda a derecha, podemos separar en a * ay el resultado / b: 2 * 2 = 4, 4 / 4 = 1.

Luego podemos realizar la suma y la resta: 4 + 1 - 2. El valor de ces 3.

En todos los casos, sin embargo, quiero asegurarme de que se dé cuenta de que puede usar paréntesis para hacer que cualquier expresión similar sea más fácil de leer y comprender.

Los paréntesis tienen mayor prioridad que cualquier otra cosa.

La expresión de ejemplo anterior se puede reescribir como:

int c = b + ((a * a) / b) - a;

y no tenemos que pensar mucho en ello.

Condicionales

Cualquier lenguaje de programación proporciona a los programadores la capacidad de realizar elecciones.

Queremos hacer X en algunos casos e Y en otros casos.

Queremos verificar los datos y tomar decisiones basadas en el estado de esos datos.

C nos proporciona 2 formas de hacerlo.

El primero es la ifsentencia, con su elseayudante, y el segundo es la switchsentencia.

si

En una ifdeclaración, puede verificar que una condición sea verdadera y luego ejecutar el bloque proporcionado entre llaves:

int a = 1;

if (a == 1) {
  /* do something */
}

Puede agregar un elsebloque para ejecutar un bloque diferente si la condición original resulta ser falsa:

int a = 1;

if (a == 2) {
  /* do something */
} else {
  /* do something else */
}

Tenga cuidado con una fuente común de errores: use siempre el operador ==de comparación en las comparaciones, y no el operador de asignación =. Si no lo hace, la ifverificación condicional siempre será verdadera, a menos que el argumento sea 0, por ejemplo, si lo hace:

int a = 0;

if (a = 0) {
  /* never invoked */
}

¿Por qué pasó esto? Porque la verificación condicional buscará un resultado booleano (el resultado de una comparación), y el 0número siempre equivale a un valor falso. Todo lo demás es cierto, incluidos los números negativos.

Puede tener varios elsebloques apilando varias ifdeclaraciones:

int a = 1;

if (a == 2) {
  /* do something */
} else if (a == 1) {
  /* do something else */
} else {
  /* do something else again */
}

cambiar

Si necesita hacer demasiados bloques if / else / if para realizar una verificación, tal vez porque necesita verificar el valor exacto de una variable, entonces switchpuede serle muy útil.

Puede proporcionar una variable como condición y una serie de casepuntos de entrada para cada valor que espera:

int a = 1;

switch (a) {
  case 0:
    /* do something */
    break;
  case 1:
    /* do something else */
    break;
  case 2:
    /* do something else */
    break;
}

Necesitamos una breakpalabra clave al final de cada caso para evitar que el siguiente caso se ejecute cuando finaliza el anterior. Este efecto de "cascada" puede ser útil en algunas formas creativas.

Puede agregar un caso "cajón de sastre" al final, etiquetado como default:

int a = 1;

switch (a) {
  case 0:
    /* do something */
    break;
  case 1:
    /* do something else */
    break;
  case 2:
    /* do something else */
    break;
  default:
    /* handle all the other cases */
    break;
}

Bucles

C nos ofrece tres formas de realizar un bucle: bucles for , bucles while y bucles do while . Todos le permiten iterar sobre arreglos, pero con algunas diferencias. Veámoslos en detalle.

Para bucles

La primera y probablemente la forma más común de realizar un ciclo es for loops .

Usando la forpalabra clave, podemos definir las reglas del bucle por adelantado y luego proporcionar el bloque que se ejecutará repetidamente.

Como esto:

for (int i = 0; i <= 10; i++) {
  /* instructions to be repeated */
}

El (int i = 0; i <= 10; i++)bloque contiene 3 partes de los detalles del bucle:

  • la condición inicial ( int i = 0)
  • la prueba ( i <= 10)
  • el incremento ( i++)

Primero definimos una variable de bucle, en este caso llamada i. ies un nombre de variable común que se utiliza para bucles, junto con jbucles anidados (un bucle dentro de otro bucle). Es solo una convención.

La variable se inicializa en el valor 0 y se realiza la primera iteración. Luego se incrementa como dice la parte de incremento ( i++en este caso, incrementando en 1), y todo el ciclo se repite hasta llegar al número 10.

Dentro del bloque principal del bucle podemos acceder a la variable ipara saber en qué iteración estamos. Este programa debe imprimir 0 1 2 3 4 5 5 6 7 8 9 10:

for (int i = 0; i <= 10; i++) {
  /* instructions to be repeated */
  printf("%u ", i);
}

Los bucles también pueden comenzar desde un número alto e ir a un número más bajo, como este:

for (int i = 10; i > 0; i--) {
  /* instructions to be repeated */
}

También puede incrementar la variable de bucle en 2 u otro valor:

for (int i = 0; i < 1000; i = i + 30) {
  /* instructions to be repeated */
}

Mientras que los bucles

Mientras que los bucles son más simples de escribir que un forbucle, porque requiere un poco más de trabajo de su parte.

En lugar de definir todos los datos del ciclo por adelantado cuando inicia el ciclo, como lo hace en el forciclo, whilesimplemente verifique una condición:

while (i < 10) {

}

Esto supone que iya está definido e inicializado con un valor.

Y este bucle será un bucle infinito a menos que incrementes la ivariable en algún punto dentro del bucle. Un bucle infinito es malo porque bloqueará el programa y no permitirá que suceda nada más.

Esto es lo que necesita para un ciclo while "correcto":

int i = 0;

while (i < 10) {
  /* do something */

  i++;
}

Hay una excepción a esto, y la veremos en un minuto. Antes, déjame presentarte do while.

Hacer mientras bucles

Los bucles while son geniales, pero puede haber momentos en los que necesite hacer una cosa en particular: desea ejecutar siempre un bloque y luego tal vez repetirlo.

Esto se hace usando la do whilepalabra clave. En cierto modo, es muy similar a un whilebucle, pero ligeramente diferente:

int i = 0;

do {
  /* do something */

  i++;
} while (i < 10);

El bloque que contiene el /* do something */comentario siempre se ejecuta al menos una vez, independientemente de la verificación de condición en la parte inferior.

Luego, hasta ique sea menor de 10, repetiremos el bloque.

Salir de un bucle usando break

En todos los bucles de C tenemos una forma de salir de un bucle en cualquier momento, inmediatamente, independientemente de las condiciones establecidas para el bucle.

Esto se hace usando la breakpalabra clave.

Esto es útil en muchos casos. Es posible que desee verificar el valor de una variable, por ejemplo:

for (int i = 0; i <= 10; i++) {
  if (i == 4 && someVariable == 10) {
    break;
  }
}

Tener esta opción para salir de un ciclo es particularmente interesante para los whileciclos (y do whiletambién), porque podemos crear ciclos aparentemente infinitos que terminan cuando ocurre una condición. Usted define esto dentro del bloque de bucle:

int i = 0;
while (1) {
  /* do something */

  i++;
  if (i == 10) break;
}

Es bastante común tener este tipo de bucle en C.

arreglos

Una matriz es una variable que almacena múltiples valores.

Cada valor en la matriz, en C, debe tener el mismo tipo . Esto significa que tendrá matrices de intvalores, matrices de doublevalores y más.

Puede definir una matriz de intvalores como esta:

int prices[5];

Siempre debe especificar el tamaño de la matriz. C no proporciona matrices dinámicas listas para usar (debe usar una estructura de datos como una lista vinculada para eso).

Puede usar una constante para definir el tamaño:

const int SIZE = 5;
int prices[SIZE];

Puede inicializar una matriz en el momento de la definición, así:

int prices[5] = { 1, 2, 3, 4, 5 };

Pero también puedes asignar un valor después de la definición, de esta forma:

int prices[5];

prices[0] = 1;
prices[1] = 2;
prices[2] = 3;
prices[3] = 4;
prices[4] = 5;

O, más práctico, usando un bucle:

int prices[5];

for (int i = 0; i < 5; i++) {
  prices[i] = i + 1;
}

Y puede hacer referencia a un elemento en la matriz usando corchetes después del nombre de la variable de la matriz, agregando un número entero para determinar el valor del índice. Como esto:

prices[0]; /* array item value: 1 */
prices[1]; /* array item value: 2 */

Los índices de matriz comienzan desde 0, por lo que una matriz con 5 elementos, como la pricesmatriz anterior, tendrá elementos que van desde prices[0]a prices[4].

Lo interesante de las matrices C es que todos los elementos de una matriz se almacenan secuencialmente, uno tras otro. No es algo que suceda normalmente con los lenguajes de programación de alto nivel.

Otra cosa interesante es esta: el nombre de la variable de la matriz, pricesen el ejemplo anterior, es un puntero al primer elemento de la matriz. Como tal, se puede utilizar como un puntero normal.

Más sobre punteros pronto.

Instrumentos de cuerda

En C, las cadenas son un tipo especial de matriz: una cadena es una matriz de charvalores:

char name[7];

Introduje el chartipo cuando introduje los tipos, pero en resumen, se usa comúnmente para almacenar letras del gráfico ASCII.

Una cadena se puede inicializar como inicializa una matriz normal:

char name[7] = { "F", "l", "a", "v", "i", "o" };

O más convenientemente con un literal de cadena (también llamado constante de cadena), una secuencia de caracteres entre comillas dobles:

char name[7] = "Flavio";

Puede imprimir una cadena mediante el printf()uso de %s:

printf("%s", name);

¿Notas cómo "Flavio" tiene 6 caracteres de largo, pero definí una matriz de 7 de longitud? ¿Por qué? Esto se debe a que el último carácter de una cadena debe ser un   0valor, el terminador de la cadena, y debemos dejarle espacio.

Es importante tener esto en cuenta, especialmente cuando se manipulan cadenas.

Hablando de manipular cadenas, hay una biblioteca estándar importante proporcionada por C: string.h.

Esta biblioteca es esencial porque abstrae muchos de los detalles de bajo nivel del trabajo con cadenas y nos proporciona un conjunto de funciones útiles.

Puede cargar la biblioteca en su programa agregando en la parte superior:

#include <string.h>

Y una vez que lo haga, tendrá acceso a:

  • strcpy()copiar una cadena sobre otra cadena
  • strcat()para agregar una cadena a otra cadena
  • strcmp()comparar dos cadenas para la igualdad
  • strncmp()para comparar los primeros ncaracteres de dos cadenas
  • strlen()para calcular la longitud de una cadena

y muchos muchos mas.

Punteros

Los punteros son una de las partes más confusas/desafiantes de C, en mi opinión. Especialmente si eres nuevo en la programación, pero también si vienes de un lenguaje de programación de nivel superior como Python o JavaScript.

En esta sección quiero presentarlos de la manera más simple pero no simplificada posible.

Un puntero es la dirección de un bloque de memoria que contiene una variable.

Cuando declaras un número entero como este:

int age = 37;

Podemos usar el &operador para obtener el valor de la dirección en memoria de una variable:

printf("%p", &age); /* 0x7ffeef7dcb9c */

Usé el %pformato especificado en printf()para imprimir el valor de la dirección.

Podemos asignar la dirección a una variable:

int *address = &age;

Usando int *addressen la declaración, no estamos declarando una variable entera, sino un puntero a un entero .

Podemos usar el operador de puntero *para obtener el valor de la variable a la que apunta una dirección:

int age = 37;
int *address = &age;
printf("%u", *address); /* 37 */

Esta vez estamos usando el operador de puntero nuevamente, pero como no es una declaración esta vez significa "el valor de la variable a la que apunta este puntero".

En este ejemplo, declaramos una agevariable y usamos un puntero para inicializar el valor:

int age;
int *address = &age;
*address = 37;
printf("%u", *address);

Cuando trabaje con C, encontrará que muchas cosas se basan en este concepto simple. Así que asegúrese de familiarizarse un poco con él ejecutando los ejemplos anteriores por su cuenta.

Los punteros son una gran oportunidad porque nos obligan a pensar en las direcciones de memoria y en cómo se organizan los datos.

Las matrices son un ejemplo. Cuando declaras una matriz:

int prices[3] = { 5, 4, 3 };

La pricesvariable es en realidad un puntero al primer elemento de la matriz. Puede obtener el valor del primer elemento usando esta printf()función en este caso:

printf("%u", *prices); /* 5 */

Lo bueno es que podemos obtener el segundo elemento agregando 1 al pricespuntero:

printf("%u", *(prices + 1)); /* 4 */

Y así sucesivamente para todos los demás valores.

También podemos hacer muchas buenas operaciones de manipulación de cadenas, ya que las cadenas son matrices bajo el capó.

También tenemos muchas más aplicaciones, incluido pasar la referencia de un objeto o una función para evitar consumir más recursos para copiarlo.

Funciones

Las funciones son la forma en que podemos estructurar nuestro código en subrutinas que podemos:

  1. dar un nombre a
  2. llamar cuando los necesitamos

A partir de su primer programa, un "¡Hola, mundo!", Inmediatamente hace uso de las funciones de C:

#include <stdio.h>

int main(void) {
    printf("Hello, World!");
}

La main()función es una función muy importante, ya que es el punto de entrada para un programa en C.

Aquí hay otra función:

void doSomething(int value) {
    printf("%u", value);
}

Las funciones tienen 4 aspectos importantes:

  1. tienen un nombre, por lo que podemos invocarlos ("llamarlos") más tarde
  2. especifican un valor de retorno
  3. pueden tener argumentos
  4. tienen un cuerpo, envuelto en llaves

El cuerpo de la función es el conjunto de instrucciones que se ejecutan cada vez que invocamos una función.

Si la función no tiene valor de retorno, puede usar la palabra clave voidantes del nombre de la función. De lo contrario, especifique el tipo de valor de retorno de la función ( intpara un número entero, floatpara un valor de punto flotante, const char *para una cadena, etc.).

No puede devolver más de un valor de una función.

Una función puede tener argumentos. Son opcionales. Si no los tiene, dentro de los paréntesis insertamos void, así:

void doSomething(void) {
   /* ... */
}

En este caso, cuando invoquemos la función, la llamaremos sin nada entre paréntesis:

doSomething();

Si tenemos un parámetro, especificamos el tipo y el nombre del parámetro, así:

void doSomething(int value) {
   /* ... */
}

Cuando invoquemos la función, pasaremos ese parámetro entre paréntesis, así:

doSomething(3);

Podemos tener múltiples parámetros, y si es así los separamos mediante una coma, tanto en la declaración como en la invocación:

void doSomething(int value1, int value2) {
   /* ... */
}

doSomething(3, 4);

Los parámetros se pasan por copia . Esto significa que si modifica value1, su valor se modifica localmente. El valor fuera de la función, donde se pasó en la invocación, no cambia.

Si pasa un puntero como parámetro, puede modificar ese valor de variable porque ahora puede acceder a él directamente usando su dirección de memoria.

No puede definir un valor predeterminado para un parámetro. C ++ puede hacer eso (y también los programas Arduino Language pueden hacerlo), pero C no puede.

Asegúrese de definir la función antes de llamarla, o el compilador generará una advertencia y un error:

➜  ~ gcc hello.c -o hello; ./hello
hello.c:13:3: warning: implicit declaration of
      function 'doSomething' is invalid in C99
      [-Wimplicit-function-declaration]
  doSomething(3, 4);
  ^
hello.c:17:6: error: conflicting types for
      'doSomething'
void doSomething(int value1, char value2) {
     ^
hello.c:13:3: note: previous implicit declaration
      is here
  doSomething(3, 4);
  ^
1 warning and 1 error generated.

La advertencia que recibe se refiere al pedido, que ya mencioné.

El error es por otra cosa, relacionado. Dado que C no "ve" la declaración de la función antes de la invocación, debe hacer suposiciones. Y asume la función de volver int. Sin embargo, la función devuelve void, de ahí el error.

Si cambia la definición de la función a:

int doSomething(int value1, int value2) {
  printf("%d %d\n", value1, value2);
  return 1;
}

solo obtendrías la advertencia, y no el error:

➜  ~ gcc hello.c -o hello; ./hello
hello.c:14:3: warning: implicit declaration of
      function 'doSomething' is invalid in C99
      [-Wimplicit-function-declaration]
  doSomething(3, 4);
  ^
1 warning generated.

En cualquier caso, asegúrese de declarar la función antes de usarla. Mueva la función hacia arriba o agregue el prototipo de función en un archivo de encabezado.

Dentro de una función, puedes declarar variables.

void doSomething(int value) {
  int doubleValue = value * 2;
}

Una variable se crea en el punto de invocación de la función y se destruye cuando finaliza la función. No es visible desde el exterior.

Dentro de una función, puede llamar a la función misma. Esto se llama recursividad y es algo que ofrece oportunidades peculiares.

Entrada y salida

C es un lenguaje pequeño y el "núcleo" de C no incluye ninguna funcionalidad de entrada/salida (E/S).

Esto no es algo exclusivo de C, por supuesto. Es común que el núcleo del lenguaje sea independiente de la E/S.

En el caso de C, la entrada/salida nos la proporciona la biblioteca estándar de C a través de un conjunto de funciones definidas en el stdio.harchivo de encabezado.

Puede importar esta biblioteca usando:

#include <stdio.h>

en la parte superior de su archivo C.

Esta librería nos proporciona, entre otras muchas funciones:

  • printf()
  • scanf()
  • sscanf()
  • fgets()
  • fprintf()

Antes de describir lo que hacen esas funciones, quiero tomarme un minuto para hablar sobre los flujos de E/S .

Tenemos 3 tipos de flujos de E/S en C:

  • stdin(entrada estándar)
  • stdout(salida estándar)
  • stderr(Error estándar)

Con las funciones de E/S siempre trabajamos con flujos. Una secuencia es una interfaz de alto nivel que puede representar un dispositivo o un archivo. Desde el punto de vista de C, no tenemos ninguna diferencia entre leer desde un archivo o leer desde la línea de comando: es un flujo de E/S en cualquier caso.

Eso es una cosa a tener en cuenta.

Algunas funciones están diseñadas para funcionar con un flujo específico, como printf(), que usamos para imprimir caracteres en stdout. Usando su contraparte más general fprintf(), podemos especificar en qué flujo escribir.

Ya que comencé a hablar de printf(), vamos a presentarlo ahora.

printf()es una de las primeras funciones que usará cuando aprenda a programar en C.

En su forma de uso más simple, le pasa un literal de cadena:

printf("hey!");

y el programa imprimirá el contenido de la cadena en la pantalla.

Puede imprimir el valor de una variable. Pero es un poco complicado porque necesita agregar un carácter especial, un marcador de posición, que cambia según el tipo de variable. Por ejemplo, usamos %dpara un dígito entero decimal con signo:

int age = 37;

printf("My age is %d", age);

Podemos imprimir más de una variable usando comas:

int age_yesterday = 37;
int age_today = 36;

printf("Yesterday my age was %d and today is %d", age_yesterday, age_today);

Hay otros especificadores de formato como %d:

  • %cpara un char
  • %spara un char
  • %fpara números de coma flotante
  • %ppara punteros

y muchos más.

Podemos usar caracteres de escape en printf(), como \nlos que podemos usar para hacer que la salida cree una nueva línea.

scanf()

printf()se utiliza como una función de salida. Quiero presentar una función de entrada ahora, para que podamos decir que podemos hacer todo el asunto de E/S: scanf().

Esta función se utiliza para obtener un valor del usuario que ejecuta el programa, desde la línea de comandos.

Primero debemos definir una variable que contendrá el valor que obtengamos de la entrada:

int age;

Luego llamamos scanf()con 2 argumentos: el formato (tipo) de la variable y la dirección de la variable:

scanf("%d", &age);

Si queremos obtener una cadena como entrada, recuerde que el nombre de una cadena es un puntero al primer carácter, por lo que no necesita el &carácter anterior:

char name[20];
scanf("%s", name);

Aquí hay un pequeño programa que usa tanto printf()y scanf():

#include <stdio.h>

int main(void) {
  char name[20];
  printf("Enter your name: ");
  scanf("%s", name);
  printf("you entered %s", name);
}

Alcance variable

Cuando defines una variable en un programa C, dependiendo de dónde la declares, tendrá un alcance diferente .

Esto significa que estará disponible en algunos lugares, pero no en otros.

La posición determina 2 tipos de variables:

  • variables globales
  • variables locales

Esta es la diferencia: una variable declarada dentro de una función es una variable local, así:

int main(void) {
  int age = 37;
}

Las variables locales solo son accesibles desde dentro de la función, y cuando la función termina, dejan de existir. Se borran de la memoria (con algunas excepciones).

Una variable definida fuera de una función es una variable global, como en este ejemplo:

int age = 37;

int main(void) {
  /* ... */
}

Las variables globales son accesibles desde cualquier función del programa, y ​​están disponibles durante toda la ejecución del programa, hasta que finaliza.

Mencioné que las variables locales ya no están disponibles después de que finaliza la función.

El motivo es que las variables locales se declaran en la pila de forma predeterminada, a menos que las asigne explícitamente en el montón mediante punteros. Pero luego tienes que administrar la memoria tú mismo.

Variables estáticas

Dentro de una función, puede inicializar una variable estática usando la staticpalabra clave.

Dije "dentro de una función" porque las variables globales son estáticas de forma predeterminada, por lo que no es necesario agregar la palabra clave.

¿Qué es una variable estática? Una variable estática se inicializa en 0 si no se especifica ningún valor inicial y conserva el valor entre las llamadas de función.

Considere esta función:

int incrementAge() {
  int age = 0;
  age++;
  return age;
}

Si llamamos incrementAge()una vez, lo obtendremos 1como valor de retorno. Si lo llamamos más de una vez, siempre obtendremos 1, porque agees una variable local y se reinicializa 0en cada llamada de función.

Si cambiamos la función a:

int incrementAge() {
  static int age = 0;
  age++;
  return age;
}

Ahora, cada vez que llamemos a esta función, obtendremos un valor incrementado:

printf("%d\n", incrementAge());
printf("%d\n", incrementAge());
printf("%d\n", incrementAge());

nos dará

1
2
3

También podemos omitir la inicialización agea 0 en static int age = 0;, y simplemente escribir static int age;porque las variables estáticas se establecen automáticamente en 0 cuando se crean.

También podemos tener arreglos estáticos. En este caso, cada elemento individual de la matriz se inicializa en 0:

int incrementAge() {
  static int ages[3];
  ages[0]++;
  return ages[0];
}

Variables globales

En esta sección quiero hablar más sobre la diferencia entre variables globales y locales .

Una variable local se define dentro de una función y solo está disponible dentro de esa función.

Como esto:

#include <stdio.h>

int main(void) {
  char j = 0;
  j += 10;
  printf("%u", j); //10
}

jno está disponible en ningún lugar fuera de la mainfunción.

Una variable global se define fuera de cualquier función, así:

#include <stdio.h>

char i = 0;

int main(void) {
  i += 10;
  printf("%u", i); //10
}

Cualquier función del programa puede acceder a una variable global. El acceso no se limita a la lectura del valor: la variable puede ser actualizada por cualquier función.

Debido a esto, las variables globales son una forma que tenemos de compartir los mismos datos entre funciones.

La principal diferencia con las variables locales es que la memoria asignada para las variables se libera una vez que finaliza la función.

Las variables globales solo se liberan cuando finaliza el programa.

Definiciones de tipo

La typedefpalabra clave en C le permite definir nuevos tipos.

A partir de los tipos C incorporados, podemos crear nuestros propios tipos, usando esta sintaxis:

typedef existingtype NEWTYPE

El nuevo tipo que creamos suele ser, por convención, en mayúsculas.

Esto es para distinguirlo más fácilmente, e inmediatamente reconocerlo como tipo.

Por ejemplo, podemos definir un nuevo NUMBERtipo que es un int:

typedef int NUMBER

y una vez que lo haga, puede definir nuevas NUMBERvariables:

NUMBER one = 1;

Ahora te preguntarás: ¿por qué? ¿Por qué no usar el tipo integrado en intsu lugar?

Bueno, typedefse vuelve realmente útil cuando se combina con dos cosas: tipos y estructuras enumerados.

Tipos enumerados

Usando las palabras clave typedefy enumpodemos definir un tipo que puede tener un valor u otro.

Es uno de los usos más importantes de la typedefpalabra clave.

Esta es la sintaxis de un tipo enumerado:

typedef enum {
  //...values
} TYPENAME;

El tipo enumerado que creamos suele ser, por convención, en mayúsculas.

Aquí hay un ejemplo simple:

typedef enum {
  true,
  false
} BOOLEAN;

C viene con un booltipo, por lo que este ejemplo no es realmente práctico, pero entiende la idea.

Otro ejemplo es definir los días de la semana:

typedef enum {
  monday,  
  tuesday,
  wednesday,
  thursday,
  friday,
  saturday,
  sunday
} WEEKDAY;

Aquí hay un programa simple que usa este tipo enumerado:

#include <stdio.h>

typedef enum {
  monday,  
  tuesday,
  wednesday,
  thursday,
  friday,
  saturday,
  sunday
} WEEKDAY;

int main(void) {
  WEEKDAY day = monday;

  if (day == monday) {
    printf("It's monday!"); 
  } else {
    printf("It's not monday"); 
  }
}

Cada elemento de la definición de enumeración se empareja con un número entero, internamente. Así que en este ejemplo mondayes 0, tuesdayes 1 y así sucesivamente.

Esto significa que el condicional podría haber sido if (day == 0)en lugar de if (day == monday), pero es mucho más sencillo para nosotros los humanos razonar con nombres en lugar de números, por lo que es una sintaxis muy conveniente.

Estructuras

Usando la structpalabra clave podemos crear estructuras de datos complejas usando tipos básicos de C.

Una estructura es una colección de valores de diferentes tipos. Las matrices en C están limitadas a un tipo, por lo que las estructuras pueden resultar muy interesantes en muchos casos de uso.

Esta es la sintaxis de una estructura:

struct <structname> {
  //...variables
};

Ejemplo:

struct person {
  int age;
  char *name;
};

Puede declarar variables que tengan como tipo esa estructura agregándolas después del corchete de cierre, antes del punto y coma, así:

struct person {
  int age;
  char *name;
} flavio;

O varios, como este:

struct person {
  int age;
  char *name;
} flavio, people[20];

En este caso, declaro una sola personvariable named flavio, y una matriz de 20 personnamed people.

También podemos declarar variables más adelante, usando esta sintaxis:

struct person {
  int age;
  char *name;
};

struct person flavio;

Podemos inicializar una estructura en el momento de la declaración:

struct person {
  int age;
  char *name;
};

struct person flavio = { 37, "Flavio" };

y una vez que tenemos una estructura definida, podemos acceder a los valores en ella usando un punto:

struct person {
  int age;
  char *name;
};

struct person flavio = { 37, "Flavio" };
printf("%s, age %u", flavio.name, flavio.age);

También podemos cambiar los valores usando la sintaxis de puntos:

struct person {
  int age;
  char *name;
};

struct person flavio = { 37, "Flavio" };

flavio.age = 38;

Las estructuras son muy útiles porque podemos pasarlas como parámetros de función, o devolver valores, incrustando varias variables dentro de ellas. Cada variable tiene una etiqueta.

Es importante tener en cuenta que las estructuras se pasan por copia , a menos, por supuesto, que pase un puntero a una estructura, en cuyo caso se pasa por referencia.

Usando typedefpodemos simplificar el código cuando se trabaja con estructuras.

Veamos un ejemplo:

typedef struct {
  int age;
  char *name;
} PERSON;

La estructura que creamos usando typedefsuele ser, por convención, en mayúsculas.

Ahora podemos declarar nuevas PERSONvariables como esta:

PERSON flavio;

y podemos inicializarlos en la declaración de esta manera:

PERSON flavio = { 37, "Flavio" };

Parámetros de línea de comando

En sus programas C, es posible que deba aceptar parámetros de la línea de comando cuando se inicia el comando.

Para necesidades simples, todo lo que necesita hacer para hacerlo es cambiar la main()firma de la función de

int main(void)

a

int main (int argc, char *argv[])

argces un número entero que contiene la cantidad de parámetros que se proporcionaron en la línea de comando.

argves una matriz de cadenas.

Cuando se inicia el programa, se nos proporcionan los argumentos en esos 2 parámetros.

Tenga en cuenta que siempre hay al menos un elemento en la argvmatriz: el nombre del programa

Tomemos el ejemplo del compilador de C que usamos para ejecutar nuestros programas, así:

gcc hello.c -o hello

Si este fuera nuestro programa, tendríamos que argcser 4 y argvser una matriz que contiene

  • gcc
  • hello.c
  • -o
  • hello

Escribamos un programa que imprima los argumentos que recibe:

#include <stdio.h>

int main (int argc, char *argv[]) {
  for (int i = 0; i < argc; i++) {
    printf("%s\n", argv[i]);
  }
}

Si el nombre de nuestro programa es helloy lo ejecutamos así: ./hello, obtendríamos esto como resultado:

./hello

Si pasamos algunos parámetros aleatorios, como este: ./hello a b cobtendremos esta salida en la terminal:

./hello
a
b
c

Este sistema funciona muy bien para necesidades simples. Para necesidades más complejas, existen paquetes de uso común como getopt .

Archivos de encabezados

Los programas simples se pueden poner en un solo archivo. Pero cuando su programa crece, es imposible guardarlo todo en un solo archivo.

Puede mover partes de un programa a un archivo separado. Luego crea un archivo de encabezado .

Un archivo de encabezado se parece a un archivo C normal, excepto que termina .hcon .c. En lugar de las implementaciones de sus funciones y las otras partes de un programa, contiene las declaraciones .

Ya usó archivos de encabezado cuando usó la printf()función por primera vez, u otra función de E/S, y tuvo que escribir:

#include <stdio.h>

para usarlo

#includees una directiva de preprocesador.

El preprocesador va y busca el stdio.harchivo en la biblioteca estándar porque usó corchetes a su alrededor. Para incluir sus propios archivos de encabezado, usará comillas, como esta:

#include "myfile.h"

Lo anterior buscará myfile.hen la carpeta actual.

También puede utilizar una estructura de carpetas para bibliotecas:

#include "myfolder/myfile.h"

Veamos un ejemplo. Este programa calcula los años desde un año dado:

#include <stdio.h>

int calculateAge(int year) {
  const int CURRENT_YEAR = 2020;
  return CURRENT_YEAR - year;
}

int main(void) {
  printf("%u", calculateAge(1983));
}

Supongamos que quiero mover la calculateAgefunción a un archivo separado.

Creo un calculate_age.carchivo:

int calculateAge(int year) {
  const int CURRENT_YEAR = 2020;
  return CURRENT_YEAR - year;
}

Y un calculate_age.harchivo donde pongo la función prototipo , que es igual a la función del .carchivo, excepto el cuerpo:

int calculateAge(int year);

Ahora, en el .carchivo principal, podemos ir y eliminar la calculateAge()definición de la función, y podemos importar calculate_age.h, lo que hará que la calculateAge()función esté disponible:

#include <stdio.h>
#include "calculate_age.h"

int main(void) {
  printf("%u", calculateAge(1983));
}

No olvide que para compilar un programa compuesto por varios archivos, debe enumerarlos todos en la línea de comando, así:

gcc -o main main.c calculate_age.c

Y con configuraciones más complejas, se necesita un Makefile para decirle al compilador cómo compilar el programa.

el preprocesador

El preprocesador es una herramienta que nos ayuda mucho a la hora de programar en C. Forma parte del Estándar C, al igual que el lenguaje, el compilador y la biblioteca estándar.

Analiza nuestro programa y se asegura de que el compilador obtenga todo lo que necesita antes de continuar con el proceso.

¿Qué hace, en la práctica?

Por ejemplo, busca todos los archivos de encabezado que incluye con la #includedirectiva.

También mira cada constante que definiste usando #definey la sustituye con su valor real.

Eso es solo el comienzo. Mencioné esas 2 operaciones porque son las más comunes. El preprocesador puede hacer mucho más.

¿Te diste cuenta #includey tuviste #defineun #al principio? Eso es común a todas las directivas de preprocesador. Si una línea comienza con #, eso lo soluciona el preprocesador.

Condicionales

Una de las cosas que podemos hacer es usar condicionales para cambiar cómo se compilará nuestro programa, dependiendo del valor de una expresión.

Por ejemplo podemos comprobar si la DEBUGconstante es 0:

#include <stdio.h>

const int DEBUG = 0;

int main(void) {
#if DEBUG == 0
  printf("I am NOT debugging\n");
#else
  printf("I am debugging\n");
#endif
}

constantes simbólicas

Podemos definir una constante simbólica :

#define VALUE 1
#define PI 3.14
#define NAME "Flavio"

Cuando usamos NOMBRE o PI o VALOR en nuestro programa, el preprocesador reemplaza su nombre con el valor antes de ejecutar el programa.

Las constantes simbólicas son muy útiles porque podemos dar nombres a los valores sin crear variables en el momento de la compilación.

macros

Con #definetambién podemos definir una macro . La diferencia entre una macro y una constante simbólica es que una macro puede aceptar un argumento y normalmente contiene código, mientras que una constante simbólica es un valor:

#define POWER(x) ((x) * (x))

Observe los paréntesis alrededor de los argumentos: esta es una buena práctica para evitar problemas cuando se reemplaza la macro en el proceso de precompilación.

Entonces podemos usarlo en nuestro código así:

printf("%u\n", POWER(4)); //16

La gran diferencia con las funciones es que las macros no especifican el tipo de sus argumentos o valores devueltos, lo que puede ser útil en algunos casos.

Las macros, sin embargo, están limitadas a definiciones de una línea.

Si está definido

Podemos verificar si se define una constante simbólica o una macro usando #ifdef:

#include <stdio.h>
#define VALUE 1

int main(void) {
#ifdef VALUE
  printf("Value is defined\n");
#else
  printf("Value is not defined\n");
#endif
}

También tenemos #ifndevque comprobar lo contrario (macro no definido).

También podemos usar #if definedy #if !definedpara hacer la misma tarea.

Es común envolver algún bloque de código en un bloque como este:

#if 0

#endif

para evitar temporalmente que se ejecute, o para usar una constante simbólica DEBUG:

#define DEBUG 0

#if DEBUG
  //code only sent to the compiler
  //if DEBUG is not 0
#endif

Constantes simbólicas predefinidas que puede utilizar

El preprocesador también define una cantidad de constantes simbólicas que puede usar, identificadas por los 2 guiones bajos antes y después del nombre, que incluyen:

  • __LINE__se traduce a la línea actual en el archivo de código fuente
  • __FILE__se traduce al nombre del archivo
  • __DATE__se traduce a la fecha de compilación, en el Mmm gg aaaaformato
  • __TIME__se traduce al tiempo de compilación, en el hh:mm:ssformato

Conclusión

¡Muchas gracias por leer este manual!

Espero que te sirva de inspiración para saber más sobre C. 

Esta historia se publicó originalmente en https://www.freecodecamp.org/news/the-c-beginners-handbook/

#cprogramming 

Manual Para Principiantes De C En Solo Unas Pocas Horas

Cビギナーズハンドブック:わずか数時間でCプログラミング言語の基本を学ぶ

このC初心者向けハンドブックは、80/20の法則に従います。20%の時間でCプログラミング言語の80%を学習します。

このアプローチにより、言語の包括的な概要がわかります。

このハンドブックは、Cに関連するすべてを網羅しようとはしていません。言語のコアに焦点を当て、より複雑なトピックを単純化しようとしています。

注:このC初心者向けハンドブックのPDF版とePub版はこちらから入手できます

楽しみ!

Cの紹介

Cはおそらく最も広く知られているプログラミング言語です。これは、世界中のコンピュータサイエンスコースの参照言語として使用されており、おそらく、PythonやJavaとともに、人々が学校で最もよく学ぶ言語です。

Pascalに次ぐ2番目のプログラミング言語だったことを覚えています。

Cは、学生がプログラミングを学ぶために使用するものだけではありません。アカデミックな言語ではありません。そして、Cはかなり低レベルのプログラミング言語であるため、これは最も簡単な言語ではないと思います。

現在、Cは組み込みデバイスで広く使用されており、Linuxを使用して構築されたほとんどのインターネットサーバーに電力を供給しています。LinuxカーネルはCを使用して構築されており、これはCがすべてのAndroidデバイスのコアに電力を供給することも意味します。Cコードは全世界のかなりの部分を実行していると言えます。たった今。かなり注目に値する。

それが作成されたとき、Cはマシン間で移植可能であったため、高級言語と見なされていました。今日、私たちは、おそらくNode.jsまたはPythonを使用して、WindowsまたはLinux上のMacで作成されたプログラムを実行できることを当然のことと思っています。

昔々、これはまったくそうではありませんでした。Cがテーブルにもたらしたのは、実装が簡単で、さまざまなマシンに簡単に移植できるコンパイラーを備えた言語でした。

コンパイラーについて言いました。Cは、Go、Java、Swift、Rustなどのコンパイル済みプログラミング言語です。Python、Ruby、JavaScriptなどの他の一般的なプログラミング言語が解釈されます。違いは一貫しています。コンパイルされた言語は、直接実行および配布できるバイナリファイルを生成します。

Cはガベージコレクションではありません。これは、自分でメモリを管理する必要があることを意味します。これは複雑な作業であり、バグを防ぐために多くの注意を払う必要がありますが、CがArduinoのような組み込みデバイス用のプログラムを作成するのに理想的な理由でもあります。

Cは、その下にあるマシンの複雑さと機能を隠しません。何ができるかを知ったら、あなたにはたくさんの力があります。

今から最初のCプログラムを紹介したいと思います。これを「Hello、World!」と呼びます。

こんにちはC

#include <stdio.h>

int main(void) {
    printf("Hello, World!");
}

プログラムのソースコードについて説明しましょう。最初にstdioライブラリをインポートします(名前は標準の入出力ライブラリを表します)。

このライブラリを使用すると、入出力関数にアクセスできます。

Cはその核となる非常に小さな言語であり、核の一部ではないものはすべてライブラリによって提供されます。これらのライブラリの一部は通常のプログラマーによって構築され、他の人が使用できるようになっています。他のいくつかのライブラリがコンパイラに組み込まれています。のようstdioに、他の人。

stdio関数を提供するライブラリですprintf()

この関数は関数にラップされていmain()ます。このmain()関数は、Cプログラムのエントリポイントです。

しかし、とにかく、関数とは何ですか?

関数は、1つ以上の引数を取り、単一の値を返すルーチンです。

の場合main()、関数は引数を取得せず、整数を返します。void引数にキーワードを使用intし、戻り値にキーワードを使用してそれを識別します。

関数には、中括弧で囲まれた本体があります。本体の中には、関数がその操作を実行するために必要なすべてのコードがあります。

ご覧のprintf()とおり、関数の記述は異なります。戻り値は定義されておらず、二重引用符で囲まれた文字列を渡します。引数のタイプは指定しませんでした。

これは関数の呼び出しだからです。stdioライブラリ内のどこかで、次のprintfように定義されます

int printf(const char *format, ...);

これが今何を意味するのかを理解する必要はありませんが、要するに、これが定義です。そして、を呼び出すとprintf("Hello, World!");、そこで関数が実行されます。

main()上で定義した関数:

#include <stdio.h>

int main(void) {
    printf("Hello, World!");
}

プログラムの実行時にオペレーティングシステムによって実行されます。

Cプログラムを実行するにはどうすればよいですか?

前述のように、Cはコンパイルされた言語です。プログラムを実行するには、最初にプログラムをコンパイルする必要があります。LinuxまたはmacOSコンピュータには、すでにCコンパイラが組み込まれています。Windowsの場合、Windows Subsystem for Linux(WSL)を使用できます。

いずれの場合も、ターミナルウィンドウを開くgccと、と入力できます。このコマンドは、ファイルを指定しなかったことを示すエラーを返す必要があります。

スクリーンショット-2020-01-29-at-10.10.50

それは良い。これは、Cコンパイラが存在し、使用を開始できることを意味します。

次に、上記のプログラムをhello.cファイルに入力します。任意のエディターを使用できますが、簡単にするためnanoに、コマンドラインでエディターを使用します。

スクリーンショット-2020-01-29-at-10.11.39

プログラムを入力します。

スクリーンショット-2020-01-29-at-10.16.52

次にを押しctrl-Xて終了します。

スクリーンショット-2020-01-29-at-10.18.11

キーを押しyて確認し、Enterキーを押してファイル名を確認します。

スクリーンショット-2020-01-29-at-10.18.15

これで、ターミナルに戻る必要があります。

スクリーンショット-2020-01-29-at-10.13.46

ここで入力します

gcc hello.c -o hello

プログラムはエラーを出さないはずです:

スクリーンショット-2020-01-29-at-10.16.31

helloただし、実行可能ファイルが生成されているはずです。ここで入力します

./hello

それを実行するには:

スクリーンショット-2020-01-29-at-10.19.20

./プログラム名の前にコマンドを追加して、コマンドが現在のフォルダーにあることを端末に通知します

素晴らしい!

ここで、を呼び出すとls -al hello、プログラムのサイズがわずか12KBであることがわかります。

スクリーンショット-2020-01-29-at-10.19.55

これはCの長所の1つです。高度に最適化されており、リソースの量が非常に限られている組み込みデバイスにこれが適している理由の1つでもあります。

変数とタイプ

Cは静的に型付けされた言語です。

これは、すべての変数に関連付けられた型があり、この型はコンパイル時に認識されることを意味します。

これは、Python、JavaScript、PHP、およびその他のインタープリター言語で変数を操作する方法とは大きく異なります。

Cで変数を作成するときは、宣言時に変数の型を指定する必要があります。

この例では、変数ageを次の型で初期化しますint

int age;

変数名には、大文字または小文字を含めることができ、数字とアンダースコア文字を含めることができますが、数字で始めることはできません。AGEおよびAge10は有効な変数名ですが、そうで1ageはありません。

初期値を指定して、宣言時に変数を初期化することもできます。

int age = 37;

変数を宣言すると、プログラムコードで使用できるようになります。=たとえば、のように演算子を使用して、いつでもその値を変更できますage = 100;(新しい値が同じタイプの場合)。

この場合:

#include <stdio.h>

int main(void) {
    int age = 0;
    age = 37.2;
    printf("%u", age);
}

コンパイラはコンパイル時に警告を発し、10進数を整数値に変換します。

Cの組み込みデータ型は、、、、、、、、、intです。それらについてもっと知りましょう。charshortlongfloatdoublelong double

整数

Cは、整数値を定義するために次のタイプを提供します。

  • char
  • int
  • short
  • long

ほとんどの場合int、整数を格納するためにを使用する可能性があります。ただし、場合によっては、他の3つのオプションのいずれかを選択することをお勧めします。

このcharタイプは、ASCIIチャートの文字を格納するために一般的に使用されますが、から-128までの小さな整数を保持するために使用できます127。少なくとも1バイトかかります。

int少なくとも2バイトかかります。short少なくとも2バイトかかります。long少なくとも4バイトかかります。

ご覧のとおり、異なる環境で同じ値が保証されるわけではありません。表示のみです。問題は、各データ型に格納できる正確な数が実装とアーキテクチャに依存することです。

shortを超えないことが保証されていますintlongそして、私たちはより短くないことが保証されていますint

ANSI C仕様規格は、各タイプの最小値を決定します。そのおかげで、少なくとも、自由に使用できると期待できる最小値を知ることができます。

ArduinoでCをプログラミングしている場合、ボードが異なれば制限も異なります。

Arduino Unoボードに、intからまでの範囲の2バイトの値を格納-32,76832,767ます。Arduino MKR 1010では、からまでintの範囲の4バイトの値を格納します。かなり大きな違いです。-2,147,483,6482,147,483,647

すべてのArduinoボードで、からまでshortの範囲の2バイトの値を格納します。からまでの範囲の4バイトを格納します。-32,76832,767long-2,147,483,6482,147,483,647

符号なし整数

上記のすべてのデータ型についてunsigned、負の数ではなく、0から範囲を開始するように追加できます。多くの場合、これは理にかなっています。

  • unsigned char0から少なくともまでの範囲になります255
  • unsigned int0から少なくともまでの範囲になります65,535
  • unsigned short0から少なくともまでの範囲になります65,535
  • unsigned long0から少なくともまでの範囲になります4,294,967,295

オーバーフローの問題

これらすべての制限を考えると、疑問が生じる可能性があります。数が制限を超えないようにするにはどうすればよいでしょうか。そして、制限を超えた場合はどうなりますか?

あなたがunsigned int255で数を持っていて、それを増やすならば、あなたは見返りに256を得るでしょう。予想通り。unsigned char255の数値があり、それをインクリメントすると、代わりに0が返されます。初期値からリセットします。

あなたがunsigned char255の数を持っていて、それに10を加えると、あなたはその数を得るでしょう9

#include <stdio.h>

int main(void) {
  unsigned char j = 255;
  j = j + 10;
  printf("%u", j); /* 9 */
}

符号付きの値がない場合、動作は未定義です。基本的に、この場合のように、変化する可能性のある膨大な数が得られます。

#include <stdio.h>

int main(void) {
  char j = 127;
  j = j + 10;
  printf("%u", j); /* 4294967177 */
}

言い換えると、Cは型の制限を超えないように保護しません。あなたはこれを自分で世話する必要があります。

間違ったタイプを宣言するときの警告

変数を宣言して間違った値で初期化すると、gccコンパイラー(おそらく使用しているもの)は次のように警告する必要があります。

#include <stdio.h>

int main(void) {
  char j = 1000;
}
hello.c:4:11: warning: implicit conversion 
  from 'int' to
      'char' changes value from 1000 to -24
      [-Wconstant-conversion]
        char j = 1000;
             ~   ^~~~
1 warning generated.

また、直接割り当てで警告します。

#include <stdio.h>

int main(void) {
  char j;
  j = 1000;
}

ただし、たとえば次のように使用して数を増やした場合はそうではありません+=

#include <stdio.h>

int main(void) {
  char j = 0;
  j += 1000;
}

浮動小数点数

浮動小数点型は、整数よりもはるかに大きな値のセットを表すことができます。また、整数ではできない分数を表すこともできます。

浮動小数点数を使用して、数値を10進数に10の累乗を掛けたものとして表します。

浮動小数点数は次のように書かれている場合があります

  • 1.29e-3
  • -2.3e+5

そして他の一見奇妙な方法で。

次のタイプ:

  • float
  • double
  • long double

小数点付きの数値を表すために使用されます(浮動小数点タイプ)。すべてが正の数と負の数の両方を表すことができます。

C実装の最小要件は、float10^-37から10^+ 37の範囲を表すことができ、通常は32ビットを使用して実装されます。doubleより大きな数のセットを表すことができます。long doubleさらに多くの数を保持できます。

整数値の場合と同様に、正確な数値は実装によって異なります。

最新のMacでは、afloatは32ビットで表され、24ビットの精度があります。指数のエンコードには8ビットが使用されます。

数値は64​​ビットで表されdouble、精度は53ビットです。指数のエンコードには11ビットが使用されます。

タイプlong doubleは80ビットで表され、64の有効ビットの精度があります。指数のエンコードには15ビットが使用されます。

特定のコンピューターで、タイプの特定のサイズをどのように判断できますか?あなたはそれをするためのプログラムを書くことができます:

#include <stdio.h>

int main(void) {
  printf("char size: %lu bytes\n", sizeof(char));
  printf("int size: %lu bytes\n", sizeof(int));
  printf("short size: %lu bytes\n", sizeof(short));
  printf("long size: %lu bytes\n", sizeof(long));
  printf("float size: %lu bytes\n", sizeof(float));
  printf("double size: %lu bytes\n", 
    sizeof(double));
  printf("long double size: %lu bytes\n", 
    sizeof(long double));
}

私のシステム、最新のMacでは、次のように出力されます。

char size: 1 bytes
int size: 4 bytes
short size: 2 bytes
long size: 8 bytes
float size: 4 bytes
double size: 8 bytes
long double size: 16 bytes

定数

定数について話しましょう。

定数は変数と同様に宣言されますが、constキーワードが前に付けられ、常に値を指定する必要がある点が異なります。

このような:

const int age = 37;

これは完全に有効なCですが、次のように定数を大文字で宣言するのが一般的です。

const int AGE = 37;

これは単なる慣例ですが、Cプログラムを読み書きするときに、読みやすさが向上するため、非常に役立ちます。大文字の名前は定数を意味し、小文字の名前は変数を意味します。

定数名は、変数名と同じ規則に従います。大文字または小文字を含めることができ、数字とアンダースコア文字を含めることができますが、数字で始めることはできません。AGEおよびAge10は有効な変数名ですが、そうで1AGEはありません。

定数を定義する別の方法は、次の構文を使用することです。

#define AGE 37

=この場合、タイプを追加する必要はなく、等号も必要ありません。また、最後のセミコロンを省略します。

Cコンパイラは、コンパイル時に、指定された値から型を推測します。

演算子

Cは、データの操作に使用できるさまざまな演算子を提供します。

特に、オペレーターのさまざまなグループを識別できます。

  • 算術演算子
  • 比較演算子
  • 論理演算子
  • 複合代入演算子
  • ビット演算子
  • ポインタ演算子
  • 構造演算子
  • その他の演算子

このセクションでは、2つの虚数変数を使用してab例としてそれらすべてを詳しく説明します。

物事を単純にするために、ビット演算子、構造演算子、およびポインター演算子をこのリストから除外しています。

算術演算子

このマクログループでは、二項演算子と単項演算子を分離します。

二項演算子は、次の2つのオペランドを使用して機能します。

オペレーター名前
=割り当てa = b
+添加a + b
-減算a - b
*乗算a * b
/分割a / b
%モジュロa % b

単項演算子は1つのオペランドのみを取ります。

オペレーター名前
+単項プラス+a
-単項マイナス-a
++インクリメントa++また++a
--デクリメントa--また--a

との違いはa++、使用後に変数++aa++インクリメントすることです。使用する前に変数をインクリメントします。a++aa

例えば:

int a = 2;
int b;
b = a++ /* b is 2, a is 3 */
b = ++a /* b is 4, a is 4 */

同じことがデクリメント演算子にも当てはまります。

比較演算子

オペレーター名前
==等しい演算子a == b
!=等しくない演算子a != b
>より大きいa > b
<未満a < b
>=以上a >= b
<=以下a <= b

論理演算子

  • !NOT(例!a:)
  • &&AND(例a && b:)
  • ||または(例a || b:)

これらの演算子は、ブール値を操作する場合に最適です。

複合代入演算子

これらの演算子は、割り当てを実行すると同時に算術演算を実行するのに役立ちます。

オペレーター名前
+=追加の割り当てa += b
-=減算の割り当てa -= b
*=乗算の割り当てa *= b
/=部門の割り当てa /= b
%=モジュロ割り当てa %= b

三項演算子

三項演算子は、3つのオペランドで機能するCの唯一の演算子であり、条件式を表現するための短い方法です。

これはそれがどのように見えるかです:

<condition> ? <expression> : <expression>

例:

a ? b : c

aがと評価された場合truebステートメントが実行されます。それ以外の場合cはです。

三項演算子は、表現するのが短く、式にインライン化できることを除いて、機能的にはif/else条件と同じです。

のサイズ

sizeof演算子は、渡したオペランドのサイズを返します。変数、または型を渡すこともできます。

使用例:

#include <stdio.h>

int main(void) {
  int age = 37;
  printf("%ld\n", sizeof(age));
  printf("%ld", sizeof(int));
}

演算子の優先順位

これらすべての演算子(およびビット単位、構造演算子、ポインター演算子など、この投稿では取り上げていません)を使用して、これらを1つの式で一緒に使用する場合は注意が必要です。

次の操作があるとします。

int a = 2;
int b = 4;
int c = b + a * a / b - a;

の価値はc何ですか?乗算と除算の前に加算が実行されますか?

このパズルを解くのに役立つ一連のルールがあります。

優先順位の低いものから高いものの順に、次のようになります。

  • 代入=演算子
  • および二+演算子-
  • *および/演算子_
  • および+単項-演算子

演算子には結合法則もあり、単項演算子と代入を除いて常に左から右になります。

の:

int c = b + a * a / b - a;

最初にを実行しa * a / bます。これは左から右であるため、に分離しa * aて結果を得ることができます/ b2 * 2 = 44 / 4 = 1

次に、合計と減算を実行できます:4+1-2。の値はcです3

ただし、いずれの場合も、かっこを使用して同様の式を読みやすく、理解しやすくすることができることを理解してください。

括弧は他の何よりも優先されます。

上記の式の例は、次のように書き直すことができます。

int c = b + ((a * a) / b) - a;

そんなに考える必要はありません。

条件付き

どのプログラミング言語でも、プログラマーは選択を実行できます。

Xを実行したい場合もあれば、Yを実行したい場合もあります。

データを確認し、そのデータの状態に基づいて選択したいと思います。

Cは、そのための2つの方法を提供します。

1つ目はヘルパーをif含むステートメントで、2つ目はステートメントです。elseswitch

もしも

ステートメントではif、条件が真であるかどうかを確認してから、中括弧で囲まれたブロックを実行できます。

int a = 1;

if (a == 1) {
  /* do something */
}

else元の条件がfalseであることが判明した場合は、ブロックを追加して別のブロックを実行できます。

int a = 1;

if (a == 2) {
  /* do something */
} else {
  /* do something else */
}

==バグの一般的な原因の1つに注意してください。代入演算子ではなく、常に比較演算子を使用して=ください。そうしないとif、引数が次の場合を除いて、条件付きチェックは常にtrueになります0

int a = 0;

if (a = 0) {
  /* never invoked */
}

なぜこれが起こるのですか?条件付きチェックはブール結果(比較の結果)を検索するため、0数値は常にfalse値に等しくなります。負の数を含め、他のすべてが真実です。

複数のステートメントをスタックすることにより、複数のelseブロックを持つことができます。if

int a = 1;

if (a == 2) {
  /* do something */
} else if (a == 1) {
  /* do something else */
} else {
  /* do something else again */
}

スイッチ

おそらく変数の正確な値をチェックする必要があるために、チェックを実行するためにif / else / ifブロックを実行する必要がある場合は、switch非常に便利です。

case条件として変数を指定し、期待する値ごとに一連のエントリポイントを指定できます。

int a = 1;

switch (a) {
  case 0:
    /* do something */
    break;
  case 1:
    /* do something else */
    break;
  case 2:
    /* do something else */
    break;
}

break前のケースが終了したときに次のケースが実行されないように、各ケースの最後にキーワードが必要です。この「カスケード」効果は、いくつかの創造的な方法で役立ちます。

最後に「キャッチオール」ケースを追加して、次のラベルを付けることができますdefault

int a = 1;

switch (a) {
  case 0:
    /* do something */
    break;
  case 1:
    /* do something else */
    break;
  case 2:
    /* do something else */
    break;
  default:
    /* handle all the other cases */
    break;
}

ループ

Cは、ループを実行する3つの方法を提供します。forループwhileループ、およびdowhileループです。これらはすべて、配列を反復処理できますが、いくつかの違いがあります。それらを詳しく見てみましょう。

forループ

ループを実行する最初の、そしておそらく最も一般的な方法は、forループです。

キーワードを使用して、ループのルールforを事前に定義してから、繰り返し実行されるブロックを提供できます。

このような:

for (int i = 0; i <= 10; i++) {
  /* instructions to be repeated */
}

(int i = 0; i <= 10; i++)ブロックには、ループの詳細の3つの部分が含まれています。

  • 初期条件(int i = 0
  • テスト(i <= 10
  • 増分(i++

最初にループ変数を定義します。この場合は。という名前iです。ネストされたループ(別のループ内のループ)iとともに、ループに使用される一般的な変数名です。jそれは単なる慣習です。

変数は0の値で初期化され、最初の反復が実行されます。次に、増分部分に示されているように増分され(i++この場合、1ずつ増分されます)、数値10に到達するまですべてのサイクルが繰り返されます。

ループのメインブロック内で、変数にアクセスiして、どの反復であるかを知ることができます。このプログラムは印刷する必要があります0 1 2 3 4 5 5 6 7 8 9 10

for (int i = 0; i <= 10; i++) {
  /* instructions to be repeated */
  printf("%u ", i);
}

ループは、次のように、大きい数値から開始して、小さい数値に進むこともできます。

for (int i = 10; i > 0; i--) {
  /* instructions to be repeated */
}

ループ変数を2または別の値でインクリメントすることもできます。

for (int i = 0; i < 1000; i = i + 30) {
  /* instructions to be repeated */
}

whileループ

一方、ループはループよりも記述が簡単です。これは、forループの方が少し作業が必要になるためです。

ループの場合のように、ループを開始するときにすべてのループデータを事前に定義する代わりにforwhile条件を確認するだけです。

while (i < 10) {

}

iこれは、がすでに定義され、値で初期化されていることを前提としています。

また、ループ内のある時点で変数をインクリメントしない限り、このループは無限ループになります。i無限ループはプログラムをブロックし、他に何も起こらないので悪いです。

これは、「正しい」whileループに必要なものです。

int i = 0;

while (i < 10) {
  /* do something */

  i++;
}

これには1つの例外があり、1分後に表示されます。前に、紹介させてくださいdo while

whileループを実行します

whileループは素晴らしいですが、特定のことを行う必要がある場合があります。常にブロックを実行してから、それを繰り返す必要がある場合があります。

これは、do whileキーワードを使用して行われます。ある意味、ループと非常に似ていwhileますが、わずかに異なります。

int i = 0;

do {
  /* do something */

  i++;
} while (i < 10);

コメントを含むブロックは/* do something */、下部の条件チェックに関係なく、常に少なくとも1回は実行されます。

次に、iが10未満になるまで、ブロックを繰り返します。

breakを使用してループから抜け出す

すべてのCループでは、ループに設定された条件に関係なく、いつでもすぐにループから抜け出す方法があります。

これは、breakキーワードを使用して行われます。

これは多くの場合に役立ちます。たとえば、変数の値を確認することをお勧めします。

for (int i = 0; i <= 10; i++) {
  if (i == 4 && someVariable == 10) {
    break;
  }
}

ループから抜け出すためのこのオプションがあると、whileループ(およびループdo while)にとって特に興味深いものになります。これは、条件が発生したときに終了する、一見無限のループを作成できるためです。これをループブロック内で定義します。

int i = 0;
while (1) {
  /* do something */

  i++;
  if (i == 10) break;
}

この種のループがCで発生するのはかなり一般的です。

配列

配列は、複数の値を格納する変数です。

Cの配列内のすべての値は、同じ型である必要があります。これは、int値の配列、値の配列などがあることを意味doubleします。

int次のように値の配列を定義できます。

int prices[5];

常に配列のサイズを指定する必要があります。Cは、すぐに使用できる動的配列を提供していません(そのためには、リンクリストのようなデータ構造を使用する必要があります)。

定数を使用してサイズを定義できます。

const int SIZE = 5;
int prices[SIZE];

次のように、定義時に配列を初期化できます。

int prices[5] = { 1, 2, 3, 4, 5 };

ただし、次のようにして、定義の後に値を割り当てることもできます。

int prices[5];

prices[0] = 1;
prices[1] = 2;
prices[2] = 3;
prices[3] = 4;
prices[4] = 5;

または、より実用的には、ループを使用します。

int prices[5];

for (int i = 0; i < 5; i++) {
  prices[i] = i + 1;
}

また、配列変数名の後に角かっこを使用し、整数を追加してインデックス値を決定することにより、配列内の項目を参照できます。このような:

prices[0]; /* array item value: 1 */
prices[1]; /* array item value: 2 */

配列インデックスは0から始まるため、上記の配列のように5つの項目を持つ配列には、からまでpricesの範囲の項目があります。prices[0]prices[4]

C配列の興味深い点は、配列のすべての要素が順番に順番に格納されることです。高水準プログラミング言語では通常発生することではありません。

もう1つの興味深い点は、これです。prices上記の例では、配列の変数名は、配列の最初の要素へのポインターです。そのため、通常のポインタのように使用できます。

ポインタの詳細はすぐに。

文字列

Cでは、文字列は1つの特別な種類の配列です。文字列はchar値の配列です。

char name[7];

タイプを紹介したcharときにタイプを紹介しましたが、要するに、ASCIIチャートの文字を格納するために一般的に使用されます。

文字列は、通常の配列を初期化するのと同じように初期化できます。

char name[7] = { "F", "l", "a", "v", "i", "o" };

または、文字列リテラル(文字列定数とも呼ばれます)を使用すると、二重引用符で囲まれた文字のシーケンスがより便利になります。

char name[7] = "Flavio";

printf()次を使用して文字列を印刷できます%s

printf("%s", name);

「Flavio」の長さが6文字であることに気づきましたが、長さ7の配列を定義しましたか?なんで?これは、文字列の最後の文字が  0値、文字列ターミネータである必要があり、そのためのスペースを確保する必要があるためです。

これは、特に文字列を操作するときに覚えておくことが重要です。

文字列の操作について言えば、Cによって提供される重要な標準ライブラリが1つありますstring.h

このライブラリは、文字列の操作に関する低レベルの詳細の多くを抽象化し、一連の便利な関数を提供するため、不可欠です。

上に追加することで、プログラムにライブラリをロードできます。

#include <string.h>

これを行うと、次の機能にアクセスできます。

  • strcpy()文字列を別の文字列にコピーするには
  • strcat()文字列を別の文字列に追加するには
  • strcmp()2つの文字列が等しいかどうかを比較します
  • strncmp()n2つの文字列の最初の文字を比較します
  • strlen()文字列の長さを計算するには

そしてもっとたくさん。

ポインタ

私の意見では、ポインターはCの最も紛らわしい/挑戦的な部分の1つです。特にプログラミングに不慣れな場合だけでなく、PythonやJavaScriptなどの高級プログラミング言語を使用している場合も同様です。

このセクションでは、可能な限りシンプルでありながら、控えめな方法でそれらを紹介したいと思います。

ポインタは、変数を含むメモリブロックのアドレスです。

このように整数を宣言すると、次のようになります。

int age = 37;

演算子を使用して&、変数のメモリ内のアドレスの値を取得できます。

printf("%p", &age); /* 0x7ffeef7dcb9c */

%pで指定された形式を使用してprintf()、アドレス値を出力しました。

アドレスを変数に割り当てることができます。

int *address = &age;

宣言で使用int *addressすると、整数変数を宣言するのではなく、整数へのポインターを宣言します。

ポインタ演算子を使用して*、アドレスが指している変数の値を取得できます。

int age = 37;
int *address = &age;
printf("%u", *address); /* 37 */

今回もポインタ演算子を使用していますが、今回は宣言ではないため、「このポインタが指す変数の値」を意味します。

この例では、age変数を宣言し、ポインターを使用して値を初期化します。

int age;
int *address = &age;
*address = 37;
printf("%u", *address);

Cを使用する場合、この単純な概念の上に多くのものが構築されていることがわかります。したがって、上記の例を自分で実行して、少し理解してください。

ポインタは、メモリアドレスとデータの編成方法について考える必要があるため、絶好の機会です。

配列はその一例です。配列を宣言する場合:

int prices[3] = { 5, 4, 3 };

prices変数は、実際には配列の最初の項目へのポインターです。printf()この場合、この関数を使用して最初のアイテムの値を取得できます。

printf("%u", *prices); /* 5 */

pricesすばらしいのは、ポインターに1を追加することで、2番目の項目を取得できることです。

printf("%u", *(prices + 1)); /* 4 */

他のすべての値についても同様です。

文字列は内部の配列であるため、多くの優れた文字列操作操作を実行することもできます。

また、オブジェクトや関数の参照を渡して、それをコピーするためにより多くのリソースを消費しないようにするなど、さらに多くのアプリケーションがあります。

機能

関数は、コードを次のようなサブルーチンに構造化する方法です。

  1. に名前を付ける
  2. 必要なときに電話する

最初のプログラム「Hello、World!」から始めて、すぐにC関数を使用します。

#include <stdio.h>

int main(void) {
    printf("Hello, World!");
}

このmain()関数は、Cプログラムのエントリポイントであるため、非常に重要な関数です。

別の関数は次のとおりです。

void doSomething(int value) {
    printf("%u", value);
}

関数には4つの重要な側面があります。

  1. それらには名前があるので、後で呼び出す(「呼び出す」)ことができます
  2. 戻り値を指定します
  3. 彼らは議論を持つことができます
  4. 彼らは中かっこで包まれた体を持っています

関数本体は、関数を呼び出すたびに実行される一連の命令です。

関数に戻り値がない場合はvoid、関数名の前にキーワードを使用できます。それ以外の場合は、関数の戻り値の型(int整数、float浮動小数点値、const char *文字列など)を指定します。

関数から複数の値を返すことはできません。

関数は引数を持つことができます。それらはオプションです。それらがない場合はvoid、次のように括弧内に挿入します。

void doSomething(void) {
   /* ... */
}

この場合、関数を呼び出すときに、括弧内に何も入れずに関数を呼び出します。

doSomething();

パラメータが1つある場合は、次のようにパラメータのタイプと名前を指定します。

void doSomething(int value) {
   /* ... */
}

関数を呼び出すときは、次のようにかっこでそのパラメーターを渡します。

doSomething(3);

複数のパラメーターを持つことができます。その場合、宣言と呼び出しの両方で、コンマを使用してパラメーターを区切ります。

void doSomething(int value1, int value2) {
   /* ... */
}

doSomething(3, 4);

パラメータはcopyによって渡されます。これは、を変更するvalue1と、その値がローカルで変更されることを意味します。呼び出しで渡された関数の外部の値は変更されません。

ポインタをパラメータとして渡すと、メモリアドレスを使用して直接アクセスできるようになったため、その変数値を変更できます。

パラメータのデフォルト値を定義することはできません。C ++はそれを行うことができます(そしてArduino言語プログラムはそれを行うことができます)が、Cはできません。

関数を呼び出す前に必ず関数を定義してください。定義しないと、コンパイラーが警告とエラーを発生させます。

➜  ~ gcc hello.c -o hello; ./hello
hello.c:13:3: warning: implicit declaration of
      function 'doSomething' is invalid in C99
      [-Wimplicit-function-declaration]
  doSomething(3, 4);
  ^
hello.c:17:6: error: conflicting types for
      'doSomething'
void doSomething(int value1, char value2) {
     ^
hello.c:13:3: note: previous implicit declaration
      is here
  doSomething(3, 4);
  ^
1 warning and 1 error generated.

あなたが得る警告は、私がすでに述べた注文に関するものです。

エラーは、関連する別のことに関するものです。Cは、呼び出しの前に関数宣言を「認識」しないため、仮定を行う必要があります。そして、それは関数を返すことを前提としていますint。ただし、関数はを返すvoidため、エラーが発生します。

関数定義を次のように変更した場合:

int doSomething(int value1, int value2) {
  printf("%d %d\n", value1, value2);
  return 1;
}

エラーではなく、警告が表示されるだけです。

➜  ~ gcc hello.c -o hello; ./hello
hello.c:14:3: warning: implicit declaration of
      function 'doSomething' is invalid in C99
      [-Wimplicit-function-declaration]
  doSomething(3, 4);
  ^
1 warning generated.

いずれの場合も、使用する前に必ず関数を宣言してください。関数を上に移動するか、関数プロトタイプをヘッダーファイルに追加します。

関数内で、変数を宣言できます。

void doSomething(int value) {
  int doubleValue = value * 2;
}

変数は、関数の呼び出し時に作成され、関数が終了すると破棄されます。外からは見えません。

関数内では、関数自体を呼び出すことができます。これは再帰と呼ばれ、独特の機会を提供するものです。

入出力

Cは小さな言語であり、Cの「コア」には入出力(I / O)機能は含まれていません。

もちろん、これはCに固有のものではありません。言語コアがI/Oにとらわれないのは一般的です。

stdio.hCの場合、入力/出力は、ヘッダーファイルで定義された一連の関数を介してC標準ライブラリによって提供されます。

このライブラリは、次を使用してインポートできます。

#include <stdio.h>

Cファイルの上に。

このライブラリは、他の多くの機能の中でも特に次の機能を提供します。

  • printf()
  • scanf()
  • sscanf()
  • fgets()
  • fprintf()

これらの関数の機能を説明する前に、 I/Oストリームについて少し説明したいと思います。

Cには3種類のI/Oストリームがあります。

  • stdin(標準入力)
  • stdout(標準出力)
  • stderr(標準誤差)

I / O関数では、常にストリームを処理します。ストリームは、デバイスまたはファイルを表すことができる高レベルのインターフェイスです。Cの観点からは、ファイルからの読み取りとコマンドラインからの読み取りに違いはありません。いずれの場合もI/Oストリームです。

それは覚えておくべき1つのことです。

printf()一部の関数は、文字をに出力するために使用するのような特定のストリームで動作するように設計されていstdoutます。より一般的な対応物を使用してfprintf()、書き込むストリームを指定できます。

話し始めたのでprintf()、今から紹介しましょう。

printf()は、Cプログラミングを学習するときに使用する最初の関数の1つです。

最も単純な使用法では、文字列リテラルを渡します。

printf("hey!");

プログラムは文字列の内容を画面に出力します。

変数の値を出力できます。ただし、変数のタイプに応じて変化する特殊文字であるプレースホルダーを追加する必要があるため、少し注意が必要です。たとえば%d、符号付き10進整数に使用します。

int age = 37;

printf("My age is %d", age);

カンマを使用して、複数の変数を出力できます。

int age_yesterday = 37;
int age_today = 36;

printf("Yesterday my age was %d and today is %d", age_yesterday, age_today);

次のような他のフォーマット指定子があります%d

  • %cチャーのために
  • %sチャーのために
  • %f浮動小数点数の場合
  • %pポインタ用

などなど。

でエスケープ文字を使用できprintf()ます\n。これを使用して、出力に改行を作成させることができます。

scanf()

printf()出力関数として使用されます。ここで入力関数を紹介したいので、すべてのI/O処理を実行できると言えますscanf()

この関数は、コマンドラインからプログラムを実行しているユーザーから値を取得するために使用されます。

最初に、入力から取得した値を保持する変数を定義する必要があります。

int age;

次に、2つの引数を使用して呼び出しscanf()ます。変数の形式(タイプ)と変数のアドレスです。

scanf("%d", &age);

&文字列を入力として取得する場合は、文字列名が最初の文字へのポインタであるため、その前の文字は必要ないことに注意してください。

char name[20];
scanf("%s", name);

printf()との両方を使用する小さなプログラムを次に示しますscanf()

#include <stdio.h>

int main(void) {
  char name[20];
  printf("Enter your name: ");
  scanf("%s", name);
  printf("you entered %s", name);
}

可変スコープ

Cプログラムで変数を定義する場合、宣言する場所に応じて、スコープが異なります。

これは、一部の場所では利用できるが、他の場所では利用できないことを意味します。

位置によって、2種類の変数が決まります。

  • グローバル変数
  • ローカル変数

これが違いです。関数内で宣言された変数は、次のようなローカル変数です。

int main(void) {
  int age = 37;
}

ローカル変数には関数内からのみアクセスでき、関数が終了するとその存在を停止します。それらはメモリからクリアされます(いくつかの例外を除く)。

関数の外部で定義された変数は、次の例のようにグローバル変数です。

int age = 37;

int main(void) {
  /* ... */
}

グローバル変数は、プログラムのどの関数からでもアクセスでき、プログラムが終了するまで、プログラムの実行全体で使用できます。

関数が終了すると、ローカル変数は使用できなくなると述べました。

その理由は、ローカル変数は、ポインタを使用してヒープに明示的に割り当てない限り、デフォルトでスタックで宣言されるためです。しかし、その後、自分でメモリを管理する必要があります。

静的変数

関数内では、キーワードを使用して静的変数を初期化できます。static

グローバル変数はデフォルトで静的であるため、「関数内」と言いました。したがって、キーワードを追加する必要はありません。

静的変数とは何ですか?初期値が指定されていない場合、静的変数は0に初期化され、関数呼び出し間で値を保持します。

この関数について考えてみましょう。

int incrementAge() {
  int age = 0;
  age++;
  return age;
}

incrementAge()一度呼び出す1と、戻り値として取得されます。これを複数回呼び出すと、常に1が返されます。これは、がローカル変数であり、すべての関数呼び出しでage再初期化されるためです。0

関数を次のように変更すると、次のようになります。

int incrementAge() {
  static int age = 0;
  age++;
  return age;
}

これで、この関数を呼び出すたびに、増分値が取得されます。

printf("%d\n", incrementAge());
printf("%d\n", incrementAge());
printf("%d\n", incrementAge());

私たちに

1
2
3

ageで0への初期化を省略して、静的変数が作成時に自動的に0に設定されるためstatic int age = 0;、単に書き込むこともできます。static int age;

静的配列を持つこともできます。この場合、配列内の各単一アイテムは0に初期化されます。

int incrementAge() {
  static int ages[3];
  ages[0]++;
  return ages[0];
}

グローバル変数

このセクションでは、グローバル変数とローカル変数の違いについて詳しく説明します。

ローカル変数は関数内で定義され、その関数内でのみ使用できます。

このような:

#include <stdio.h>

int main(void) {
  char j = 0;
  j += 10;
  printf("%u", j); //10
}

j関数以外の場所では使用できませんmain

グローバル変数は、次のように関数の外部で定義されます。

#include <stdio.h>

char i = 0;

int main(void) {
  i += 10;
  printf("%u", i); //10
}

グローバル変数には、プログラム内の任意の関数からアクセスできます。アクセスは値の読み取りに限定されません。変数は任意の関数で更新できます。

このため、グローバル変数は、関数間で同じデータを共有するための1つの方法です。

ローカル変数との主な違いは、関数が終了すると、変数に割り当てられたメモリが解放されることです。

グローバル変数は、プログラムが終了したときにのみ解放されます。

タイプ定義

typedefCのキーワードを使用すると、新しいタイプを定義できます。

組み込みのC型から始めて、次の構文を使用して独自の型を作成できます。

typedef existingtype NEWTYPE

私たちが作成する新しいタイプは、通常、慣例により大文字です。

これは、より簡単に区別し、すぐにタイプとして認識できるようにするためです。

たとえば、 :である新しいNUMBERタイプを定義できます。int

typedef int NUMBER

NUMBERそうしたら、新しい変数を定義できます。

NUMBER one = 1;

今、あなたは尋ねるかもしれません:なぜですか?int代わりに組み込み型を使用しないのはなぜですか?

ええと、typedef列挙型と構造の2つと組み合わせると本当に便利になります。

列挙型

typedefandキーワードを使用しenumて、1つの値または別の値を持つことができるタイプを定義できます。

typedefこれは、キーワードの最も重要な使用法の1つです。

列挙型の構文は次のとおりです。

typedef enum {
  //...values
} TYPENAME;

私たちが作成する列挙型は、通常、慣例により大文字です。

簡単な例を次に示します。

typedef enum {
  true,
  false
} BOOLEAN;

Cにはboolタイプが付属しているため、この例は実際には実用的ではありませんが、理解できます。

別の例は、平日を定義することです。

typedef enum {
  monday,  
  tuesday,
  wednesday,
  thursday,
  friday,
  saturday,
  sunday
} WEEKDAY;

この列挙型を使用する単純なプログラムは次のとおりです。

#include <stdio.h>

typedef enum {
  monday,  
  tuesday,
  wednesday,
  thursday,
  friday,
  saturday,
  sunday
} WEEKDAY;

int main(void) {
  WEEKDAY day = monday;

  if (day == monday) {
    printf("It's monday!"); 
  } else {
    printf("It's not monday"); 
  }
}

列挙型定義のすべての項目は、内部的に整数とペアになっています。したがって、この例mondayでは0、1などtuesdayです。

これは、条件がif (day == 0)の代わりになっている可能性があることを意味しますがif (day == monday)、人間が数字ではなく名前で推論する方がはるかに簡単なので、非常に便利な構文です。

構造

キーワードを使用すると、struct基本的なC型を使用して複雑なデータ構造を作成できます。

構造体は、さまざまなタイプの値のコレクションです。Cの配列は型に制限されているため、多くのユースケースで構造体が非常に興味深いことがわかります。

構造体の構文は次のとおりです。

struct <structname> {
  //...variables
};

例:

struct person {
  int age;
  char *name;
};

次のように、閉じ中括弧の後、セミコロンの前に変数を追加することにより、その構造を型として持つ変数を宣言できます。

struct person {
  int age;
  char *name;
} flavio;

または、次のように複数のもの:

struct person {
  int age;
  char *name;
} flavio, people[20];

この場合、という名前の単一のperson変数と、という名前flavioの20の配列を宣言します。personpeople

次の構文を使用して、後で変数を宣言することもできます。

struct person {
  int age;
  char *name;
};

struct person flavio;

宣言時に構造を初​​期化できます。

struct person {
  int age;
  char *name;
};

struct person flavio = { 37, "Flavio" };

構造を定義したら、ドットを使用してその中の値にアクセスできます。

struct person {
  int age;
  char *name;
};

struct person flavio = { 37, "Flavio" };
printf("%s, age %u", flavio.name, flavio.age);

ドット構文を使用して値を変更することもできます。

struct person {
  int age;
  char *name;
};

struct person flavio = { 37, "Flavio" };

flavio.age = 38;

構造体は、関数パラメーターまたは戻り値として渡し、さまざまな変数をその中に埋め込むことができるため、非常に便利です。各変数にはラベルがあります。

もちろん、構造体へのポインタを渡さない限り、構造体はコピーによって渡されることに注意することが重要です。その場合、構造体は参照によって渡されます。

を使用typedefすると、構造を操作するときにコードを簡略化できます。

例を見てみましょう:

typedef struct {
  int age;
  char *name;
} PERSON;

を使用して作成する構造typedefは、通常、慣例により大文字です。

PERSONこれで、次のような新しい変数を宣言できます。

PERSON flavio;

そして、次のように宣言時にそれらを初期化できます。

PERSON flavio = { 37, "Flavio" };

コマンドラインパラメータ

Cプログラムでは、コマンドの起動時にコマンドラインからパラメーターを受け入れる必要がある場合があります。

単純なニーズの場合、そうするために必要なのは、main()関数のシグネチャをから変更することだけです。

int main(void)

int main (int argc, char *argv[])

argcコマンドラインで指定されたパラメーターの数を含む整数です。

argv文字列の配列です。

プログラムが起動すると、これら2つのパラメーターの引数が提供されます。

argv配列には常に少なくとも1つの項目があることに注意してください:プログラムの名前

次のように、プログラムの実行に使用するCコンパイラの例を見てみましょう。

gcc hello.c -o hello

これが私たちのプログラムだったとしたら、私たちはargc4でありargv

  • gcc
  • hello.c
  • -o
  • hello

受け取った引数を出力するプログラムを書いてみましょう。

#include <stdio.h>

int main (int argc, char *argv[]) {
  for (int i = 0; i < argc; i++) {
    printf("%s\n", argv[i]);
  }
}

プログラムの名前がで、次のhelloように実行すると、次のよう./helloになります。これを出力として取得します。

./hello

次のようなランダムなパラメータを渡す./hello a b cと、次の出力が端末に渡されます。

./hello
a
b
c

このシステムは、単純なニーズに最適です。より複雑なニーズには、getoptのような一般的に使用されるパッケージがあります。

ヘッダーファイル

簡単なプログラムを1つのファイルに入れることができます。しかし、プログラムが大きくなると、すべてを1つのファイルにまとめることは不可能になります。

プログラムの一部を別のファイルに移動できます。次に、ヘッダーファイルを作成します。

.hヘッダーファイルは、。の代わりにで終わることを除いて、通常のCファイルのように見えます.c。関数やプログラムの他の部分の実装の代わりに、宣言を保持します。

printf()関数または他のI/O関数を最初に使用したときにすでにヘッダーファイルを使用しており、次のように入力する必要がありました。

#include <stdio.h>

それを使用します。

#includeプリプロセッサディレクティブです。

プリプロセッサは、stdio.h角かっこを使用しているため、標準ライブラリでファイルを検索します。独自のヘッダーファイルを含めるには、次のように引用符を使用します。

#include "myfile.h"

上記はmyfile.h現在のフォルダで検索されます。

ライブラリのフォルダ構造を使用することもできます。

#include "myfolder/myfile.h"

例を見てみましょう。このプログラムは、特定の年からの年数を計算します。

#include <stdio.h>

int calculateAge(int year) {
  const int CURRENT_YEAR = 2020;
  return CURRENT_YEAR - year;
}

int main(void) {
  printf("%u", calculateAge(1983));
}

calculateAge関数を別のファイルに移動したいとします。

ファイルを作成しcalculate_age.cます:

int calculateAge(int year) {
  const int CURRENT_YEAR = 2020;
  return CURRENT_YEAR - year;
}

そして、関数プロトタイプcalculate_age.hを置いたファイル。これは、本体を除いて、ファイル内の関数と同じです。.c

int calculateAge(int year);

これでメイン.cファイルに移動してcalculateAge()関数定義を削除し、インポートcalculate_age.hしてcalculateAge()関数を使用できるようにします。

#include <stdio.h>
#include "calculate_age.h"

int main(void) {
  printf("%u", calculateAge(1983));
}

複数のファイルで構成されるプログラムをコンパイルするには、次のようにコマンドラインにすべてをリストする必要があることを忘れないでください。

gcc -o main main.c calculate_age.c

さらに複雑な設定では、プログラムのコンパイル方法をコンパイラーに指示するためにMakefileが必要です。

プリプロセッサ

プリプロセッサは、Cでプログラミングするときに非常に役立つツールです。これは、言語、コンパイラ、および標準ライブラリと同様に、C標準の一部です。

プログラムを解析し、プロセスを続行する前に、コンパイラが必要なものをすべて取得していることを確認します。

実際には、それは何をしますか?

たとえば、#includeディレクティブにインクルードするすべてのヘッダーファイルを検索します。

また、を使用して定義したすべての定数を調べ#define、実際の値に置き換えます。

それはほんの始まりに過ぎません。最も一般的な操作であるため、これら2つの操作について説明しました。プリプロセッサはさらに多くのことを実行できます。

あなたは最初に気づき#include#define持ってい#ましたか?これは、すべてのプリプロセッサディレクティブに共通です。行がで始まる場合、#それはプリプロセッサによって処理されます。

条件付き

私たちができることの1つは、条件を使用して、式の値に応じて、プログラムのコンパイル方法を変更することです。

たとえば、DEBUG定数が0であるかどうかを確認できます。

#include <stdio.h>

const int DEBUG = 0;

int main(void) {
#if DEBUG == 0
  printf("I am NOT debugging\n");
#else
  printf("I am debugging\n");
#endif
}

シンボリック定数

シンボリック定数を定義できます:

#define VALUE 1
#define PI 3.14
#define NAME "Flavio"

プログラムでNAME、PI、またはVALUEを使用する場合、プリプロセッサはプログラムを実行する前にその名前を値に置き換えます。

シンボリック定数は、コンパイル時に変数を作成せずに値に名前を付けることができるため、非常に便利です。

マクロ

を使用して、マクロ#defineを定義することもできます。マクロとシンボリック定数の違いは、マクロは引数を受け入れることができ、通常はコードを含むのに対し、シンボリック定数は値であるということです。

#define POWER(x) ((x) * (x))

引数を囲む括弧に注意してください。これは、コンパイル前のプロセスでマクロが置き換えられたときに問題が発生しないようにするための良い方法です。

次に、次のようにコードで使用できます。

printf("%u\n", POWER(4)); //16

関数との大きな違いは、マクロが引数や戻り値のタイプを指定しないことです。これは、場合によっては便利な場合があります。

ただし、マクロは1行の定義に制限されています。

定義されている場合

シンボリック定数またはマクロが次を使用して定義されているかどうかを確認できます#ifdef

#include <stdio.h>
#define VALUE 1

int main(void) {
#ifdef VALUE
  printf("Value is defined\n");
#else
  printf("Value is not defined\n");
#endif
}

また#ifndev、反対のことも確認する必要があります(マクロは定義されていません)。

とを使用して同じタスクを実行することもでき#if definedます#if !defined

コードの一部のブロックを次のようなブロックにラップするのが一般的です。

#if 0

#endif

一時的に実行を阻止する、またはDEBUGシンボリック定数を使用するには:

#define DEBUG 0

#if DEBUG
  //code only sent to the compiler
  //if DEBUG is not 0
#endif

使用できる事前定義されたシンボリック定数

プリプロセッサは、名前の前後の2つのアンダースコアで識別される、使用できるいくつかの記号定数も定義します。これには、次のものが含まれます。

  • __LINE__ソースコードファイルの現在の行に変換されます
  • __FILE__ファイルの名前に変換されます
  • __DATE__コンパイル日を次のMmm gg aaaa形式で変換します
  • __TIME__hh:mm:ss次の形式でコンパイル時間に変換されます

結論

このハンドブックを読んでくれてありがとう!

Cについてもっと知るきっかけになることを願っています。 

このストーリーは、もともとhttps://www.freecodecamp.org/news/the-c-beginners-handbook/で公開されました

#cprogramming 

Cビギナーズハンドブック:わずか数時間でCプログラミング言語の基本を学ぶ

¿Qué Es El Lenguaje De Programación C? Un Tutorial Para Principiantes

Este tutorial le dará una amplia visión general de los conceptos básicos del lenguaje de programación C.

Repasaremos la historia del lenguaje, por qué y dónde se usa, el proceso de compilación y algunos conceptos de programación muy básicos que son comunes en los lenguajes de programación más populares.

Esta no es una guía completa del lenguaje, sino que le brindará una comprensión de alto nivel de conceptos e ideas importantes de C como un principiante absoluto en la codificación.

Cada lenguaje tiene su propia sintaxis y formas específicas de hacer las cosas, pero los conceptos que se tratan aquí son comunes y se aplican a todos los lenguajes de programación.

Tener una comprensión de cómo funcionan las cosas y estos conceptos universales puede llevarlo muy lejos en su viaje de codificación. Facilita el aprendizaje de una nueva tecnología a largo plazo.

Este tutorial se inspira en gran medida en el material cubierto en las primeras semanas del curso CS50: Introducción a la informática, que recomiendo encarecidamente a cualquiera que desee profundizar en la informática y la programación, sin importar su nivel de experiencia.

La historia del lenguaje de programación C

La historia del lenguaje de programación C está íntimamente ligada a la historia del desarrollo del Sistema Operativo Unix.

Si miramos hacia atrás para comprender qué condujo al desarrollo del sistema operativo que cambió el mundo de la informática, veremos los pasos que condujeron al desarrollo de C.

En pocas palabras, C se derivó de la necesidad de encontrar inicialmente y eventualmente crear un lenguaje para aplicar en el sistema operativo Unix.

Proyecto MAC y MULTICS

Todo comenzó en 1965 cuando se completó el proyecto experimental MAC en el MIT, el primer sistema de este tipo. Este fue el comienzo de la era MULTICS. Usó algo llamado CTSS, o el Sistema de Tiempo Compartido Compatible.

Esta fue una innovación clave en ese momento. Hasta este punto, estábamos en la era de los mainframes, donde las computadoras masivas, poderosas y extremadamente costosas solían ocupar habitaciones enteras.

Para realizar las tareas, los programadores escribirían el código a mano. Luego perforaban una baraja de tarjetas de cinta de papel que estaban codificadas con el programa escrito a mano.

Hicieron esto entregando las hojas de papel en las que estaba escrito el programa a los operadores que usaban una máquina perforadora de llaves que perforaba los agujeros de la tarjeta y representaba los datos y las instrucciones en la tarjeta.

Luego pasarían las tarjetas perforadas a un lector de tarjetas perforadas conectado a la computadora central. Luego convirtió las secuencias en los hoyos de las cartas en información digital. Las tareas simples tomaban mucho tiempo usando este método y solo una persona podía usar cada máquina a la vez.

La idea de compartir el tiempo lo cambió todo. En lugar de usar tarjetas, conectó múltiples consolas (que en ese momento eran terminales mecánicas llamadas teletipos) a una computadora principal. Esto permitió que muchas personas usaran la misma computadora simultáneamente.

Más de 100 terminales de máquinas de escribir repartidas por el campus del MIT podrían conectarse a una gran computadora principal. Este sistema admitía hasta 30 usuarios remotos al mismo tiempo, cada uno usando una de esas terminales.

El sistema operativo de la computadora principal realizaba múltiples tareas y daba vueltas a las personas que querían realizar tareas informáticas desde sus terminales conectados y les daba unos segundos a cada uno.

Proporcionó lo que parecía un servicio continuo, aparentemente cargando y ejecutando muchos programas simultáneamente. Pero en realidad pasó por el programa de cada usuario muy rápidamente. Esto dio la ilusión de que una persona tenía toda la computadora para ellos solos.

Este sistema demostró ser extremadamente eficiente, efectivo y productivo, ahorrando tiempo y a la larga dinero, ya que esas computadoras eran extremadamente costosas.

Algo que podría haber tomado días para completar ahora tomó mucho menos tiempo. Y esto comenzó a permitir un mayor acceso a la informática.

Tras el éxito del CTSS, el MIT decidió que era hora de desarrollar este sistema y dar el siguiente paso. El siguiente paso sería crear un sistema de tiempo compartido más avanzado.

Pero imaginaron un esfuerzo más ambicioso que eso: querían construir un sistema que sirviera como una utilidad informática para los programadores que fuera capaz de admitir que cientos de usuarios accedieran al mainframe al mismo tiempo. Y compartiría datos y recursos entre ellos.

Esto requeriría más recursos, por lo que unieron fuerzas con General Electric y Bell Labs.

Este nuevo proyecto se denominó MULTICS, que significa "Servicio de computación e información multiplexada" y se implementó en uno de los mainframes de General Electric, el GE 635.

Este equipo trabajó en MULTICS durante varios años. Pero en 1969 Bell Labs abandonó el proyecto porque tardaba demasiado y era demasiado caro.

Bell Labs: el centro de innovación

La retirada de Bell Labs del proyecto MULTICS dejó a algunos empleados frustrados y buscando alternativas.

Mientras trabajaba en MULTICS, el equipo creó un entorno informático sin precedentes. Estaban acostumbrados a trabajar con sistemas de tiempo compartido y habían visto su eficacia. Estos programadores tenían un vasto conocimiento de los sistemas operativos y las innovaciones de ese proyecto hicieron que quisieran expandirse más.

Un grupo dirigido principalmente por Ken Thompson y Dennis Ritchie quería utilizar la informática comunitaria y crear un sistema de archivos que pudieran compartir. Tendría las características innovadoras que les gustaban de MULTICS pero lo implementarían de una manera simple, más pequeña y menos costosa.

Compartieron sus ideas y comenzaron a iterar.

Captura de pantalla-2021-02-07-a-7.03.16-PM-1

Ken Thompson y Dennis Ritchie, Fuente de la imagen de Wikipedia

Bell Labs fomentó un entorno abierto y de apoyo que permitió que florecieran la expresión creativa y las ideas innovadoras. Fue una investigación intensa y alentaron la resolución de problemas de pensamiento independiente para ayudarlos a mejorar sus soluciones iniciales.

A través de mucha discusión y experimentación lograron los mayores avances y escribieron la historia.

Mientras aún trabajaba en MULTICS, Ken Thompson había creado un juego llamado Space Travel. Inicialmente lo escribió en MULTICS, en el GE 635, pero cuando Bell Labs se retiró, adaptó el gamae a un programa Fortran para que se ejecutara en el sistema operativo GECOS que se ejecutaba en el GE 635.

Había muchos problemas con el juego: no funcionaba tan bien en GECOS como en MULTICS y necesitaba una máquina diferente y menos costosa para ejecutarlo.

Ken Thompson enfrentó el rechazo cuando solicitó fondos para crear un sistema operativo diferente, ya que los laboratorios Bell ya se habían retirado de ese proyecto. Pero terminó encontrando una minicomputadora DEC PDP-7 vieja y poco utilizada que pudo probar: era el único sistema disponible.

Captura de pantalla-2021-02-07-a-las-7.00.24-PM

Un DEC PDP-7, Fuente de la imagen de Wikipedia

Comenzó a escribir su juego en ese sistema simple, pero estaba limitado por el software de la computadora. Entonces, mientras trabajaba en él, terminó implementando el sistema de archivos básico que su equipo había estado imaginando.

Comenzó con un sistema de archivos jerárquico, un intérprete de línea de comandos y otros programas de utilidad. En un mes había creado un sistema operativo con ensamblador, editor y caparazón. Eran características más pequeñas y simples de MULTICS. Este sistema operativo fue la primera versión de Unix.

Los primeros días de Unix con lenguaje ensamblador

Al comienzo del proyecto, Ken Thompson no podía programar en la computadora DEC PDP-7. Los programas DEC PDP-7 tenían que compilarse y traducirse en el mainframe GE 635 más potente y luego la salida se transfirió físicamente al PDP-7 mediante cinta de papel.

El DEC PDP-7 tenía muy poca memoria, solo 8 KB. Para hacer frente a esta restricción, el sistema de archivos, la primera versión del kernel de Unix y prácticamente todo lo demás en el proyecto se codificaron en ensamblador. El uso de Assembly permitió a Thompson manipular y controlar directamente cada parte de la memoria en esa computadora.

El lenguaje ensamblador es un lenguaje de programación de bajo nivel que usa código simbólico y está cerca del lenguaje nativo de la máquina, el binario. Las instrucciones en el código y cada declaración en el lenguaje se corresponden estrechamente con las instrucciones de la máquina específicas de la arquitectura de la computadora.

Depende de la máquina y es específico de la máquina, lo que significa que un conjunto de instrucciones tiene resultados muy diferentes de una máquina a otra. Los programas escritos en lenguaje ensamblador están escritos para un tipo específico de procesador, por lo que un programa escrito en ensamblador no funcionará en una variedad de procesadores.

Era común escribir sistemas operativos usando lenguaje ensamblador en ese entonces. Y cuando empezaron a trabajar en Unix, no tenían en mente la portabilidad.

No les importaba si el sistema operativo funcionaba en diferentes arquitecturas y sistemas de máquinas. Ese fue un pensamiento que vino después. Su principal prioridad era la eficiencia del software.

Mientras trabajaban en MULTICS, utilizaron lenguajes de programación de alto nivel, como PL/I al principio y luego BCPL. Los programadores se habían acostumbrado a usar lenguajes de alto nivel para escribir software, utilidades y herramientas de sistemas operativos debido a las ventajas que ofrecían (eran relativamente fáciles de usar y comprender).

Cuando se utiliza un lenguaje de programación de nivel superior, existe una abstracción entre la arquitectura de la computadora y varios detalles oscuros. Esto significa que está por encima del nivel de la máquina y no hay manipulación directa de la memoria del hardware.

Los lenguajes de alto nivel son más fáciles de leer, aprender, comprender y mantener, lo que los convierte en una opción más fácil cuando se trabaja en equipo. Los comandos tienen una sintaxis similar al inglés, y los términos y las instrucciones parecen más familiares y amigables para los humanos en comparación con el formato simbólico de Asamblea.

Usar lenguajes de alto nivel también significa escribir menos código para lograr algo, mientras que los programas ensambladores eran extremadamente largos.

Thompson quería usar un lenguaje de nivel superior para Unix desde el principio, pero estaba limitado por el DEC PDP-7.

A medida que el proyecto avanzaba y más personas comenzaban a trabajar en él, el uso de Assembly no era lo ideal. Thompson decidió que Unix necesitaba un lenguaje de programación de sistemas de alto nivel.

En 1970 consiguieron financiación para el DEC PDP-11, más grande y potente, que tenía bastante más memoria.

Con un lenguaje de programación de alto nivel rápido, estructurado y más eficiente que podría reemplazar a Assembly, todos podrían entender el código y los compiladores podrían estar disponibles para diferentes máquinas.

Comenzaron a explorar diferentes lenguajes para escribir software de sistema que pudieran usar para implementar Unix.

De B ​​a C: la necesidad de un nuevo lenguaje

El objetivo era crear utilidades, programas que agregan funcionalidad, para ejecutarse en Unix. Thompson inicialmente intentó crear un compilador FORTRAN pero luego recurrió a un lenguaje que usaba antes, BCPL (Lenguaje de programación combinado básico).

BCPL fue diseñado y desarrollado a fines de la década de 1960 por Martin Richards. Su objetivo principal era escribir compiladores y software de sistema.

Este lenguaje era lento y tenía muchas restricciones, por lo que cuando Thompson comenzó a usarlo en 1970 para el proyecto Unix en el DEC PDP-7, hizo ajustes y modificaciones y terminó escribiendo su propio lenguaje, llamado B.

B tenía muchas de las características de BCPL pero era un lenguaje más pequeño, con una sintaxis menos detallada y un estilo más simple. Sin embargo, todavía era lento y no lo suficientemente potente como para admitir las utilidades de Unix, y no podía aprovechar las potentes funciones del PDP-11.

Dennis Ritchie decidió mejorar estos dos lenguajes anteriores, BCPL y B. Tomó funciones y características de cada uno y agregó conceptos adicionales. Creó un lenguaje más poderoso, C, tan poderoso y eficiente como Assembly. Este nuevo lenguaje superó las limitaciones de sus predecesores y pudo usar el poder de la máquina de manera efectiva.

Entonces, en 1972 nació C, y el primer compilador de C se escribió e implementó por primera vez en la máquina DEC PDP-11.

Captura de pantalla-2021-02-09-a-12.51.23-PM

La famosa imagen de Thompson y Ritchie trabajando en un PDP-11, Fuente de la imagen Wikipedia

El lenguaje de programación C

En 1973, Dennis Ritchie reescribió el código fuente de Unix y la mayoría de los programas y aplicaciones de Unix utilizando el lenguaje de programación C. Esto lo convirtió en el lenguaje de implementación estándar del sistema operativo.

Reimplementó el kernel de Unix en C, y casi todo el sistema operativo (más del 90%) está escrito en este lenguaje de alto nivel. Combina características de legibilidad de alto nivel y funcionalidad de bajo nivel, lo que lo convierte en la elección perfecta para escribir un sistema operativo.

Hacia fines de la década de 1970, la popularidad de C comenzó a aumentar y el lenguaje comenzó a obtener un apoyo y un uso más generalizados. Hasta ese momento, C solo estaba disponible para sistemas Unix y los compiladores no estaban disponibles fuera de los laboratorios Bell.

Este aumento de popularidad provino no solo del poder que C le dio a la máquina sino también al programador. También ayudó que el sistema operativo Unix estuviera ganando la misma popularidad a un ritmo aún más rápido.

Unix se destacó de lo que vino antes por su portabilidad y su capacidad para ejecutarse en una variedad de máquinas, sistemas y entornos diferentes.

C hizo posible esa portabilidad y, dado que era el lenguaje del sistema Unix, ganó más notoriedad, por lo que cada vez más programadores querían probarlo.

En 1978, Brian Kernighan y Dennis Ritchie coescribieron y publicaron la primera edición del libro 'el lenguaje de programación C', también conocido en la comunidad de programación como 'K&R'. Durante muchos años, este texto fue la referencia para la descripción, definición y referencia del lenguaje C.

Captura de pantalla-2021-02-09-a-4.20.50-PM

Portada del libro, fuente de la imagen Wikipedia

En la década de 1980, la popularidad de C se disparó a medida que se creaban y comercializaban diferentes compiladores. Muchos grupos y organizaciones que no estaban involucrados en el diseño de C comenzaron a fabricar compiladores para cada sistema operativo y estructura de arquitectura informática. C ahora estaba disponible en todas las plataformas.

A medida que estas organizaciones creaban sus propios compiladores, comenzaron a cambiar las características del lenguaje para adaptarse a cada plataforma para la que se estaba escribiendo el compilador.

Había varias versiones de C que tenían ligeras diferencias entre ellas. Mientras escribían los compiladores, estos grupos propusieron sus propias interpretaciones de algunos aspectos del lenguaje, que se basaron en la primera edición del libro 'Lenguaje de programación C'.

Sin embargo, con todas las iteraciones y ajustes, este libro ya no describía el idioma tal como era, y los cambios en el idioma comenzaron a causar problemas.

El mundo necesitaba una versión común de C, un estándar para el lenguaje.

El estándar C

Para asegurarse de que hubiera una definición estándar e independiente de la máquina del lenguaje, ANSI (el Instituto Nacional Estadounidense de Estándares) formó un comité en 1983. Este comité se denominó comité X3J11 y su misión era proporcionar una definición y estandarización claras y completas. De c.

Después de algunos años, en 1989, el trabajo del comité se hizo y se hizo oficial. Definieron un estándar comercial para el lenguaje. Esa versión del lenguaje se conoce como 'ANSI C' o C89.

C se utilizó en todo el mundo, por lo que un año después, en 1990, la norma fue aprobada y adoptada por ISO, la Organización Internacional de Normalización. La primera versión, C90, se llamó ISO/IEC 9899:1990.

Desde entonces, se han realizado muchas revisiones al lenguaje.

La segunda versión del estándar, C99, se publicó en 1999 y se llamó ISO/IEC 9899:1999 e introdujo características adicionales de lenguaje nuevo. La tercera versión, C11, se publicó en 2011. La versión más reciente es la cuarta, C17, y se llama ISO/IEC 9899:2018.

La continuación de C

C forjó un camino para la creación de muchos lenguajes de programación diferentes. Muchos de los lenguajes de programación modernos de alto nivel que usamos y amamos hoy en día se basan en C.

Muchos de los lenguajes creados después de C querían resolver problemas que C no podía, o superar algunos de los problemas que limitan a C. Por ejemplo, el hijo más popular de C es su extensión orientada a objetos C++, pero Go, Java y JavaScript también se inspiraron en C.

Características del lenguaje C y por qué debería considerar aprender C

C es un lenguaje antiguo, pero sigue siendo popular hasta el día de hoy, incluso después de todos estos años.

Debe su popularidad al auge y éxito de Unix, pero hoy en día ha ido mucho más allá de ser simplemente el lenguaje 'nativo' de Unix. Ahora alimenta la mayoría, si no todos, los servidores y sistemas del mundo.

Los lenguajes de programación son herramientas que utilizamos para resolver problemas informáticos específicos que nos afectan a gran escala.

No necesita saber C para crear páginas web y aplicaciones web. Pero resulta útil cuando desea escribir un sistema operativo, un programa que controla otros programas o una utilidad de programación para el desarrollo del núcleo, o cuando desea programar dispositivos integrados o cualquier aplicación de sistemas. C sobresale en todas estas tareas. Así que veamos algunas razones para aprender C.

Te ayuda a entender cómo funciona tu computadora

A pesar de que C es un lenguaje de programación de propósito general, se utiliza principalmente para interactuar con funciones de máquina de bajo nivel. Además de las razones prácticas detrás de aprender el lenguaje, conocer C puede ayudarlo a comprender cómo funciona realmente la computadora, qué sucede debajo del capó y cómo los programas realmente se ejecutan y ejecutan en las máquinas.

Dado que C se considera la base de otros lenguajes de programación, si puede aprender los conceptos utilizados en este lenguaje, será más fácil comprender otros lenguajes más adelante.

Escribir código C nos permite comprender los procesos ocultos que ocurren en nuestras máquinas. Nos permite acercarnos al hardware subyacente de la computadora sin jugar con el lenguaje ensamblador. También nos permite manejar una multitud de tareas de bajo nivel mientras se mantiene legible como los lenguajes de alto nivel.

C es rápido y eficiente

Al mismo tiempo, no perdemos la funcionalidad, la eficiencia y el control de bajo nivel de cómo se ejecuta el código que proporciona Assembly.

Recuerde que cada procesador en el hardware de cada dispositivo tiene su propio código de ensamblaje que es único para ese procesador. No es en absoluto compatible con ningún otro procesador en ningún otro dispositivo.

El uso de C nos brinda un enfoque más rápido, más fácil y, en general, menos engorroso para interactuar con la computadora en su nivel más bajo. De hecho, tiene una mezcla de características de alto y bajo nivel. Y nos ayuda a hacer el trabajo sin la molestia y el alboroto del código ensamblador largo e incomprensible.

Por lo tanto, C es lo más cercano que puede llegar al hardware subyacente de la computadora y es un excelente reemplazo para Assembly (el antiguo estándar para escribir sistemas operativos) cuando trabaja e implementa el software del sistema.

C es potente y flexible

Esta proximidad al hardware significa que el código C se escribe de forma explícita y precisa. Le brinda una imagen clara y un modelo mental de cómo su código interactúa con la computadora.

C no oculta la complejidad con la que opera una máquina. Le brinda mucho poder y flexibilidad, como la capacidad de asignar, manipular y escribir manualmente directamente en la memoria.

El programador hace gran parte del trabajo pesado y el lenguaje le permite administrar y estructurar la memoria de manera eficiente para que la máquina ofrezca un alto rendimiento, optimización y velocidad. C permite que el programador haga lo que debe hacerse.

C es portátil, eficaz e independiente de la máquina

C también es altamente portátil e independiente de la máquina. Aunque está cerca de la máquina y tiene acceso a sus funciones de bajo nivel, tiene suficiente abstracción de estas partes para hacer posible la portabilidad del código.

Como las instrucciones de ensamblaje son específicas de la máquina, los programas no son portátiles. Un programa escrito en una máquina tendría que ser reescrito para ejecutarse en otra. Y eso es difícil de mantener para cada arquitectura de computadora.

C es universal y los programas escritos en él se pueden compilar y ejecutar en muchas plataformas, arquitecturas y una variedad de máquinas sin perder rendimiento. Esto hace que C sea una excelente opción para crear sistemas y programas donde el rendimiento realmente importa.

C inspiró la creación de muchos otros lenguajes de programación

Muchos lenguajes que se usan comúnmente en la actualidad, como Python, Ruby, PHP y Java, se inspiraron en C. Estos lenguajes modernos se basan en C para funcionar y ser eficientes. Además, sus bibliotecas, compiladores e intérpretes están construidos en C.

Estos lenguajes ocultan la mayoría de los detalles sobre cómo funcionan realmente los programas debajo del capó. Al usar estos lenguajes, no tiene que lidiar con la asignación de memoria y los bits y bytes, ya que hay más niveles de abstracción. Y no necesita este nivel de control granular con aplicaciones de nivel superior donde la interacción con la memoria es propensa a errores.

Pero cuando está implementando parte de un sistema operativo o dispositivo integrado, conocer esos detalles de nivel inferior y el manejo directo puede ayudarlo a escribir un código más limpio.

C es un lenguaje bastante compacto

Aunque C puede ser bastante críptico y difícil de aprender para los principiantes, en realidad es un lenguaje bastante pequeño y compacto con un conjunto mínimo de palabras clave, sintaxis y funciones integradas. Por lo tanto, puede esperar aprender y usar todas las características del lenguaje cuando explore cómo funciona.

Incluso si no está interesado en aprender a programar un sistema operativo o una aplicación de sistemas, conocer los conceptos básicos de C y cómo interactúa con la computadora le brindará una buena base de conceptos y principios de informática.

Además, comprender cómo funciona y se distribuye la memoria es un concepto fundamental de programación. Entonces, comprender cómo se comporta la computadora en un nivel más profundo y los procesos que están sucediendo realmente puede ayudarlo a aprender y trabajar con cualquier otro idioma.

¿Dónde se usa C?

Hay una gran cantidad de código C en los dispositivos, productos y herramientas que miles de millones de nosotros usamos en nuestra vida cotidiana. Este código alimenta todo, desde las supercomputadoras del mundo hasta los dispositivos más pequeños.

El código C hace que los sistemas integrados y los dispositivos inteligentes de todo tipo funcionen. Algunos ejemplos son electrodomésticos como refrigeradores, televisores, cafeteras, reproductores de DVD y cámaras digitales.

¿Tu rastreador de actividad física y tu reloj inteligente? Desarrollado por C. ¿El sistema de rastreo GPS en su automóvil e incluso los controladores de semáforos? Lo has adivinado: C. Y hay muchos ejemplos de sistemas integrados utilizados en las industrias industrial, médica, robótica y automotriz que se ejecutan en código C.

Otra área en la que C se usa ampliamente es en los sistemas operativos y en el desarrollo del kernel. Además de Unix, para el cual se creó el lenguaje, otros sistemas operativos importantes y populares están codificados hasta cierto punto en C.

El kernel de Microsoft Windows está escrito principalmente en C, al igual que el kernel de Linux. La mayoría de las supercomputadoras funcionan con Linux, al igual que la mayoría de los servidores de Internet. Esto significa que C alimenta una gran parte de Internet.

Linux también alimenta los dispositivos Android, por lo que el código C no solo hace que las supercomputadoras y las computadoras personales funcionen, sino también los teléfonos inteligentes. Incluso OSX está codificado hasta cierto punto en C, lo que hace que las computadoras Mac también se ejecuten en C.

C también es popular para desarrollar aplicaciones de escritorio y GUI (interfaces gráficas de usuario). La mayoría de las aplicaciones de Abode que utilizamos para la edición de videos y fotografías y el diseño gráfico (como Photoshop, Adobe Illustrator y Adobe Premiere) están codificadas con C o su sucesor, C++.

Los compiladores, intérpretes y ensambladores para una variedad de lenguajes están diseñados y construidos con C; de hecho, estos son algunos de los usos más comunes del lenguaje.

Muchos navegadores y sus extensiones están construidos con C, como Google Chromium y el sistema de archivos de Google. Los desarrolladores también usan C a menudo en el diseño de bases de datos (MySql y Oracle son dos de los sistemas de bases de datos más populares creados en C) y potencia gráficos avanzados en muchos juegos de computadora.

A partir de esta descripción general, podemos ver que C y su derivado C++ ejecutan una gran parte de Internet y del mundo en general. Muchos de los dispositivos y tecnologías que usamos en nuestra vida diaria están escritos o dependen de C.

Proceso de compilación de C: Escribir-Compilar-Ejecutar

¿Qué es un programa en C?

Un programa de computadora escrito en C es un conjunto ordenado y legible por humanos de instrucciones que una computadora ejecuta. Su objetivo es proporcionar una solución a un problema informático específico y decirle a la computadora que realice una determinada tarea con una secuencia de instrucciones que debe seguir.

Esencialmente, todos los programas son solo archivos de texto sin formato almacenados en el disco duro de su computadora que usan una sintaxis especial que está definida por el lenguaje de programación que está usando.

Cada idioma tiene sus propias reglas que dictan lo que puedes escribir y lo que se considera válido y lo que no.

Un programa tiene palabras clave, que son palabras específicas que están reservadas y forman parte del lenguaje. También tiene piezas de datos literales como cadenas y números. Y tiene palabras que siguen las reglas del lenguaje, que definimos e introducimos en el lenguaje que aún no existen (como variables o métodos).

¿Qué es un compilador?

Los programas están escritos por nosotros y para nosotros. Están destinados a ser entendidos por los humanos.

Cuando escribimos programas en forma legible por humanos, podemos entenderlos, pero es posible que la computadora no pueda hacerlo. Las computadoras no entienden directamente los lenguajes de programación, solo entienden binario. Por lo tanto, los programas deben traducirse a esta otra forma para que la computadora pueda comprender las instrucciones de nuestro programa.

Los programas en lenguajes de alto nivel pueden compilarse o interpretarse. Utilizan piezas especiales de software llamadas compiladores e intérpretes, respectivamente.

¿Cuál es la diferencia entre un compilador y un intérprete?

Tanto los compiladores como los intérpretes son programas, pero son mucho más complejos y actúan como traductores. Toman un programa que está escrito en una forma legible por humanos y lo convierten en algo que las computadoras pueden entender. Y hacen posible ejecutar y ejecutar programas en diferentes sistemas informáticos.

Los programas compilados se convierten primero en un formato legible por máquina, lo que significa que se traducen a código de máquina antes de ejecutarse. El código de máquina es un lenguaje numérico: instrucciones binarias compuestas de secuencias de 0 y 1.

Esta compilación produce un programa ejecutable, es decir, un archivo que contiene el código en lenguaje máquina que la CPU (Unidad Central de Procesamiento) podrá leer, comprender y ejecutar directamente.

Después de esto, el programa puede ejecutarse y la computadora hace lo que el programa le dice que haga. Los programas compilados tienen una correspondencia más fuerte con el hardware subyacente y pueden manipular más fácilmente la CPU y la memoria de la computadora.

Los programas interpretados, por otro lado, no son ejecutados directamente por la máquina ni necesitan ser traducidos a un programa de lenguaje de máquina. En su lugar, utilizan un intérprete que traduce y ejecuta automática y directamente cada declaración e instrucción en el código línea por línea durante el tiempo de ejecución.

C es un lenguaje de programación compilado. Esto significa que usa un compilador para analizar el código fuente escrito en C y luego lo convierte en un archivo binario que el hardware de la computadora puede ejecutar directamente. Esto será específico para cada máquina en particular.

Cómo usar el compilador GCC con ejemplos

Los sistemas Unix y similares a Unix ya tienen un compilador C integrado e instalado. Esto significa que Linux y MacOS tienen un popular compilador integrado, llamado GCC Compiler (o GNU Compiler Collection).

En el resto de esta sección veremos ejemplos usando este compilador y he basado estos ejemplos en un sistema Unix o similar a Unix. Entonces, si tiene un sistema Windows, asegúrese de habilitar el Subsistema de Windows para Linux .

Primero, asegúrese de tener instalado el compilador GCC. Puede verificar abriendo su terminal y escribiendo gcc --versionel indicador que generalmente se encuentra después del $carácter.

Si está utilizando MacOS y no ha instalado las herramientas de desarrollo de la línea de comandos, aparecerá un cuadro de diálogo que le pedirá que las instale, así que si ve eso, continúe y hágalo.

Una vez que los tenga instalados, abra una nueva sesión de terminal y vuelva a escribir el gcc --versioncomando. Si ya ha instalado las herramientas de línea de comandos, debería obtener el siguiente resultado:

Captura de pantalla-2021-02-17-a-3.02.52-PM

Sin embargo, el término compilar solo es una abstracción y simplificación, ya que en realidad hay muchos pasos que suceden detrás de escena. Estos son los detalles más finos de nivel inferior que suceden entre nosotros escribiendo, compilando y luego ejecutando nuestro programa C. La mayoría incluso sucede automáticamente, sin que nos demos cuenta.

Cómo escribir código fuente C

Para poder desarrollar programas en C, primero necesitamos tener algún tipo de editor de texto. Un editor de texto es un programa que podemos usar para escribir nuestro código (llamado nuestro código fuente) en un archivo de texto.

Para esto, puede usar un editor de texto de línea de comandos como nano o Vim si se siente cómodo con ellos.

También puede usar un IDE (Entorno de desarrollo integrado) o un editor de texto con características similares a IDE (un terminal integrado, la capacidad de escribir, depurar, ejecutar y ejecutar nuestros programas, todo en un solo lugar sin salir del editor, y mucho más) .

Un editor con estas capacidades es Visual Studio Code, que usa la extensión C/C++ . A lo largo del resto de este tutorial, usaremos VSCode.

De vuelta en su terminal, continúe y escriba los comandos a continuación para crear un archivo donde vivirá nuestro código C.

`cd` # Takes us to our home directory,if not there already
`mkdir cprogram` # Creates a directory named cprogram 
`cd cprogram` #navigates us into the cprogram directory we just created
`touch hello.c` #creates a file named hello
`code .` #opens VSCODE  in the current directory

Así que acabamos de crear un archivo de texto sin formato, hello.c. Este archivo tendrá un código escrito en lenguaje C, lo que significa que será un programa C. Esto se indica mediante la .cextensión del archivo, que es una convención.

Dentro de él podemos escribir cualquier programa en C que queramos, empezando por uno muy básico como un programa que muestra 'hola mundo' en la pantalla.

Hola Mundo

Para ver lo que hace nuestro código, tenemos que ejecutar el programa que acabamos de escribir. Sin embargo, antes de ejecutarlo, primero debemos compilarlo escribiendo algunos comandos en la terminal.

Podemos continuar usando la línea de comando en nuestra computadora o podemos usar la terminal integrada en VSCode (manteniendo presionadas las control ~teclas al mismo tiempo que se abre una nueva ventana de terminal).

Hasta ahora podemos ver en el panel izquierdo que solo hay un archivo en nuestro cprogramdirectorio hello.c, que contiene nuestro código C.

El término 'compilar nuestro código C' no ocurre en un solo paso. También implica algunas acciones más pequeñas que ocurren automáticamente para nosotros.

Como recordatorio, cuando nos referimos a la compilación, generalmente queremos decir que el compilador toma nuestro código fuente como entrada (el código que escribimos en C que tiene una sintaxis similar al inglés) y lo traduce para producir declaraciones de código de máquina como salida.

Este código de máquina corresponde directamente a las instrucciones de nuestro código fuente, pero está escrito de una manera que la CPU puede entender para que pueda llevar a cabo las instrucciones y ejecutarlas.

Cómo el código fuente C se transforma en código binario

Esta es la idea general, pero hay 4 pasos más pequeños involucrados que suceden en el medio. Cuando compilamos nuestro código, en realidad lo estamos preprocesando, compilando, ensamblando y vinculando .

Estos pasos comienzan a ocurrir cuando escribimos el comando gcc hello.cen la terminal que es el nombre del compilador y el archivo de código fuente, respectivamente.

Si quisiéramos, podríamos alternar y personalizar ese comando escribiendo uno más específico como gcc -o hello hello.c, donde:

  • -osignifica 'salir este archivo'
  • helloes el nombre que nosotros mismos especificamos para el archivo de programa ejecutable que queremos generar y que se creará, y
  • hello.ces el archivo que el gcccompilador tomará como entrada (que es el archivo donde vive nuestro código fuente y queremos compilar).

Preprocesamiento en C

Otro programa que forma parte del compilador lleva a cabo este primer paso: el preprocesador. El preprocesador hace muchas cosas; por ejemplo, actúa como una "herramienta de búsqueda y reemplazo" mientras escanea nuestro código fuente en busca de declaraciones especiales y busca líneas que comiencen con un #.

Las líneas que comienzan con #,like #include, se denominan directivas de preprocesador. Cualquier línea que comience con a #indica al preprocesador que debe hacer algo. En particular, dice que debe sustituir esa línea con otra cosa automáticamente. No vemos este proceso, pero está sucediendo detrás de escena.

Por ejemplo, cuando el preprocesador encuentra la línea #include <stdio.h>en nuestro hello worldprograma anterior, #includeliteralmente le dice al preprocesador que incluya, copiando y pegando, todo el código de ese archivo de encabezado (que es una biblioteca externa stdio.h) en el lugar de esa declaración en nuestro propio código fuente. Entonces reemplaza la #include <stdio.h>línea con el contenido real del stdio.harchivo.

Dentro de la <stdio.h>biblioteca hay prototipos de funciones y definiciones o sugerencias. De esta manera todas las funciones quedan definidas para que la computadora las reconozca durante el tiempo de compilación, y podamos usarlas en nuestro programa.

Por ejemplo, la función printf();se define como int printf(const char *format,…);inside <stdio.h>. Los mismos pasos ocurren para otros archivos de encabezado, es decir, archivos con una .hextensión.

Durante el paso de preprocesamiento, nuestros comentarios en nuestro código también se eliminan y las macros se expanden y reemplazan con sus valores. Una macro es un fragmento de código al que se le ha dado un nombre.

En esta etapa, si no hay errores en nuestro código, no debería haber salida en la terminal, lo cual es una buena señal.

No vemos ningún resultado, pero se ha creado un nuevo archivo con una .iextensión que sigue siendo código fuente C. Este archivo incluye la salida del preprocesamiento, por lo que se denomina código fuente preprocesado. En este caso se genera un nuevo archivo, hello.ipero no será visible en nuestro editor.

Si ejecutamos el comando gcc -E hello.c:

Captura de pantalla-2021-03-02-a-las-8.29.46-PM

Podremos ver todo el contenido de este archivo (que es mucho) y el final se parece a esto:

Captura de pantalla-2021-03-02-a-8.30.05-PM

Si hay algún error con la corrección de nuestro código o no estamos siguiendo la semántica del lenguaje, veremos algunos errores y la compilación terminará. Tendríamos que corregir los errores y empezar el proceso desde el principio.

Compilando en C

Después del paso de preprocesamiento que produce el código fuente C preprocesado, a continuación tenemos que compilar el código. Esto implica tomar el código que aún es código fuente y cambiarlo a otra forma intermedia. Usamos un compilador para este paso.

Para repasar, un compilador es un programa que toma como entrada el código fuente y lo traduce a algo más cercano al lenguaje nativo de las computadoras.

Cuando nos referimos a la compilación, podemos referirnos a todo el proceso de traducción del código fuente a código objeto (código de máquina) o simplemente a un paso específico en todo el proceso de compilación.

El paso que estamos discutiendo ahora es cuando la compilación convierte cada declaración del programa de código fuente C preprocesado a un lenguaje más amigable para la computadora. Este lenguaje está más cerca del binario que la computadora puede entender directamente.

Este lenguaje intermedio es el código ensamblador, un lenguaje de programación de bajo nivel que se usa para controlar la CPU y manipularla para realizar tareas específicas y obtener un acceso cercano a la memoria de la computadora. ¿Recuerdas el código ensamblador de la sección de historial?

Cada CPU, el cerebro de la computadora, tiene su propio conjunto de instrucciones. El código ensamblador usa declaraciones y comandos específicos que se correlacionan directamente con esas instrucciones y operaciones de bajo nivel que realiza y lleva a cabo una CPU.

Entonces, en este paso del proceso de compilación, hello.iel compilador traduce cada declaración en el código fuente C preprocesado en el archivo a la declaración equivalente en lenguaje ensamblador en un nivel inferior.

El resultado de esta acción crea un archivo que termina en .s( hello.sdetrás de escena) que contiene instrucciones en ensamblaje.

Al escribir el comando gcc -S hello.c, podemos ver el contenido y los comandos de ensamblaje algo incomprensibles del hello.sarchivo que creó el compilador (pero eso no fue visible para nosotros cuando escribimos gcc hello.csolos).

Si miramos de cerca, veremos un par de palabras clave familiares y declaraciones utilizadas en nuestro código fuente C como mainy printf:

Captura de pantalla-2021-03-12-a-11.15.27-AM

Montaje en C

Ensamblar significa tomar el hello.sarchivo que contiene instrucciones de código ensamblador como entrada y, con la ayuda de otro programa que se ejecuta automáticamente en el proceso de compilación, ensamblarlo en instrucciones de código de máquina. Esto significa que tendrá como salida 0 y 1 reales, o declaraciones en formato binario.

Este paso también ocurre detrás de escena y da como resultado el idioma final al que se traducen las instrucciones en nuestro código fuente. Y ahora la computadora finalmente puede entender esas instrucciones.

Cada uno de los comandos que escribimos en nuestro código fuente C se transformó en declaraciones de lenguaje ensamblador y finalmente en las instrucciones binarias equivalentes. Todo esto sucedió solo con el comando gcc. ¡Uf!

El código que escribimos ahora se llama código objeto, que la CPU de una computadora específica puede entender. El lenguaje es incomprensible para nosotros los humanos.

La gente solía codificar en lenguaje de máquina, pero era un proceso muy tedioso. Cualquier símbolo que no sea un símbolo de código de máquina (es decir, cualquier cosa que no sea 0 y 1) es difícil de entender. La codificación en dicho lenguaje directamente es extremadamente propensa a errores.

En esta etapa, se crea otro archivo con una .oextensión (para objeto), por lo que en nuestro caso será hello.o.

Podemos ver el contenido real del archivo de objeto que contiene las instrucciones a nivel de máquina con el comando gcc -c hello.c. Si hacemos esto, veremos el contenido no legible por humanos de hello.o:

Captura de pantalla-2021-03-14-a-10.22.15-PM

Vinculación en C

En las imágenes de arriba, es posible que haya notado un a.outarchivo en nuestro directorio.

Este es el paso predeterminado y el archivo que se crea cuando escribimos el comando del compilador y nuestro nombre de archivo, gcc hello.cen nuestro caso.

Si hubiéramos usado el comando gcc -o hello hello.cmencionado anteriormente, habríamos visto un helloprograma ejecutable con nombre personalizado en lugar de a.out.

Los a.outsoportes para salida de montaje . Si tecleamos lsen la terminal para listar los archivos de nuestro directorio, vemos que a.outincluso se ve diferente al resto:

Captura de pantalla-2021-03-19-a-10.37.05-PM

La vinculación es la etapa final del proceso de compilación en la que el archivo binario final hello.ose vincula con el resto del código objeto de nuestro proyecto.

Entonces, si hay otros archivos que contienen código fuente C (como archivos incluidos en nuestro programa que implementan bibliotecas C que ya están procesadas y compiladas, u otro archivo que hemos escrito con el nombre, por ejemplo, filename.cademás hello.cde ), aquí es cuando el archivo objeto filename.oserá combinado con hello.oy los otros códigos de objeto, vinculándolos a todos juntos.

Esto forma un gran archivo ejecutable con el código de máquina combinado, a.outo hello, que representa nuestro programa.

Como finalmente hemos terminado de compilar, el programa está en su forma final. Y ahora podemos ejecutar y ejecutar el archivo en nuestra máquina escribiendo ./a.out. Esto significa 'ejecutar el archivo a.out que está en el directorio actual', ya que ./representa la carpeta en la que estamos. Luego vemos la salida de nuestro programa en la terminal:

Captura de pantalla-2021-03-19-a-10.18.20-PM

Cada vez que hacemos cambios en nuestro archivo de código fuente, tenemos que repetir el proceso de compilación desde el principio para ver los cambios cuando volvamos a ejecutar el código.

Cómo escribir Hola Mundo en C

Un hello worldprograma es muy simple, pero es una tradición que también actúa como un mensaje de prueba cuando comienzas a aprender a codificar en un nuevo lenguaje de programación.

Si ejecuta su programa "Hello World" con éxito, esto le permite saber que su sistema está configurado correctamente.

Hola_Mundo_Brian_Kerninghan_1978-1

'Hola mundo' ideado por Brian Kernighan de Artsy's Algorythm Auction basado en un memorando interno de Bell Laboratories de 1974, "Programación en C: un tutorial", que contiene la primera versión conocida. Fue reimpreso en el popular libro de 1978, El lenguaje de programación C. Fuente de imagen y descripción de Wikipedia

Un programa 'hola mundo' contiene la sintaxis básica del lenguaje y podemos dividirla en partes más pequeñas:

#include<stdio.h>

int main(void)
{
    // print hello world to the screen
	printf("Hello world\n");
}

Archivos de encabezado en C

Los archivos de encabezado son bibliotecas externas. Esto significa que son un conjunto de código ya escrito por algunos desarrolladores para que lo usen otros desarrolladores.

Proporcionan características que no están incluidas en el núcleo del lenguaje C. Al agregar archivos de encabezado a nuestro código, a cambio obtenemos funcionalidad adicional que podemos usar en nuestros programas.

Archivos de encabezado como include <stdio.h>end en la extensión .h. En particular, un archivo de encabezado como stdio.hya viene integrado en el compilador.

La línea include <stdio.h>es una instrucción para las funciones escritas previamente en el stdio.harchivo de la biblioteca que le dice a la computadora que acceda a ellas e las incluya en nuestro programa.

stdio.hnos da la funcionalidad standard input and standard output, lo que significa que podremos obtener entradas y salidas del usuario. Por lo tanto, podemos usar funciones de entrada/salida como printf.

Si no incluye el stdio.harchivo en la parte superior de su código, la computadora no entenderá cuál printfes la función.

El programa principal en C

Aquí está el código:

int main(void)
{
}

Esta es la principal función de inicio de un programa en C. Las llaves ( {}) son el cuerpo que envuelve todo el código que debe estar en nuestro programa.

Esta línea actúa como modelo y punto de partida para todos los programas en C. Le permite a la computadora saber dónde comenzar a leer el código cuando ejecuta nuestros programas.

Comentarios en C

Lo que escribamos después //no afectará cómo se ejecuta nuestro código y la computadora no lo tendrá en cuenta durante el tiempo de compilación y ejecución.

Esas dos líneas indican que está agregando comentarios, que son notas para nosotros mismos en el futuro y para nuestros compañeros de trabajo. Los comentarios pueden ayudarnos a recordar y recordar a otros lo que hace una determinada línea de código o por qué escribimos ese código en primer lugar. También nos recuerda cuál es exactamente el propósito de ese código cuando volvemos a él al día siguiente o incluso meses después.

Salida o impresión a la consola en C

printf("Hello world/n");imprime la frase 'Hola mundo' en la consola. Usamos printfcuando queremos decir algo y ver la salida en la pantalla. Los caracteres que queremos generar deben estar entre comillas dobles ""y paréntesis ().

El /nes un carácter de escape, lo que significa que crea una nueva línea y le dice al cursor que se mueva a la siguiente línea cuando lo vea.

El ;indica el final de la oración y el final de esa línea de código.

Variables en C

Así es como definimos una variable en C:

Un elemento de datos que puede tomar más de un valor durante el tiempo de ejecución de un programa.

En los términos más simples, puede pensar en las variables como un cuadro con nombre. Una caja que actúa como un lugar de almacenamiento y ubicación para contener información diferente que puede variar en contenido.

Cada caja tiene un nombre único que actúa como una etiqueta colocada en el exterior que es un identificador único, y la información/contenido vive en el interior. El contenido es el valor de la variable.

Las variables se mantienen y apuntan a un valor, a algunos datos útiles. Actúan como referencia o abstracción de datos literales. Esos datos se almacenan en la memoria de la computadora y ocupan una cierta cantidad de espacio. Vive allí para que podamos recuperarlo más tarde y usarlo en nuestros programas cuando lo necesitemos.

Como sugiere el nombre, las variables a las que apuntan pueden variar. Pueden tomar diferentes valores a lo largo del tiempo a medida que cambia la información durante la vida del programa.

Asignación de Variables en C

El proceso de nombrar una variable se llama asignación. Estableces un valor específico que está a la derecha, a un nombre de variable específico que está a la izquierda. Utiliza el =o el operador de asignación para hacer esto.

Como mencioné, puede cambiar el valor de una variable, por lo que puede asignar y reasignar variables. Cuando reasigna un valor, el nuevo valor apunta al nombre de la variable. Entonces, el valor puede ser uno nuevo, pero el nombre de la variable permanece igual.

Cómo declarar vs inicializar una variable en C

El lenguaje de programación C es un lenguaje fuertemente tipado estáticamente , a diferencia de muchos otros lenguajes de programación modernos.

En los lenguajes tipificados estáticamente, debe declarar explícitamente que sus variables son de un determinado tipo de datos. De esa forma, el compilador sabe durante el tiempo de compilación si la variable puede realizar las acciones que se establecieron y solicitaron.

En los lenguajes tipificados dinámicamente , una variable puede cambiar entre diferentes tipos de datos sin necesidad de definir explícitamente ese tipo de datos.

Entonces, al declarar una nueva variable en el lenguaje C, debe definir y especificar qué tipo es y qué tipo de datos contiene su valor.

El tipo de una variable es el tipo del valor que contiene. Esto le permite al programa y luego al compilador saber qué tipo de información está almacenando.

Para declarar una variable, especifica el tipo de datos y le da un nombre a la variable . Un paso opcional es establecer un valor inicial. ¡No olvide el punto y coma al final, que termina la declaración!

#include <stdio.h>
 
int main(void)
{
  int n = 27;
  // int is the data type
  // n is the name 
  // n is capable of holding integer values
  // positive/negative whole numbers or 0
  // = is the assignment operator
  // 27 is the value
}

¿Cuál es la diferencia entre inicializar y declarar una variable?

En resumen:

int n; // declaration, create a variable called n capable of holding integer values
int n = 27; // initialisation, creating a variable called n and assigning a value, storing a number in that variable

int n;está declarando una variable. Declarar significa que definimos un nombre para la variable y especificamos su tipo.

No necesariamente necesitamos especificar un valor para la variable todavía. Esto es suficiente, ya que declarar una variable le dice a la computadora que queremos que exista una variable y necesitamos asignarle algo de espacio en la memoria. El valor puede y será almacenado en un momento posterior.

Cuando asignamos un valor a la variable más adelante, no es necesario especificar el tipo de datos nuevamente. También podemos declarar varias variables a la vez.

int name, age;

Si declaramos una variable y le asignamos un valor a la vez, esto se llama inicializar la variable.

int n = 27;está inicializando la variable. Se trata de asignar un valor inicial que podemos cambiar posteriormente.

Si el nuevo valor es del mismo tipo de datos, no necesitamos incluir el tipo de datos, solo el nuevo valor. Si el tipo de datos es diferente, obtendremos un error.

#include<stdio.h>

int main(void)
{
  int age = 27;
  age = 37;
  // the new value of age is 37
}

Reglas para nombrar variables en C

  • Los nombres de variables deben comenzar con una letra o un guión bajo, por ejemplo, agey _ageson válidos.
  • Un nombre de variable puede contener letras (mayúsculas o minúsculas), números o un guión bajo.
  • No puede haber otros símbolos especiales además de un guión bajo.
  • Los nombres de variables distinguen entre mayúsculas y minúsculas , por ejemplo, agees diferente de Age.

El alcance de una variable en C

El alcance de una variable se refiere a dónde se puede hacer referencia y acceder a la variable. Es esencialmente donde vive la variable y es válida y qué tan visible es para el resto del programa.

Ámbito local

Si una variable se declara dentro de un conjunto de llaves {}, como por ejemplo una función específica, ese será su alcance y no podemos acceder a ella y usarla fuera de esas llaves en el resto del programa. El resto del programa no sabrá que existe.

Por lo tanto, no es una buena idea declarar las variables de esa manera ya que su alcance y uso es tan limitado que puede dar lugar a errores. Este alcance se llama localalcance.

Alcance global

Si las variables se declaran fuera de las funciones, tienen globalalcance. Tener un alcance global significa que son visibles dentro de todo el programa y se puede acceder a ellos desde cualquier lugar.

Pero tenga en cuenta que puede ser difícil hacer un seguimiento de ellos. Además, cualquier cambio que les hagamos en el camino puede volverse confuso ya que pueden ocurrir en cualquier parte y ubicación del programa.

Tipos de datos en C

Los tipos de datos especifican en qué forma podemos representar y almacenar información en nuestros programas C. Nos permiten saber cómo se utilizará esa información y qué operaciones se pueden realizar sobre ella.

Los tipos de datos también determinan qué tipo de datos pueden contener nuestras variables, ya que cada variable en C necesita declarar qué tipo de datos representa.

Hay 6 tipos de datos integrados en el lenguaje. Pero puede convertir entre diferentes tipos, lo que hace que no esté tan fuertemente tipado.

Cada uno de los tipos de datos requiere una asignación diferente de memoria y cada tipo de datos puede tener diferentes rangos hasta los cuales pueden almacenar valores.

Agregar palabras clave delante del nombre de un tipo modifica y realiza cambios en el tipo. Estas palabras clave pueden estar firmadas o no firmadas .

Una palabra clave sin firmar significa que el tipo solo puede ser positivo y no negativo, por lo que el rango de números comienza desde 0. Una palabra clave firmada le permite hacer que un número sea negativo o positivo.

Veamos estos tipos de datos con más detalle.

El tipo de datos char en C

El tipo de datos más básico en C es char. Se usa para almacenar un solo carácter, como letras del gráfico ASCII como 'a', 'Z' o '!". (Observe cómo usé comillas simples alrededor del carácter único; no puede usar comillas dobles en este caso.)

chartambién le permite almacenar números que van desde [-128 a 127] y en ambos casos utiliza 1 byte de memoria.

Un carácter sin firmar puede tomar un rango de números [0-255]

El tipo de datos int en C

intes un número entero, un número entero, que puede contener un valor positivo o negativo o 0 pero que no tiene decimales.

Es un valor hasta un cierto número de bits. Cuando declara un int, la computadora le asigna 4 bytes de memoria. Más específicamente, usa al menos 2 bytes, pero generalmente 4. 4 bytes de memoria significa que asigna 32 bits (ya que 1 byte = 8 bits). Entonces, un int tiene 232 valores posibles, más de 4 mil millones de enteros posibles.

El rango es de -231 a 231-1, en concreto de [-2.147.483.648 a 2.147.483.647].

  • Un int sin signo todavía tiene el mismo tamaño que un int (4 bytes), pero eso no incluye los números negativos en el rango de valores posibles. Entonces el rango es de 0 a 232-1, más específicamente [0 a 4,294,969,295]
  • Un int corto tiene valores más pequeños que un int y asigna 2 bytes de memoria. Permite números en un rango de [-32,768 a 32,767]
  • Un int corto sin signo usa nuevamente 2 bytes de memoria y tiene un rango de números de [0 a 65,535]
  • Un int largo es para cuando necesitamos usar un número más grande. Utiliza al menos 4 bytes de memoria, pero generalmente 8 bytes con valores de [-2,147,483,648 a 2,147,483,647]
  • Un int largo sin signo tiene al menos 4 bytes de memoria con un rango de [0 a 4,294,967,295]
  • Un long long int es un número entero con más bits que puede contar hasta números cada vez más grandes en comparación con ints y long ints. Utilizan 8 bytes en lugar de 4, por lo que utilizan 64 bits. Esto permite un rango de -263 a 263-1, por lo que para números de [-9,223,372,036,854,775,808 a 9,223,372,036,854,775,807]
  • Un long long sin firmar usa 8 bytes y tiene un rango de números de [0 a 18,446,744,073,709,551,615]

El tipo de datos flotante en C

Los flotantes son un valor de punto flotante que es un número con un decimal (también llamado número real), con precisión simple. Asigna 4 bytes de memoria.

El tipo de dato doble en C

Un doble es un valor de punto flotante que tiene valores más grandes que el de un flotador. Puede contener más memoria, 8 bytes, en comparación con un flotante, y es de doble precisión.

  • Un doble largo es el tamaño más grande en comparación con los flotantes y los dobles, y contiene al menos 10 bytes de memoria, pero incluso puede contener hasta 12 o 16 bytes.

Y, por último, el tipo vacío esencialmente significa nada o ningún valor.

Códigos de formato en C

Los códigos de formato o especificadores de formato se utilizan para la entrada y salida en C.

Estas son una forma de decirle al compilador qué tipo de datos toma como entrada con una variable y qué tipo de datos produce como salida cuando usa la printf()función. El fin printf()significa formado .

Actúan como marcador de posición del código de formato y sustituyen a las variables. Le permiten al compilador saber de antemano de qué tipo son cuando el valor de la salida estándar (es decir, lo que queremos imprimir) aún no se conoce.

La sintaxis que usamos es % format specifier for data type:

#include<stdio.h>
int main(void)
{
	int age = 27;
	printf("My age is %i/n", age)
	// prints 27
// age is the variable we want to use 
// %i is the format specifier,a placeholder for an integer value
// we separate each argument with a comma
// in the output %i  is replaced with the value of age
}

Hay diferentes especificadores de formato para cada tipo de datos que discutimos anteriormente. Éstos son algunos de ellos:

ESPECIFICADOR DE FORMATOTIPO DE DATOS
%ccarbonizarse
%ccarácter sin firmar
%io&dEn t
%uint sin firmar
%hio%hdcorto
%huint corto sin firmar
%lio%ldlargo tiempo
%luint largo sin firmar
%llio%lldmucho tiempo
%lluint largo largo sin firmar
%fflotar
%lfdoble
%Lflargo doble

Operadores en C

Operadores aritméticos en C

Los operadores aritméticos son operadores matemáticos que realizan funciones matemáticas en números. Las operaciones pueden incluir suma, resta, multiplicación y división.

Los operadores más utilizados son:

  • +para la adición
  • -para la resta
  • *para la multiplicación
  • /para división
  • %para división módulo (calculando el resto de la división)

Operador de asignación en C

El operador de asignación =, asigna un valor a una variable. Se 'pone' un valor en una variable.

En otras palabras, establece lo que sea que esté en el lado derecho del =para ser el valor de la variable en el lado izquierdo del =.

Existen operadores de asignación específicos para actualizar una variable modificando el valor.

En C, hay varias formas de actualizar los valores de las variables. Por ejemplo, si queremos incrementar la variable por 1hay tres formas posibles de hacerlo.

Vale la pena mencionar primero que incrementar significa tomar el valor existente de una variable, cualquier valor que esté a la derecha, y agregarlo 1. Luego, el nuevo valor se almacena nuevamente en la variable y se actualiza automáticamente.

La forma más sencilla de incrementar o actualizar es llamar a una variable xcon un valor inicial de 5, por lo que:

x=5.

Para sumar 1a la variable x, hacemos lo x = x + 1que significa x = 5 + 1.

El nuevo valor de xes ahora 6, x=6.

Hay una abreviatura para esta operación, usando una sintaxis especial que incrementa las variables.

En lugar de escribir x = x +1podemos escribir x += 1.

Una forma aún más corta es usar el operador de incremento, que parece variable_name ++, en nuestro caso x++.

Lo mismo ocurre con la disminución, es decir, la disminución, de una variable en 1.

Las tres formas de hacerlo son:

x = x-1, x -= 1, x --(usando el operador de decremento) respectivamente.

Esas son las formas de incrementar y decrementar una variable 1en C. Podemos actualizar una variable tomando su valor y sumando, restando, multiplicando y dividiendo ese valor por cualquier otro número y estableciendo el resultado de esa operación como el nuevo valor. Esas operaciones serían +=, -=, *=y /=respectivamente.

Entonces x = x * 5o la abreviatura x *= 5tomará el valor de la variable xy lo multiplicará por 5y lo almacenará de nuevo en x.

Operadores Lógicos en C

Usamos operadores lógicos para tomar decisiones en C. El resultado de una operación puede ser verdadero o falso.

Existe el ANDoperador lógico, &&. Los operandos en los lados izquierdo y derecho de &&deben ser verdaderos para que la condición sea verdadera.

También existe el ORoperador lógico, ||. Al menos uno o ambos operandos en los lados derecho e izquierdo de ||deben ser verdaderos para que la condición sea verdadera.

Por último, está el lógico NOT. Esto invierte el valor del operando. Si un operando es verdadero, entonces el NOToperador hace que la condición sea falsa y viceversa.

Operadores de comparación en C

Los operadores de comparación son:

  • Mas grande que>
  • Mayor qué o igual a>=
  • Menos que<
  • Menos que o igual a=<

También hay un operador de comparación de igualdad, ==. No confunda esto con =, el operador de asignación.

Usamos el ==para comparar dos valores y probar para ver si son iguales o no. Este operador hace la pregunta '¿Son estos dos iguales?', mientras que =asigna un valor a una variable.

Cuando se usa el operador de comparación de igualdad y se hace la pregunta anterior, siempre hay un valor de retorno que puede ser trueo false, de lo contrario, se conoce como Boolean valueen el contexto de la programación de computadoras.

Por último, está el operador de desigualdad !=, que usamos para probar si dos valores NO son iguales.

Funciones en C

Las funciones son verbos, es decir, pequeñas acciones. Ellos hacen algo. Realizan una tarea particular y específica.

Encapsulan una parte del comportamiento que debe usarse una y otra vez. El propósito de las funciones es tener ese comportamiento escrito solo una vez en algún lugar para que pueda reutilizarlo cuando lo necesite, en diferentes momentos y en diferentes lugares a lo largo de un programa. Esto hace que su código sea más simple y esté mejor organizado.

Las funciones existen para realizar una tarea, cumplir un propósito particular y ser reutilizadas. Y pueden tomar insumos y producir productos.

Argumentos de función en C

Las entradas que toman las funciones se llaman argumentos. Una función puede tener uno o más argumentos.

Una función común en el lenguaje de programación C es printf();. Esto imprime algo en la pantalla. Es una función que se usa para decir algo.

Los paréntesis ()son las entradas de la función, donde entran los argumentos, es decir, lo que realmente queremos decir e imprimir en la pantalla. Lo que está entre paréntesis se imprime.

En printf("Hello world!");, Hello world!es la entrada a la printffunción. Aquí, llamamos a una función llamada yprintf le damos un argumento que es una cadena. Esto dice literalmente, imprime '¡Hola mundo! 'a la pantalla.

Salidas de función en C

Hay dos tipos de salida de función:

Primero, las salidas pueden ser simplemente algo visual, un efecto visual inmediato, algo impreso rápidamente en la pantalla.

No puedes hacer nada más con esa salida después del efecto. Como en el caso de printf("Hello world!");, la salida es la cadena "¡Hola mundo!" impreso en la pantalla, y eso es todo. No puede usar esa cadena de otra manera, porque printfno tiene valor de retorno.

Este tipo de funciones se conocen como efectos secundarios , lo que significa que tienen un efecto observable inmediato sin devolver un valor.

Además, una función como printfes una invocación de función y en la stdiobiblioteca se define como int printf(const char *format,...);.

En segundo lugar, la salida puede ser reutilizable y tiene un valor de retorno. Un valor de retorno es un valor que se devuelve al programador y se almacena en una variable para su uso posterior.

En tales casos, no hay un efecto inmediato: nada se imprime en la pantalla. En cambio, la salida se nos devuelve, se almacena como información y se guarda en una variable.

Cómo definir un método en C

Hay tres cosas que debe tener en la primera línea, la línea de desaceleración, al definir una función.

  1. El tipo de retorno

Esta es la primera palabra clave utilizada, y cómo comienza una función indica el valor devuelto.

Por ejemplo, en una función como: void say_something(void), el primer vacío significa que la función no tiene valor de retorno.

En otro ejemplo con una función diferente, int main(void)especificamos y definimos su tipo de datos de retorno, en este caso un int. La salida de la función será un inttipo de datos y se devolverá al lugar donde se llama a la función.

  1. El nombre de la función

El nombre puede ser cualquier cosa que queramos, aunque es una buena práctica nombrar los métodos después de lo que pretenden hacer.

  1. Ninguno o uno o más argumentos

Estas son las entradas de la función y el tipo de datos de esas entradas.

En void say_something(void), el voidinterior de los paréntesis es una palabra clave para el argumento y un marcador de posición para 'nada'. Significa que no requiere entradas. En casos como este, el argumento también se denomina parámetro.

Los parámetros son esencialmente variables declaradas en la función, dentro de los paréntesis como la voidpalabra clave. Actúan como un marcador de posición para acceder a los datos de entrada de la función, los argumentos.

Los parámetros se refieren al valor que se pasa al método. Esto significa que cuando más tarde llamamos a la función, le pasamos los valores reales, los argumentos a la función.

Cómo llamar a una función en C

Podemos llamar a una función como:

void say_hi(void)
{
	printf("hello");
}

Escribiendo el nombre de la función, seguido de cualquier argumento entre paréntesis y un punto y coma como say_hi();. La say_hifunción no recibe entradas y no tiene valor de retorno. Cuando se llama, simplemente imprime 'hola' en la pantalla.

Otra función como:

int square(int n)
{
	return n * n
}

se llama de la misma forma que en el ejemplo anterior. En este caso, la squarefunción toma una entrada y tiene un valor de retorno (ambos son ints). La entrada que toma es el parámetro llamado n, que devuelve un intcuando se llama a la función.

La palabra returnespecifica que lo que se devolverá, la entrada nmultiplicada por sí misma.

Por ejemplo, cuando se llama a la función square(3);, nactúa como una variable que apunta al parámetro que se ha pasado a la función, como 3. Es como lo hemos puesto n = 3. El valor que se devuelve es 9.

Las funciones están destinadas a ser reutilizadas, por lo que podemos usarlas en cualquier momento que deseemos elevar un número al cuadrado:

#include <stdio.h>

  int square(int x)
  {
    return x * x;
  }
 
  int main(void)
  {
   printf("%i\n", square(2));
   printf("%i\n", square(4));
   printf("%i\n", square(8));
 }

Cómo usar expresiones booleanas en C

Una expresión booleana es una expresión que se evalúa como uno de dos valores, verdadero o falso. Reciben su nombre del matemático, filósofo y lógico George Boole.

Captura de pantalla-2021-06-18-a-1.58.33-PM

George Boole Fuente de la imagen Wikimedia Commons

Usamos expresiones booleanas para comparar dos valores y son particularmente útiles para controlar el flujo.

Todo valor distinto de cero es truey 0es false.

Podemos combinar expresiones booleanas con el uso de diferentes operadores lógicos, como &&(y), ||(o) y !(no) mencionados anteriormente en el artículo.

Diferentes combinaciones de valores y operadores conducen a diferentes resultados de salida, que pueden expresarse en una tabla de verdad , una tabla matemática utilizada para representar ecuaciones lógicas cuyo resultado es 1o 0o su equivalente trueo false.

Al comparar dos valores booleanos usando el &&operador (y), ambos valores deben ser verdaderos para que la expresión combinada sea verdadera.

Por ejemplo, si alguien nos pregunta "¿Quieres una pizza y una ensalada?", la única forma de que la expresión sea cierta es que queramos tanto una pizza como una ensalada (por lo que nuestra respuesta es a ambas). Si la respuesta a una de ellas no es verdadera, toda la expresión es falsa.

Tabla de verdad para &&

VALOR AVALOR BRESULTADO
verdaderofalsofalso
falsoverdaderofalso
falsofalsofalso
verdaderoverdaderoverdadero

A diferencia &&de , el ||operador nos permite actuar si uno o ambos valores son verdaderos. Entonces, este operador no es exclusivo, cualquiera de las comparaciones tiene que ser verdadera para que la expresión se evalúe como verdadera o incluso ambas.

Esto es bastante exclusivo de la informática, ya que en nuestra pregunta de ejemplo utilizada anteriormente, si en lugar de Y la cambiamos por O, la afirmación "¿Quieres pizza o ensalada?" no significa que quieras ambos. Quieres uno o el otro, no necesariamente ambos juntos.

Tabla de verdad para ||

VALOR AVALOR BRESULTADO
verdaderofalsoverdadero
falsoverdaderoverdadero
falsofalsofalso
verdaderoverdaderoverdadero

Por último, el !operador (no) se usa para la negación, lo que significa que se convierte trueen falsey falseen true.

!true is false
!false is true

Cómo usar declaraciones condicionales en C

Las declaraciones condicionales toman una acción específica basada en el resultado de una comparación que se lleva a cabo. El acto de hacer una cosa si una condición en particular es verdadera y posiblemente otra cosa diferente si esa condición en particular resulta ser falsa se denomina flujo de control .

Es posible que ciertas partes del programa no se ejecuten dependiendo de los resultados o de ciertas entradas del usuario. El usuario puede recorrer diferentes caminos dependiendo de las diversas bifurcaciones en el camino que surjan durante la vida de un programa.

Los programas con sentencias condicionales utilizan ifprincipalmente bloques. Los bloques if usan boolean expressionsthat solo pueden ser verdadero o falso y toman decisiones dependiendo de esos valores resultantes. Denotamos una ifdeclaración de bloque usando llaves, {}y la sangría del código que sigue.

#include <stdio.h>
int main(void)
{
int x = 2;
int y = 3;

if (x < y)
 
// x < y is a boolean expression,it can only be true or false.
// If whatever is in the parentheses is true 
//-in this case is x is actually less than y-
//run the code that follows
{
	printf("x is less than y"); 

// Because x < y is true that statement will be printed
}

}

Una ifdeclaración por sí sola no es tan útil, especialmente a medida que los programas crecen más y más. Entonces, en ese caso, la ifdeclaración va acompañada de una elsedeclaración.

Esto significa que ' ifesta condición es verdadera, haga lo siguiente, elsehaga esto en su lugar'. La elsepalabra clave es la solución para cuando la ifcondición es falsa y, por lo tanto, no se ejecuta.

int main(void)
{ 
int  x = 1;
int  y = 2;

if ( x > y)
{
  printf("x is larger than y");
}

else 

{  
  printf("x is less than y");
// Because  x > y is false ,
// this block of code will be executed
// resulting in printing the statement of the else branch
}

}

Si deseamos elegir entre más de dos opciones y queremos tener una mayor variedad de declaraciones y acciones, entonces podemos introducir una else ifcondición.

Esto significa que 'Si esta condición es verdadera, haz esto. Si no es así, haz esto en su lugar. Sin embargo, si nada de lo anterior es cierto, finalmente haz esto en su lugar.'

#include <stdio.h>
int main(void)
{
  int x = 2;
  int y = 2;

  if(x < y)
   // if this condition is true run this block
  {
    printf("x is less than y");
  }
 else if(x > y)
  / / if the above statement was true run this block instead
 { 
    printf("x is greater than y");
 } 
 else  
   // if this block of code runs 
   //it runs because x < y was false 
  //and so was x > y 
  //so it means x == y
 {
    printf("x is equal to y");
 }
}

Cómo usar bucles en C

Un bucle es un comportamiento aislado o un conjunto específico de instrucciones que se repiten una cierta cantidad de veces, una y otra vez, hasta que se cumple una condición. Es la misma acción, el mismo código, que se repite una y otra vez.

Mientras bucles en C

Antes de ejecutar cualquier código, los bucles while deben verificar una condición. Si se cumple, el código se ejecuta. Si no, el código no realiza ninguna acción. Por lo tanto, no se garantiza que el código se ejecute al menos una vez si no se cumple una condición.

Hay diferentes tipos de bucles while. Uno de ellos es un bucle infinito.

#include <stdio.h> 
int main(void)
{

	while(true)
	{
		printf("Hello world");
	}
}

La whilepalabra clave se usa junto con una expresión booleana requerida, trueen este caso (que siempre permanece como true).

Después de imprimir la línea de código dentro de las llaves, verifica continuamente si debe ejecutar el código nuevamente. Como la respuesta es siempre yes(ya que la condición que necesita verificar siempre es verdadera todas y cada una de las veces), ejecuta el código una y otra vez.

En este ejemplo, la única forma de detener el programa y escapar del bucle sin fin es ejecutarlo Ctrl + Cen la terminal.

Si la condición fuera false, nunca ejecutaría el código dentro de las llaves.

Otro bucle, es un bucle que repite algo un cierto número de veces.

#include <stdio.h>
int main(void)
{
	int i = 0;

	while(i < 10)
	{
	//while i is less than 10 run this code
		printf("Hello world");
	// and then increment
		i++
	//check the condition everytime
  //once the code in the curly braces is run, check if i is still less than 10.
  // If so run code + increment again and check again
	//loop will eventually end when i reaches 10
	}
}

Bucles do-while

#include <stdio.h>
 
int main(void)
 {
   int i = 10;
   do {
      printf("the value of i: %i\n", i);
      i++;
   }
  while( i < 20 );
}

En comparación con el whileciclo, do- whilese garantiza que el ciclo se ejecutará al menos una vez y ejecutará el código dentro de las llaves al menos una vez.

Primero hace algo y luego verifica una condición. Esto es útil cuando queremos repetir algo al menos una vez pero por un número desconocido de veces.

En nuestro ejemplo, el código se ejecutará al menos una vez y la declaración se imprimirá al menos una vez. A continuación, se incrementa el valor. Luego verifica si el valor es inferior a 20 y, de ser así, ejecuta el código nuevamente. Dejará de ejecutar el código una vez que el valor que se incremente cada vez no sea inferior a 20.

Recursos para seguir aprendiendo C

¡Esto marca el final de esta introducción al lenguaje de programación C! Buen trabajo por llegar hasta el final.

Espero que esto le haya dado una idea de los "por qué" y los "cómo" del lenguaje y los fundamentos que necesita saber para comenzar a escribir programas básicos en C.

Si desea profundizar más, crear algunos proyectos y resolver problemas con C, pruebe CS50 Introducción a las ciencias de la computación .

Si te gusta aprender leyendo libros, te recomiendo los siguientes:

Si le gusta aprender viendo videos y codificando, consulte el video Tutorial de programación C para principiantes en el canal de YouTube de freeCodeCamp.

¡Gracias por leer y feliz codificación! 

Esta historia se publicó originalmente en https://www.freecodecamp.org/news/what-is-the-c-programming-language-beginner-tutorial/  

#csharp #cprogramming 

¿Qué Es El Lenguaje De Programación C? Un Tutorial Para Principiantes

Cプログラミング言語とは何ですか?初心者のためのチュートリアル

このチュートリアルでは、Cプログラミング言語の基本的な概念の概要を説明します。

言語の歴史、それが使用される理由と場所、コンパイルプロセス、および最も一般的なプログラミング言語で一般的ないくつかの非常に基本的なプログラミング概念について説明します。

これは言語の完全なガイドではありませんが、コーディングの完全な初心者として、重要なCの概念とアイデアを高度に理解するのに役立ちます。

各言語には独自の構文と特定の方法がありますが、ここで取り上げる概念は共通であり、すべてのプログラミング言語に適用されます。

物事がどのように機能するか、そしてこれらの普遍的な概念を理解することは、コーディングの旅に長い道のりを歩むことができます。これにより、長期的には新しいテクノロジーの学習が容易になります。

このチュートリアルは、コースCS50:コンピュータサイエンス入門の最初の数週間で取り上げた資料から大きなインスピレーションを得ています。これは、経験のレベルに関係なく、コンピュータサイエンスとプログラミングを深く掘り下げたい人に強くお勧めします。

Cプログラミング言語の歴史

Cプログラミング言語の歴史は、Unixオペレーティングシステムの開発の歴史と密接に関係しています。

コンピューティングの世界を変えたオペレーティングシステムの開発につながった理由を振り返ると、Cの開発につながったステップがわかります。

簡単に言えば、Cは、Unixオペレーティングシステムに適用する言語を最初に見つけて最終的に作成する必要性から派生したものです。

プロジェクトMACとMULTICS

それはすべて、1965年に実験プロジェクトMACがMITで完了したときに始まりました。これはこの種の最初のシステムです。これがMULTICS時代の始まりでした。CTSS、または互換性のあるタイムシェアリングシステムと呼ばれるものを使用しました。

これは当時の重要な革新でした。この時点まで、私たちはメインフレームの初期の時代にあり、巨大で強力で非常に高価なコンピューターが部屋全体を占有していました。

タスクを実行するために、プログラマーは手作業でコードを記述します。それから彼らは手で書かれたプログラムでエンコードされた紙テープカードのデッキを打ち抜きました。

彼らは、プログラムが書かれた紙を、カードの穴を開けてカードのデータと指示を表すキーパンチマシンを使用するオペレーターに渡すことによってこれを行いました。

次に、メインフレームコンピュータに接続されたパンチカードリーダーにパンチカードを送ります。次に、カードの穴のシーケンスをデジタル情報に変換しました。この方法を使用すると、単純なタスクに長い時間がかかり、一度に1台のマシンしか使用できませんでした。

タイムシェアリングのアイデアはすべてを変えました。カードを使用する代わりに、複数のコンソール(当時はテレタイプと呼ばれる機械式端末でした)をメインコンピューターに接続しました。これにより、多くの人が同じコンピューターを同時に使用できるようになりました。

MITのキャンパス全体に広がる100を超えるタイプライター端末を、1台の主要な大型コンピューターに接続することができます。このシステムは、同時に最大30人のリモートユーザーをサポートし、それぞれがこれらの端末の1つを使用していました。

メインコンピュータのオペレーティングシステムは、接続された端末からコンピューティングタスクを実行したい人々の周りをマルチタスクで囲み、それぞれに数秒を与えました。

それは、多くのプログラムを同時にロードして実行しているように見える、継続的なサービスのように見えるものを提供しました。しかし実際には、それは各ユーザーのプログラムを非常に迅速に通過しただけです。これは、一人の人が自分自身にコンピュータ全体を持っているという幻想を与えました。

これらのコンピューターは非常に高価であったため、このシステムは非常に効率的、効果的、生産的であり、時間と長期的なコストを節約できることが証明されました。

完了するまでに数日かかっていたかもしれないものが、今でははるかに短い時間で完了しました。そしてこれにより、コンピューティングへのアクセスが向上し始めました。

CTSSの成功に続いて、MITは、このシステムに基づいて構築し、次のステップに進む時が来たと判断しました。この次のステップは、より高度なタイムシェアリングシステムを作成することです。

しかし、彼らはそれよりも野心的な取り組みを想像しました。メインフレームに同時にアクセスする何百人ものユーザーをサポートできるプログラマーのコンピューティングユーティリティとして機能するシステムを構築したかったのです。そして、それはそれらの間でデータとリソースを共有するでしょう。

これにはより多くのリソースが必要になるため、彼らはGeneralElectricおよびBellLabsと協力しました。

この新しいプロジェクトはMULTICSと名付けられました。これは「MultiplexedInformationandComputing Service」の略で、GeneralElectricのメインフレームの1つであるGE635に実装されました。

このチームは、MULTICSに何年も取り組んできました。しかし、1969年にベル研究所は、時間がかかりすぎ、費用がかかりすぎたため、プロジェクトを辞めました。

ベル研究所:イノベーションハブ

Bell LabsがMULTICSプロジェクトから撤退したことで、一部の従業員は不満を募らせ、代替案を探していました。

MULTICSに取り組んでいる間、チームは比類のないコンピューティング環境を作成しました。彼らはタイムシェアリングシステムでの作業に慣れており、その有効性を確認していました。これらのプログラマーはオペレーティングシステムに関する幅広い知識を持っていたため、そのプロジェクトの革新により、さらに拡張したいと考えました。

主にKenThompsonとDennisRitchieが率いるグループは、共同コンピューティングを使用して、共有できるファイルシステムを作成したいと考えていました。それは彼らがMULTICSから気に入った革新的な特徴を持っているでしょうが、彼らはそれをシンプルで、より小さく、そしてより安価な方法で実装するでしょう。

彼らはアイデアを共有し、繰り返し始めました。

スクリーンショット-2021-02-07-at-7.03.16-PM-1

ケン・トンプソンとデニス・リッチー、ウィキペディアの画像ソース

ベル研究所は、創造的な表現と革新的なアイデアを開花させるオープンで支援的な環境を育てました。それは研究が重く、彼らは最初の解決策を改善するのを助けるために独立した思考の問題解決を奨励しました。

たくさんの議論と実験を通して、彼らは最大のブレークスルーを作り、歴史を書きました。

まだMULTICSに取り組んでいる間、ケントンプソンはスペーストラベルと呼ばれるゲームを作成しました。彼は当初、それをMULTICS、GE 635で作成しましたが、ベル研究所が撤退したとき、彼は、GE635で実行されるGECOSオペレーティングシステムで実行するFortranプログラムに構えを適合させました。

ゲームには多くの問題がありました。GECOSではMULTICSの場合ほどうまく機能せず、実行するには別の安価なマシンが必要でした。

ケントンプソンは、ベル研究所がすでにそのようなプロジェクトから撤退していたため、別のオペレーティングシステムを作成するための資金を要求したときに拒否に直面しました。しかし、彼は結局、試してみることができる、古くてほとんど使用されていないDECPDP-7ミニコンピューターを見つけました。これが利用可能な唯一のシステムでした。

スクリーンショット-2021-02-07-at-7.00.24-PM

DEC PDP-7、ウィキペディアの画像ソース

彼はその単純なシステムでゲームを書き始めましたが、コンピューター上のソフトウェアによって制限されていました。それで、彼がそれに取り組んでいる間、彼は彼のチームが想像していたファイルシステムの骨組みを実装することになりました。

彼は、階層ファイルシステム、コマンドラインインタープリター、およびその他のユーティリティプログラムから始めました。1か月以内に、彼はアセンブラー、エディター、およびシェルを備えたオペレーティングシステムを作成しました。それらはMULTICSのより小さくて単純な機能でした。このオペレーティングシステムは、Unixの最初のバージョンでした。

アセンブリ言語を使用したUnixの初期

プロジェクトの開始時に、KenThompsonはDECPDP-7コンピューターでプログラミングできませんでした。DEC PDP-7プログラムは、より強力なGE 635メインフレームでコンパイルおよび変換する必要があり、その後、出力は紙テープでPDP-7に物理的に転送されました。

DEC PDP-7のメモリはごくわずかで、わずか8KBでした。この制限に対処するために、ファイルシステム、Unixカーネルの最初のバージョン、およびプロジェクト内の他のすべてのものがアセンブリでコーディングされました。アセンブリを使用すると、トンプソンはそのコンピュータのメモリの各部分を直接操作および制御できます。

アセンブリ言語は、シンボリックコードを使用し、マシンの母国語であるバイナリに近い低レベルのプログラミング言語です。コード内の命令と言語内の各ステートメントは、コンピューターのアーキテクチャーに固有のマシン命令に密接に対応しています。

これはマシンに依存し、マシン固有です。つまり、1セットの命令は、マシンごとに結果が大きく異なります。アセンブリ言語で記述されたプログラムは特定のタイプのプロセッサ用に記述されているため、アセンブリ言語で記述されたプログラムはさまざまなプロセッサでは機能しません。

当時は、アセンブリ言語を使用してオペレーティングシステムを作成するのが一般的でした。そして、彼らが最初にUnixで作業を始めたとき、彼らは移植性を念頭に置いていませんでした。

彼らは、オペレーティングシステムが異なるマシンシステムやアーキテクチャで動作するかどうかを気にしませんでした。それは後で起こった考えでした。彼らの主な優先事項は、ソフトウェアの効率でした。

MULTICSに取り組んでいる間、彼らは最初のPL/Iや後のBCPLのような高級プログラミング言語を使用していました。プログラマーは、オペレーティングシステムの種類のソフトウェア、ユーティリティ、およびツールを作成するために高級言語を使用することに慣れていました。これは、プログラマーが提供する利点のためです(比較的使いやすく、理解しやすいものでした)。

高水準プログラミング言語を使用する場合、コンピューターのアーキテクチャーとさまざまなあいまいな詳細の間に抽象化があります。これは、それがマシンのレベルを超えており、ハードウェアのメモリを直接操作できないことを意味します。

高水準言語は、読み、学び、理解し、維持するのが簡単であるため、チームで作業するときに簡単に選択できます。コマンドには英語のような構文があり、用語と命令は、アセンブリの記号形式と比較して、より親しみやすく、人間にわかりやすいように見えます。

高水準言語を使用するということは、何かを達成するために書くコードが少なくなることも意味しますが、アセンブリプログラムは非常に長いものでした。

Thompsonは、最初からUnixに高級言語を使用したいと考えていましたが、DECPDP-7によって制限されていました。

プロジェクトが進行し、より多くの人々がプロジェクトに取り組み始めるにつれて、Assemblyの使用は理想的ではありませんでした。Thompsonは、Unixには高レベルのシステムプログラミング言語が必要であると判断しました。

1970年に、彼らは、実質的により多くのメモリを備えた、より大きく、より強力なDECPDP-11の資金を得ることができました。

アセンブリを置き換えることができる高速で構造化されたより効率的な高級プログラミング言語を使用すると、誰もがコードを理解でき、コンパイラをさまざまなマシンで利用できるようになります。

彼らは、Unixの実装に使用できるシステムソフトウェアを作成するためのさまざまな言語の調査を開始しました。

BからCへ:新しい言語の必要性

目的は、Unixで実行するユーティリティ(機能を追加するプログラム)を作成することでした。Thompsonは最初にFORTRANコンパイラーを作成しようとしましたが、その後、以前に使用した言語であるBCPL(Basic Combined Programming Language)に目を向けました。

BCPLは、1960年代後半にMartinRichardsによって設計および開発されました。その主な目的は、コンパイラとシステムソフトウェアを作成することでした。

この言語は遅く、多くの制限があったため、トンプソンが1970年にDEC PDP-7のUnixプロジェクトで使用し始めたとき、彼は調整と修正を行い、最終的にBと呼ばれる独自の言語を作成しました。

BにはBCPLの多くの機能がありましたが、それはより小さな言語であり、構文がより冗長でなく、スタイルがより単純でした。ただし、Unixユーティリティをサポートするにはまだ低速で強力ではなく、PDP-11の強力な機能を利用できませんでした。

デニス・リッチーは、これら2つの以前の言語、BCPLとBを改良することを決定しました。彼はそれぞれから機能と特性を取り入れ、追加の概念を追加しました。彼は、アセンブリと同じくらい強力で効率的な、より強力な言語Cを作成しました。この新しい言語は、以前の言語の制限を克服し、マシンの能力を効果的に使用することができました。

そのため、1972年にCが誕生し、最初のCコンパイラがDECPDP-11マシンで初めて作成および実装されました。

スクリーンショット-2021-02-09-at-12.51.23-PM

PDP-11に取り組んでいるトンプソンとリッチーの有名な写真、画像ソースウィキペディア

Cプログラミング言語

1973年、デニスリッチーは、Cプログラミング言語を使用してUnixソースコードとほとんどのUnixプログラムおよびアプリケーションを書き直しました。これにより、オペレーティングシステムの標準実装言語になりました。

彼はUnixカーネルをCで再実装し、ほとんどすべてのオペレーティングシステム(90%以上)がこの高級言語で書かれています。高レベルの可読性機能と低レベルの機能の両方が混在しているため、オペレーティングシステムの作成に最適です。

1970年代後半にかけて、Cの人気が高まり始め、言語はより広くサポートされ、使用されるようになりました。その時点まで、CはまだUnixシステムでのみ利用可能であり、コンパイラはベル研究所以外では利用できませんでした。

この人気の高まりは、Cがマシンに与えた力だけでなく、プログラマーにも与えられたものです。また、Unixオペレーティングシステムがさらに速い速度で同じ人気を獲得していることも助けになりました。

Unixは、その移植性とさまざまな異なるマシン、システム、および環境で実行できる能力により、以前のものよりも際立っていました。

Cはその移植性を可能にし、それがUnixシステムの言語であったため、より多くの悪評を得ました。そのため、ますます多くのプログラマーがそれを試してみたいと思っていました。

1978年、ブライアン・カーニハンとデニス・リッチーは、プログラミングコミュニティでは「K&R」としても知られる「Cプログラミング言語」の本の初版を共同執筆し、出版しました。何年もの間、このテキストは、C言語の説明、定義、および参照の頼みの綱でした。

スクリーンショット-2021-02-09-at-4.20.50-PM

本の表紙、画像ソースウィキペディア

1980年代には、さまざまなコンパイラが作成されて商業化されるにつれて、Cの人気が急上昇しました。Cの設計に関与しなかった多くのグループや組織は、すべてのオペレーティングシステムとコンピューターアーキテクチャ構造用のコンパイラーの作成を開始しました。Cはすべてのプラットフォームで利用できるようになりました。

これらの組織が独自のコンパイラを作成するにつれて、コンパイラが作成された各プラットフォームに適応するように言語の特性を変更し始めました。

Cにはさまざまなバージョンがあり、それらの間にはわずかな違いがありました。コンパイラーを書いている間、これらのグループは、本「Cプログラミング言語」の初版に基づいた言語のいくつかの側面の独自の解釈を思いつきました。

しかし、すべての反復と調整により、この本はもはや言語をそのままでは説明しておらず、言語の変更が問題を引き起こし始めました。

世界は、言語の標準であるCの共通バージョンを必要としていました。

C標準

言語の標準的な機械に依存しない定義があることを確認するために、ANSI(米国規格協会)は1983年に委員会を設立しました。この委員会はX3J11委員会と名付けられ、その使命は明確で包括的な定義と標準化を提供することでした。 Cの。

数年後の1989年に、委員会の作業が行われ、公式になりました。彼らはその言語の商業的基準を定義しました。その言語のバージョンは、「ANSIC」またはC89として知られています。

Cは世界中で使用されていたため、1年後の1990年に、この規格は国際標準化機構であるISOによって承認および採用されました。最初のバージョンであるC90は、ISO / IEC 9899:1990と呼ばれていました。

それ以来、言語の多くの改訂が行われました。

この規格の2番目のバージョンであるC99は、1999年にISO / IEC 9899:1999と呼ばれるものとして公開され、新しい言語の追加機能が導入されました。3番目のバージョンであるC11は2011年に公開されました。最新バージョンは4番目のバージョンであるC17であり、ISO / IEC 9899:2018と呼ばれます。

Cの続き

Cは、多くの異なるプログラミング言語を作成するための道を築きました。私たちが今日使用し、愛している現代の高級プログラミング言語の多くは、Cに基づいています。

Cの後に作成された言語の多くは、Cが解決できなかった問題を解決したり、Cを制限する問題のいくつかを克服したりしたいと考えていました。たとえば、Cの最も人気のある子は、オブジェクト指向拡張C ++ですが、Go、Java、JavaScriptです。 Cにも触発されました。

C言語の特徴とCの学習を検討すべき理由

Cは古い言語ですが、何年も経った今でも人気があります。

それはUnixの台頭と成功のおかげで人気がありますが、今日では、Unixの「母国語」であるだけではありません。現在、世界のサーバーとシステムのすべてではないにしても、ほとんどに電力を供給しています。

プログラミング言語は、大規模に影響を与える特定のコンピューティングの問題を解決するために使用するツールです。

WebページやWebアプリケーションを作成するためにCを知る必要はありません。ただし、オペレーティングシステム、他のプログラムを制御するプログラム、カーネル開発用のプログラミングユーティリティを作成する場合、または組み込みデバイスやシステムアプリケーションをプログラムする場合に便利です。Cはこれらすべてのタスクに優れています。それでは、Cを学ぶいくつかの理由を見てみましょう。

それはあなたがあなたのコンピュータがどのように機能するかを理解するのを助けます

Cは汎用プログラミング言語であるという事実にもかかわらず、主に低レベルのマシン機能と対話するために使用されます。言語学習の背後にある実際的な理由に加えて、Cを知ることは、コンピューターが実際にどのように機能するか、内部で何が起こっているか、プログラムが実際にマシン上でどのように実行および実行されるかを理解するのに役立ちます。

Cは他のプログラミング言語のベースと見なされているため、この言語で使用されている概念を学ぶことができれば、後で他の言語を理解しやすくなります。

Cコードを書くことで、私たちのマシンで起こっている隠れたプロセスを理解することができます。これにより、アセンブリ言語をいじることなく、コンピューターの基盤となるハードウェアに近づくことができます。また、高級言語のように読みやすくしながら、多数の低水準タスクを処理することもできます。

Cは高速で効率的です

同時に、アセンブリが提供するコードの実行方法の機能、効率、および低レベルの制御を失うことはありません。

すべてのデバイスのハードウェアの各プロセッサには、そのプロセッサに固有の独自のアセンブリコードがあることを忘れないでください。他のデバイスの他のプロセッサとはまったく互換性がありません。

Cを使用すると、最下位レベルでコンピューターを操作するための、より速く、より簡単で、全体的に面倒なアプローチが得られます。実際、高レベルと低レベルの両方の機能が混在しています。そして、それは私たちが長い理解できないアセンブリコードの面倒と大騒ぎなしで仕事を成し遂げるのを助けます。

したがって、Cは、コンピューターの基盤となるハードウェアにできるだけ近づき、システムソフトウェアを操作および実装するときに、アセンブリ(オペレーティングシステムを作成するための古い標準)の優れた代替品になります。

Cは強力で柔軟性があります

このようにハードウェアに近接しているということは、Cコードが明示的かつ正確に記述されていることを意味します。これにより、コードがコンピューターとどのように相互作用しているかを明確に把握し、メンタルモデルを得ることができます。

Cは、マシンの操作の複雑さを隠しません。手動で割り当て、操作し、メモリに直接書き込む機能など、多くのパワーと柔軟性を提供します。

プログラマーは多くの面倒な作業を行い、言語を使用すると、マシンが高性能、最適化、および速度を提供するための効率的な方法でメモリを管理および構造化できます。Cを使用すると、プログラマーは必要なことを実行できます。

Cはポータブルで、パフォーマンスが高く、マシンに依存しません

Cはまた、携帯性が高く、マシンに依存しません。マシンに近く、低レベルの機能にアクセスできますが、コードの移植性を可能にするために、これらの部分から十分に抽象化されています。

アセンブリ命令はマシン固有であるため、プログラムは移植性がありません。あるマシンで作成された1つのプログラムは、別のマシンで実行するために再作成する必要があります。そして、それをすべてのコンピュータアーキテクチャで維持するのは困難です。

Cはユニバーサルであり、Cで記述されたプログラムは、パフォーマンスを損なうことなく、多くのプラットフォーム、アーキテクチャ、およびさまざまなマシンでコンパイルおよび実行できます。これにより、Cは、パフォーマンスが本当に重要なシステムやプログラムを作成するための優れた選択肢になります。

Cは他の多くのプログラミング言語の作成に影響を与えました

Python、Ruby、PHP、Javaなど、今日一般的に使用されている多くの言語は、Cに触発されました。これらの現代言語は、Cに依存して機能し、効率的です。また、それらのライブラリ、コンパイラ、およびインタプリタはCで構築されています。

これらの言語は、プログラムが実際に内部でどのように機能するかについての詳細のほとんどを隠しています。これらの言語を使用すると、より多くのレベルの抽象化があるため、メモリ割り当てやビットとバイトを処理する必要はありません。また、メモリとのやり取りでエラーが発生しやすい高レベルのアプリケーションでは、このレベルのきめ細かい制御は必要ありません。

ただし、オペレーティングシステムまたは組み込みデバイスの一部を実装している場合は、それらの下位レベルの詳細と直接処理を知っていると、よりクリーンなコードを作成するのに役立ちます。

Cはかなりコンパクトな言語です

Cは非常にわかりにくく、初心者には習得が難しい場合がありますが、実際には、キーワード、構文、および組み込み関数のセットが最小限である、かなり小さくコンパクトな言語です。したがって、言語がどのように機能するかを調べるときに、言語のすべての機能を学習して使用することが期待できます。

オペレーティングシステムやシステムアプリケーションのプログラミング方法を学ぶことに興味がない場合でも、Cの基本と、それがコンピューターとどのように相互作用するかを知っていると、コンピューターサイエンスの概念と原則の優れた基盤が得られます。

また、メモリがどのように機能し、配置されているかを理解することは、基本的なプログラミングの概念です。したがって、コンピューターがより深いレベルでどのように動作するか、および発生しているプロセスを理解することは、他の言語を学び、使用するのに本当に役立ちます。

Cはどこで使われていますか?

何十億もの人々が日常生活で使用しているデバイス、製品、ツールには、多くのCコードが含まれています。このコードは、世界のスーパーコンピューターから最小のガジェットまで、あらゆるものに電力を供給します。

Cコードは、あらゆる種類の組み込みシステムとスマートデバイスを機能させます。例としては、冷蔵庫、テレビ、コーヒーメーカー、DVDプレーヤー、デジタルカメラなどの家電製品があります。

あなたのフィットネストラッカーとスマートウォッチ?Cを搭載。あなたの車のGPS追跡システム、さらには信号機のコントローラー?ご想像のとおり– C.そして、Cコードで実行される産業、医療、ロボット工学、および自動車産業で使用される組み込みシステムの多くの例があります。

Cが広く使用されているもう1つの分野は、オペレーティングシステムとカーネル開発です。言語が作成されたUnixの他に、他の主要で人気のあるオペレーティングシステムはある程度Cでコード化されています。

Microsoft Windowsカーネルは主にCでスクリプト化されており、Linuxカーネルも同様です。ほとんどのスーパーコンピューターはLinuxを搭載しており、ほとんどのインターネットサーバーも同様です。これは、Cがインターネットの大部分に電力を供給していることを意味します。

LinuxはAndroidデバイスにも電力を供給しているため、Cコードはスーパーコンピューターやパーソナルコンピューターだけでなく、スマートフォンも機能させます。OSXでさえある程度Cでコーディングされているため、MacコンピュータもCで実行できます。

Cは、デスクトップアプリケーションとGUI(グラフィカルユーザーインターフェイス)の開発にも人気があります。ビデオや写真の編集やグラフィックデザインに使用するほとんどのAbodeアプリケーション(Photoshop、Adobe illustrator、Adobe Premiereなど)は、Cまたはその後継のC++でコーディングされています。

さまざまな言語用のコンパイラ、インタプリタ、およびアセンブラは、Cを使用して設計および構築されています。実際、これらは言語の最も一般的な使用法の一部です。

多くのブラウザとその拡張機能は、Google ChromiumやGoogleファイルシステムのように、Cで構築されています。開発者はデータベース設計でもCを頻繁に使用し(MySqlとOracleはCで構築された最も人気のあるデータベースシステムの2つです)、多くのコンピューターゲームで高度なグラフィックスを強化します。

この一般的な概要から、Cとその派生C++がインターネットと世界全体の大部分を実行していることがわかります。私たちが日常生活で使用しているデバイスやテクノロジーの多くは、Cで記述されているか、Cに依存しています。

Cコンパイルプロセス:書き込み-コンパイル-実行

Cのプログラムとは何ですか?

Cで記述されたコンピュータープログラムは、コンピューターが実行する、人間が読み取れる順序付けられた一連の命令です。これは、特定のコンピューティングの問題に対する解決策を提供し、従う必要のある一連の指示を使用して特定のタスクを実行するようにコンピューターに指示することを目的としています。

基本的に、すべてのプログラムは、使用しているプログラミング言語によって定義された特別な構文を使用する、コンピューターのハードドライブに保存されているプレーンテキストファイルです。

各言語には、何を書くことができ、何が有効と見なされ、何が無効であるかを規定する独自のルールがあります。

プログラムにはキーワードがあります。キーワードは予約されており、言語の一部である特定の単語です。また、文字列や数字などの文字通りのデータもあります。そして、それは言語の規則に従う単語を持っています。それは私たちが定義し、まだ存在していない言語(変数やメソッドなど)に導入します。

コンパイラとは何ですか?

プログラムは私たちによって、そして私たちのために書かれています。それらは人間が理解することを目的としています。

人間が読める形式でプログラムを作成すると、理解できますが、コンピューターでは理解できない場合があります。コンピュータはプログラミング言語を直接理解するのではなく、バイナリのみを理解します。したがって、コンピュータが実際にプログラムの指示を理解できるように、プログラムをこの別の形式に変換する必要があります。

高水準言語のプログラムは、コンパイルまたは解釈できます。彼らはそれぞれコンパイラとインタプリタと呼ばれる特別なソフトウェアを使用しています。

コンパイラとインタプリタの違いは何ですか?

コンパイラとインタプリタはどちらもプログラムですが、はるかに複雑で、トランスレータとして機能します。彼らは人間が読める形式で書かれたプログラムを取り、それをコンピューターが理解できるものに変えます。また、さまざまなコンピュータシステムでプログラムを実行および実行できるようにします。

コンパイルされたプログラムは、最初に機械可読形式に変換されます。つまり、実行前に機械語に変換されます。機械語は数値言語であり、0と1のシーケンスで構成されるバイナリ命令です。

このコンパイルにより、実行可能プログラムが生成されます。これは、CPU(中央処理装置)が直接読み取り、理解、および実行できる機械語のコードを含むファイルです。

この後、プログラムは実行可能になり、コンピューターはプログラムの指示どおりに動作します。コンパイルされたプログラムは、基盤となるハードウェアとの対応が強く、コンピューターのCPUとメモリをより簡単に操作できます。

一方、インタプリタされたプログラムは、マシンによって直接実行されることも、機械語プログラムに変換される必要もありません。代わりに、実行時にコード内の各ステートメントと命令を1行ずつ自動的に直接変換して実行するインタープリターを使用します。

Cはコンパイルされたプログラミング言語です。これは、コンパイラを使用してCで記述されたソースコードを分析し、それをコンピュータのハードウェアが直接実行できるバイナリファイルに変換することを意味します。これは、特定のマシンごとに固有です。

例を使用したGCCコンパイラの使用方法

UnixおよびUnixライクなシステムには、すでにCコンパイラが組み込まれてインストールされています。これは、LinuxとMacOSには、GCCコンパイラ(またはGNUコンパイラコレクション)と呼ばれる一般的なコンパイラが組み込まれていることを意味します。

このセクションの残りの部分では、このコンパイラを使用した例を示します。これらの例は、UnixまたはUnixライクなシステムに基づいています。したがって、Windowsシステムを使用している場合は、必ずWindows SubsystemforLinuxを有効にしてください。

まず、GCCコンパイラがインストールされていることを確認してください。ターミナルを開いて、gcc --version通常は$文字の後にあるプロンプトを入力することで確認できます。

MacOSを使用していて、コマンドライン開発ツールをインストールしていない場合は、インストールを求めるダイアログボックスが表示されます。その場合は、先に進んでインストールしてください。

それらをインストールしたら、新しいターミナルセッションを開き、gcc --versionコマンドを再入力します。コマンドラインツールを既にインストールしている場合は、次の出力が表示されます。

スクリーンショット-2021-02-17-at-3.02.52-PM

ただし、実際には舞台裏で多くのステップが発生しているため、コンパイルだけという用語は抽象化と単純化です。これらは、Cプログラムの作成、コンパイル、実行の間に発生する、より細かい下位レベルの詳細です。ほとんどの場合、私たちが気付かないうちに自動的に発生します。

Cソースコードの書き方

Cプログラムを開発するには、まず何らかのテキストエディタが必要です。テキストエディタは、コード(ソースコードと呼ばれる)をテキストファイルに書き込むために使用できるプログラムです。

このために、nanoやVimなどのコマンドラインテキストエディタに慣れている場合は、それらを使用できます。

IDE(統合開発環境)、またはIDEのような機能(統合端末、エディターを離れることなくプログラムをすべて1か所で作成、デバッグ、実行、実行する機能など)を備えたテキストエディターを使用することもできます。 。

これらの機能を備えたエディターの1つは、C /C++拡張機能を使用するVisualStudioCodeです。このチュートリアルの残りの部分では、VSCodeを使用します。

ターミナルに戻り、以下のコマンドを入力して、Cコードが存在するファイルを作成します。

`cd` # Takes us to our home directory,if not there already
`mkdir cprogram` # Creates a directory named cprogram 
`cd cprogram` #navigates us into the cprogram directory we just created
`touch hello.c` #creates a file named hello
`code .` #opens VSCODE  in the current directory

これで、プレーンテキストファイルを作成しましたhello.c。このファイルには、C言語で記述されたコードが含まれています。つまり、Cプログラムになります。.cこれは、慣例であるファイル拡張子によって示されます。

その中には、「helloworld」を画面に出力するプログラムのような非常に基本的なプログラムから始めて、好きなCプログラムを書くことができます。

こんにちは世界

コードが何をするかを確認するには、今書いたプログラムを実行する必要があります。ただし、実行する前に、ターミナルでいくつかのコマンドを入力してコンパイルする必要があります。

コンピューターでコマンドラインを引き続き使用することも、VSCodeの統合ターミナルを使用することもできます(control ~新しいターミナルウィンドウが開くと同時にキーを押し続けることにより)。

これまでのところ、左側のパネルで、cprogramディレクトリにhello.cCコードを含むファイルが1つしかないことがわかります。

「Cコードのコンパイル」という用語は、1つのステップで発生するだけではありません。また、自動的に発生するいくつかの小さなアクションも含まれます。

覚えておくと、コンパイルについて言及するときは、通常、コンパイラがソースコード(Cで記述した、英語のような構文を持つコード)を入力として受け取り、それを変換してマシンコードステートメントを出力として生成することを意味します。

このマシンコードは、ソースコードの命令に直接対応していますが、CPUが理解できるように記述されているため、命令を実行して実行できます。

Cソースコードがバイナリコードに変換される方法

これは一般的な考え方ですが、その間に発生する4つの小さなステップがあります。コードをコンパイルするとき、実際には前処理、コンパイル、アセンブル、およびリンクを行っています。

gcc hello.cこれらの手順は、それぞれコンパイラの名前とソースコードファイルであるコマンドをターミナルに入力すると発生し始めます。

必要に応じて、次のようなより具体的なコマンドを入力して、そのコマンドを変更およびカスタマイズできますgcc -o hello hello.c

  • -o'このファイルを出力する'の略です
  • helloは、作成する出力する実行可能プログラムファイルに自分で指定する名前です。
  • hello.cコンパイラが入力として受け取るファイルgccです(これは、ソースコードが存在し、コンパイルするファイルです)。

Cでの前処理

コンパイラの一部である別のプログラムが、この最初のステップであるプリプロセッサを実行します。プリプロセッサは多くのことを実行します。たとえば、プリプロセッサは、ソースコードをスキャンして特別なステートメントを探し、。で始まる行を検索するときに、「検索および置換ツール」として機能します#

#のようなで始まる行#includeは、プリプロセッサディレクティブと呼ばれます。aで始まる行#は、プリプロセッサに何かを実行する必要があることを示します。特に、その行を他の行に自動的に置き換える必要があることを示しています。このプロセスはわかりませんが、舞台裏で起こっています。

たとえば、プリプロセッサが以前のプログラムでその行#include <stdio.h>を見つけた場合、文字通り、プリプロセッサに、そのステートメントの代わりに、そのヘッダーファイル(外部ライブラリ)からのすべてのコードをコピーして貼り付けるように指示します。私たち自身のソースコード。したがって、この行はファイルの実際の内容に置き換えられます。hello world#includestdio.h#include <stdio.h>stdio.h

ライブラリ内<stdio.h>には、関数プロトタイプと定義またはヒントがあります。このようにして、すべての関数が定義され、コンピューターがコンパイル時にそれらを認識し、プログラムで使用できるようになります。

たとえば、関数はinsideprintf();として定義されています。同じ手順が他のヘッダーファイル、つまり拡張子が付いたファイルでも発生します。int printf(const char *format,…);<stdio.h>.h

前処理ステップ中に、コード内のコメントも削除され、マクロが展開されてそれらの値に置き換えられます。マクロは、名前が付けられたコードのフラグメントです。

この段階で、コードにエラーがない場合は、ターミナルに出力がないはずです。これは良い兆候です。

.i出力は表示されませんが、 Cソースコードのままの拡張子で新しいファイルが作成されています。このファイルには前処理からの出力が含まれているため、前処理されたソースコードと呼ばれます。この場合、新しいファイル、hello.iが生成されますが、エディターには表示されません。

コマンドを実行するとgcc -E hello.c

スクリーンショット-2021-03-02-at-8.29.46-P​​M

このファイルのすべての内容(たくさんあります)を見ることができ、エンディングは次のようになります。

スクリーンショット-2021-03-02-at-8.30.05-PM

コードの正確さに誤りがある場合、または言語のセマンティクスに従わない場合は、いくつかのエラーが表示され、コンパイルが終了します。間違いを訂正し、最初からプロセスを開始する必要があります。

Cでのコンパイル

前処理されたCソースコードを生成する前処理ステップの後、次にコードをコンパイルする必要があります。これには、まだソースコードであるコードを取得し、それを別の中間形式に変更することが含まれます。このステップではコンパイラーを使用します。

復習すると、コンパイラは、ソースコードを入力として受け取り、それをコンピュータの母国語に近いものに変換するプログラムです。

コンパイルとは、ソースコードをオブジェクトコード(マシンコード)に変換するプロセス全体、またはコンパイルプロセス全体の特定のステップのいずれかを意味します。

ここで説明しているステップは、コンパイル時に、前処理されたCソースコードプログラムのすべてのステートメントが、よりコンピューターに適した言語に変換されるときです。この言語は、コンピューターが実際に直接理解できるバイナリに近いものです。

この中間言語はアセンブリコードであり、CPUを制御し、CPUを操作して特定のタスクを実行し、コンピューターのメモリにアクセスするために使用される低レベルのプログラミング言語です。履歴セクションのアセンブリコードを覚えていますか?

すべてのCPU(コンピューターの頭脳)には、独自の一連の命令があります。アセンブリコードは、CPUが実行および実行するこれらの命令および低レベルの操作に直接相関する特定のステートメントおよびコマンドを使用します。

したがって、コンパイルプロセスのこのステップでは、ファイル内の前処理されたCソースコード内の各ステートメントがhello.i、コンパイラによって下位レベルのアセンブリ言語の同等のステートメントに変換されます。

このアクションの出力は、アセンブリの命令を含む.shello.s舞台裏で)で終わるファイルを作成します。

コマンドを入力することで、コンパイラが作成しgcc -S hello.cたファイルの内容とやや理解しにくいアセンブリコマンドを表示できます(ただし、単独でhello.s入力した場合は表示されませんでした)。gcc hello.c

よく見ると、Cソースコードで使用されているおなじみのキーワードとステートメントがいくつかmainありprintfます。

スクリーンショット-2021-03-12-at-11.15.27-AM

Cでの組み立て

アセンブルとは、hello.sアセンブリコードステートメントを含むファイルを入力として受け取り、コンパイルプロセスで自動的に実行される別のプログラムを使用して、マシンコード命令にアセンブルすることを意味します。これは、実際の0と1、またはバイナリ形式のステートメントを出力として持つことを意味します。

このステップも舞台裏で行われ、ソースコードの命令が翻訳される最終的な言語になります。そして今、コンピュータはついにそれらの指示を理解することができます。

Cソースコードで記述した各コマンドは、アセンブリ言語ステートメントに変換され、最終的に同等のバイナリ命令に変換されました。これはすべて、コマンドだけで発生しましたgcc。ふぅ!

私たちが書いたコードは、特定のコンピューターのCPUが理解できるオブジェクトコードと呼ばれるようになりました。言語は私たち人間には理解できません。

人々は以前は機械語でコーディングしていましたが、それは非常に退屈なプロセスでした。マシンコード以外のシンボルであるシンボル(つまり、0と1以外のシンボル)は、理解するのが困難です。このような言語で直接コーディングすると、エラーが発生しやすくなります。

この段階で、.o(オブジェクト用の)拡張子を持つ別のファイルが作成されます。したがって、この場合は。になりますhello.o

コマンドを使用して、マシンレベルの命令を含むオブジェクトファイルの実際の内容を確認できますgcc -c hello.c。これを行うと、人間が読めない次の内容が表示されhello.oます。

スクリーンショット-2021-03-14-at-10.22.15-PM

Cでのリンク

a.out上の画像では、ディレクトリ内のファイルに気付いたかもしれません。

これは、コンパイラコマンドとファイル名(この場合)を入力したときに作成されるデフォルトのステップとファイルですgcc hello.c

前述のコマンドを使用した場合、の代わりにgcc -o hello hello.cカスタムの名前付きhello実行可能プログラムが表示されa.outます。

アセンブリ出力a.out略です。ターミナルに入力してディレクトリ内のファイルを一覧表示すると、他のファイルとは異なって見えることがわかります。lsa.out

スクリーンショット-2021-03-19-at-10.37.05-PM

リンクは、コンパイルプロセスの最終段階であり、最終的なバイナリファイルhello.oがプロジェクト内の他のすべてのオブジェクトコードにリンクされます。

したがって、Cソースコードを含む他のファイル(すでに処理およびコンパイルされたCライブラリを実装するプログラムに含まれるファイルや、たとえば、filename.c他に名前を付けて作成した別のファイルなどhello.c)がある場合、オブジェクトファイルは次のfilename.oようになります。hello.oおよび他のオブジェクトコードと組み合わせて、それらをすべてリンクします。

これにより、プログラムを表すマシンコードa.outまたはを組み合わせた1つの大きな実行可能ファイルが形成されます。hello

ようやくコンパイルが完了したので、プログラムは最終的な形になっています。これで、。と入力して、マシン上でファイルを実行および実行できます./a.out。これは、「現在のディレクトリにあるa.outファイルを実行する」ことを意味します。これは、現在./のフォルダを表しているためです。次に、ターミナルにプログラムの出力が表示されます。

スクリーンショット-2021-03-19-at-10.18.20-PM

ソースコードファイルに変更を加えるときはいつでも、コードを再度実行したときに変更を確認するために、最初からコンパイルのプロセスを繰り返す必要があります。

CでHelloWorldを作成する方法

プログラムは非常に単純なhello worldものですが、新しいプログラミング言語でコーディングする方法を最初に学び始めたときにテストメッセージとしても機能する伝統です。

「HelloWorld」プログラムを正常に実行すると、システムが正しく構成されていることがわかります。

Hello_World_Brian_Kernighan_1978-1

1974年のベル研究所の内部覚書「ProgramminginC:A Tutorial」に基づいて、Artsy's AlgorythmAuctionのBrianKernighanによって考案された「Helloworld」には、最初の既知のバージョンが含まれています。それは人気のある1978年の本、TheCProgrammingLanguageに転載されました。ウィキペディアからの画像と説明のソース

「helloworld」プログラムには、言語の基本的な構文が含まれており、それをより小さな部分に分割できます。

#include<stdio.h>

int main(void)
{
    // print hello world to the screen
	printf("Hello world\n");
}

Cのヘッダーファイル

ヘッダーファイルは外部ライブラリです。これは、他の開発者が使用できるように、一部の開発者によってすでに作成されたコードのセットであることを意味します。

これらは、C言語のコアには含まれていない機能を提供します。コードにヘッダーファイルを追加することで、プログラムで使用できる追加機能を取得できます。

include <stdio.h>拡張子の終わりのようなヘッダーファイル.h。特に、のようなヘッダーファイルstdio.hはすでにコンパイラに組み込まれています。

この行include <stdio.h>は、ライブラリファイルに事前に記述された関数の命令でありstdio.h、コンピューターにアクセスしてプログラムに含めるように指示します。

stdio.h機能を提供standard input and standard outputします。つまり、ユーザーからの入力と出力を取得できるようになります。したがって、のような入出力関数を使用できるようになりprintfます。

stdio.hコードの先頭にファイルを含めないと、コンピューターはprintf関数が何であるかを理解できません。

Cのメインプログラム

コードは次のとおりです。

int main(void)
{
}

これは、Cプログラムの主な起動機能です。中括弧({})は、プログラムに含まれるべきすべてのコードをラップする本文です。

この行は、すべてのCプログラムの定型文および開始点として機能します。これにより、コンピューターは、プログラムを実行するときにコードの読み取りを開始する場所を知ることができます。

Cでのコメント

後に何を記述しても//、コードの実行方法には影響せず、コンピューターはコンパイルおよび実行時にコードを考慮しません。

これらの2行は、コメントを追加していることを示しています。コメントは、私たちの将来の自分自身と同僚へのメモです。コメントは、特定のコード行が何をするのか、またはそもそもなぜそのコードを書いたのかを覚えて思い出させるのに役立ちます。また、数か月後の翌日に戻ってきたときに、そのコードの目的が正確に何であるかを思い出させてくれます。

Cでコンソールに出力または印刷する

printf("Hello world/n");「Helloworld」というフレーズをコンソールに出力します。printf何かを言いたいときや、画面に出力を見たいときに使用します。""出力する文字は、二重引用符と括弧で囲む必要があります()

/nエスケープ文字です。つまり、改行を作成し、カーソルが表示されたら次の行に移動するように指示します。

;、文の終わりとそのコード行の終わりを示します。

Cの変数

Cで変数を定義する方法は次のとおりです。

プログラムの実行中に複数の値をとる可能性のあるデータ項目。

簡単に言うと、変数は名前付きボックスと考えることができます。内容が異なる可能性のあるさまざまな情報を保持するための保管場所および場所として機能するボックス。

各ボックスには、一意の識別子である外側に貼られたラベルのように機能する一意の名前があり、情報/コンテンツは内側にあります。内容は変数の値です。

変数は、いくつかの有用なデータを保持し、値を指し示します。これらは、リテラルデータへの参照または抽象化として機能します。そのデータはコンピュータのメモリに保存され、一定のスペースを占有します。そこにあるので、後で取得して、必要なときにプログラムで使用できます。

名前が示すように、どの変数が指すかは変わる可能性があります。プログラムの存続期間中に情報が変化するにつれて、時間の経過とともにさまざまな値をとることができます。

Cでの変数代入

変数に名前を付けるプロセスは、割り当てと呼ばれます。右側にある特定の値を、左側にある特定の変数名に設定します。=これを行うには、または代入演算子を使用します。

前述したように、変数の値を変更できるため、変数を割り当てたり、再割り当てしたりできます。値を再割り当てすると、新しい値は変数名を指します。したがって、値は新しい値にすることができますが、変数名は同じままです。

Cで変数を宣言するか初期化するか

Cプログラミング言語は、他の多くの最新のプログラミング言語とは異なり、静的に型付けされた言語です。

静的に型付けされた言語では、変数が特定のデータ型であることを明示的に宣言する必要があります。このようにして、コンパイラは、コンパイル時に、変数が設定および要求されたアクションを実行できるかどうかを認識します。

動的型付けされた言語では、変数は、そのデータ型を明示的に定義する必要なしに、異なるデータ型間で変更できます。

したがって、C言語で新しい変数を宣言するときは、それがどのタイプであり、その値が保持するデータのタイプを定義および指定する必要があります。

変数の型は、変数が保持する値の型です。これにより、プログラムと後でコンパイラは、格納している情報の種類を知ることができます。

変数を宣言するには、データ型を指定し、変数に名前を付けます。オプションの手順は、初期値を設定することです。ステートメントを終了する最後のセミコロンを忘れないでください!

#include <stdio.h>
 
int main(void)
{
  int n = 27;
  // int is the data type
  // n is the name 
  // n is capable of holding integer values
  // positive/negative whole numbers or 0
  // = is the assignment operator
  // 27 is the value
}

変数の初期化と宣言の違いは何ですか?

要約すれば:

int n; // declaration, create a variable called n capable of holding integer values
int n = 27; // initialisation, creating a variable called n and assigning a value, storing a number in that variable

int n;変数を宣言しています。宣言とは、変数の名前を定義し、その型を指定することを意味します。

まだ変数の値を指定する必要はありません。変数を宣言すると、コンピューターに変数が存在するように指示され、そのためにメモリ内にいくらかのスペースを割り当てる必要があるため、これで十分です。値は後で保存でき、保存されます。

後で変数に値を割り当てる場合、データ型を再度指定する必要はありません。一度に複数の変数を宣言することもできます。

int name, age;

変数を宣言して一度に値を割り当てる場合、これは変数の初期化と呼ばれます。

int n = 27;変数を初期化しています。これは、後で変更できる初期値を割り当てることを指します。

新しい値が同じデータ型である場合、データ型を含める必要はなく、新しい値だけを含める必要があります。データ型が異なる場合、エラーが発生します。

#include<stdio.h>

int main(void)
{
  int age = 27;
  age = 37;
  // the new value of age is 37
}

Cでの変数の命名規則

  • 変数名は、たとえば文字またはアンダースコアで始まるage必要があり_age、有効です。
  • 変数名には、文字(大文字または小文字)、数字、またはアンダースコアを含めることができます。
  • アンダースコア以外の特別な記号はありません。
  • 変数名では大文字と小文字が区別されます。たとえば、ageとは異なりAgeます。

Cの変数のスコープ

変数のスコープとは、変数を参照およびアクセスできる場所を指します。それは本質的に変数が存在し、有効であり、プログラムの残りの部分にどれほど見えるかということです。

ローカルスコープ

たとえば特定の関数のように、変数が中括弧のセット内で宣言されている場合{}、それがそのスコープになり、プログラムの残りの部分で変数にアクセスして中括弧の外で使用することはできません。プログラムの残りの部分は、それが存在することを知りません。

したがって、変数のスコープと使用法が非常に制限されており、エラーが発生する可能性があるため、変数をそのように宣言することはお勧めできません。このスコープはスコープと呼ばれlocalます。

グローバルスコープ

変数が関数の外部globalで宣言されている場合、それらにはスコープがあります。グローバルスコープを持つということは、それらがプログラム全体で表示され、どこからでもアクセスできることを意味します。

ただし、それらを追跡するのは難しい場合があることに注意してください。また、途中で変更を加えると、プログラムのどの部分や場所でも発生する可能性があるため、混乱を招く可能性があります。

Cのデータ型

データ型は、Cプログラムで情報を表現および保存できる形式を指定します。彼らは、その情報がどのように使用され、どのような操作を実行できるかを教えてくれます。

Cの各変数は、それが表すデータ型を宣言する必要があるため、データ型によって、変数が保持できるデータの種類も決まります。

この言語には6つのデータ型が組み込まれています。ただし、異なるタイプ間で変換できるため、強く型付けされていません。

データ型ごとに異なるメモリ割り当てが必要であり、データ型ごとに値を格納できる範囲を変えることができます。

タイプ名の前にキーワードを追加すると、タイプが変更および変更されます。これらのキーワードは、unsignedまたはsignedのいずれかです。

符号なしキーワードは、タイプが正で負ではないことを意味するため、数値の範囲は0から始まります。符号付きキーワードを使用すると、数値を負または正にすることができます。

これらのデータ型をさらに詳しく見てみましょう。

Cのcharデータ型

Cの最も基本的なデータ型はですchar。これを使用して、「a」、「Z」、「!」などのASCIIチャートの文字などの単一文字を格納します(単一文字を囲む単一引用符の使用方法に注意してください。二重引用符は使用できません。この場合。)

charまた、[-128から127]の範囲の数値を格納でき、どちらの場合も1バイトのメモリを使用します。

unsigned charは、[0-255]からさまざまな数値をとることができます。

Cのintデータ型

intは整数、整数であり、正または負の値または0を保持できますが、小数はありません。

特定のビット数までの値です。を宣言するintと、コンピュータはそれに4バイトのメモリを割り当てます。より具体的には、少なくとも2バイトを使用しますが、通常は4です。4バイトのメモリは、32ビットを割り当てることを意味します(1バイト= 8ビットであるため)。したがって、intには232の可能な値、つまり40億を超える可能な整数があります。

範囲は-231から231-1で、具体的には[-2,147,483,648から2,147,483,647]です。

  • unsigned intのサイズはint(4バイト)と同じですが、可能な値の範囲に負の数は含まれていません。したがって、範囲は0〜232-1、より具体的には[0〜4,294,969,295]です。
  • 短いintは、intよりも小さい値を持ち、2バイトのメモリを割り当てます。[-32,768〜32,767]の範囲の数値を使用できます
  • unsigned short intは、再び2バイトのメモリを使用し、[0〜65,535]の範囲の数値を持ちます。
  • long intは、より大きな数を使用する必要がある場合に使用します。少なくとも4バイトのメモリを使用しますが、通常は[-2,147,483,648から2,147,483,647]の値を持つ8バイトです。
  • unsigned long intには、[ 0〜4,294,967,295 ]の範囲のメモリが少なくとも4バイトあります。
  • long long intは、intやlong intと比較して、より多くのビットを数えることができる整数です。それらは4ではなく8バイトを使用するため、64ビットを使用します。これにより、-263から263-1の範囲が可能になり、[-9,223,372,036,854,775,808から9,223,372,036,854,775,807]の数値が可能になります。
  • unsigned long longは8バイトを使用し、数値の範囲は[0〜18,446,744,073,709,551,615]です。

Cのfloatデータ型

浮動小数点数は、単精度の小数(実数とも呼ばれる)の数値である浮動小数点値です。4バイトのメモリを割り当てます。

Cのdoubleデータ型

doubleは、floatよりも大きな値を持つ浮動小数点値です。浮動小数点数と比較して、より多くのメモリ(8バイト)を保持でき、倍精度です。

  • long doubleは、floatおよびdoubleと比較して最大のサイズであり、少なくとも10バイトのメモリを保持しますが、最大12バイトまたは16バイトを保持することもできます。

そして最後に、void型は本質的にも価値がないかまったくないことを意味します。

Cでのフォーマットコード

Cでの入力と出力には、フォーマットコードまたはフォーマット指定子が使用されます。

これらは、変数を使用して入力として受け取るデータのタイプと、printf()関数を使用するときに出力として生成するデータのタイプをコンパイラーに通知する方法です。finはformattedprintf()略です。

これらはフォーマットコードのプレースホルダーとして機能し、変数の代わりになります。標準出力の値(つまり、出力したいもの)がまだわからない場合は、コンパイラーに事前にタイプを通知します。

使用する構文は次のとおりです% format specifier for data type

#include<stdio.h>
int main(void)
{
	int age = 27;
	printf("My age is %i/n", age)
	// prints 27
// age is the variable we want to use 
// %i is the format specifier,a placeholder for an integer value
// we separate each argument with a comma
// in the output %i  is replaced with the value of age
}

前に説明したデータ型ごとに異なる形式指定子があります。それらのいくつかを次に示します。

フォーマット指定子データ・タイプ
%cchar
%cunsigned char
%iまた&dint
%uunsigned int
%hiまた%hd短い整数
%huunsigned short int
%liまた%ldlong int
%luunsigned long int
%lliまた%lldlong long int
%lluunsigned long long int
%f浮く
%lfダブル
%Lfロングダブル

Cの演算子

Cの算術演算子

算術演算子は、数値に対して数学関数を実行する数学演算子です。演算には、加算、減算、乗算、除算が含まれます。

最も一般的に使用される演算子は次のとおりです。

  • +追加のために
  • -減算用
  • *乗算用
  • /除算用
  • %モジュロ除算の場合(除算の余りを計算する)

Cの代入演算子

代入演算子、=は、変数に値を代入します。値を変数に「入れます」。

つまり、の右側にあるものはすべて=、の左側にある変数の値に設定されます=

値を変更して変数を更新するための特定の代入演算子があります。

Cでは、変数の値を更新するさまざまな方法があります。たとえば、変数をインクリメントする場合、13つの方法があります。

最初に言及する価値があるのは、インクリメントとは、右側にある値に関係なく、変数の既存の値を取得してそれに追加1することを意味します。その後、新しい値が変数に保存され、自動的に更新されます。

xインクリメントまたは更新する最も簡単な方法は、初期値が、である変数を呼び出す5ことです。

x=5

1変数に追加するにはx、これを実行します。x = x + 1これはを意味しx = 5 + 1ます。

の新しい値はx6になりx=6ました。

変数をインクリメントする特別な構文を使用して、この操作の省略形があります。

書く代わりに、書くx = x +1ことができますx += 1

さらに短い方法は、のように見えるインクリメント演算子を使用することです。variable_name ++したがって、この場合はx++

同じことが、変数を1ずつ減らす、つまりデクリメントする場合にも当てはまります。

そのための3つの方法は次のとおりです。

x = x-1、、(デクリメント演算子を使用)それぞれx -= 1x --

これらは、Cで変数をインクリメントおよびデクリメントする方法です1。変数の値を取得し、その値を他の数値で加算、減算、乗算、除算し、その演算の結果を新しいものとして設定することで、変数を更新できます。価値。これらの操作は+=、それぞれ-=、、、、*=およびになり/=ます。

したがってx = x * 5、または省略形x *= 5は変数の値を取得し、xそれを乗算して5に格納しxます。

Cの論理演算子

Cで決定を行うために論理演算子を使用します。操作の結果は、trueまたはfalseのいずれかになります。

論理AND演算子、があり&&ます。条件が真になるには、の左側と右側の両方のオペランド&&が真である必要があります。

OR論理演算子、もあり||ます。条件が真になるには、の右側と左側のオペランドの少なくとも1つまたは両方||が真である必要があります。

最後に、論理がありますNOT。これにより、オペランドの値が反転します。オペランドがtrueの場合、演算子はNOT条件をfalseにし、その逆も同様です。

Cの比較演算子

比較演算子は次のとおりです。

  • 大なり記号>
  • 以上>=
  • 未満<
  • 以下=<

等式比較演算子、もあり==ます。=これを代入演算子と混同しないでください。

を使用し==て2つの値を比較し、それらが等しいかどうかをテストします。この演算子は、「これら2つは等しいですか?」という質問=をしますが、変数に値を割り当てます。

等式比較演算子を使用して上記の質問をする場合、コンピュータプログラミングのコンテキストでは、trueまたはfalse、またはのいずれかである可能性のある戻り値が常にあります。Boolean value

!=最後に、 2つの値が等しくないかどうかをテストするために使用する不等式演算子があります。

Cの関数

関数は動詞、つまり小さなアクションです。彼らは何かをします。それらは特定の特定のタスクを実行します。

それらは、何度も使用されることを意図した動作の一部をカプセル化します。関数の目的は、その動作をどこかに1回だけ書き出すことで、プログラム全体のさまざまな時間にさまざまな場所で、必要なときにいつでも再利用できるようにすることです。これにより、コードがよりシンプルになり、整理されやすくなります。

関数は、1つのタスクを実行し、特定の目的を果たし、再利用するために存在します。そして、彼らはインプットを取り入れ、アウトプットを生み出すことができます。

Cの関数の引数

関数が受け取る入力は引数と呼ばれます。関数は1つ以上の引数を持つことができます。

Cプログラミング言語の一般的な関数はですprintf();。これにより、画面に何かが印刷されます。それは何かを言うために使用される関数です。

括弧()は関数への入力であり、引数が入ります。つまり、実際に言いたいことを画面に出力します。括弧の間にあるものが印刷されます。

printf("Hello world!");Hello world!は関数への入力printfです。ここでは、という関数を呼び出しprintfており、文字列である引数を指定しています。これは文字通り、「Hello world!'画面に。

Cでの関数出力

関数出力には次の2つのタイプがあります。

まず、出力は視覚的なもの、即時の視覚効果、画面にすばやく印刷されるものにすることができます。

エフェクト後の出力では、これ以上何もできません。の場合と同様にprintf("Hello world!");、出力は文字列「Helloworld!」です。画面に印刷され、それだけです。printf戻り値がないため、その文字列を他の方法で使用することはできません。

これらのタイプの関数は副作用として知られています。つまり、値を返さずにすぐに観察できる効果があります。

また、のような関数printf関数呼び出しであり、stdioライブラリではとして定義されint printf(const char *format,...);ます。

次に、出力は再利用可能であり、戻り値があります。戻り値は、プログラマーに返され、後で使用するために変数に格納される値です。

このような場合、すぐに効果はありません。画面には何も印刷されません。代わりに、出力は私たちに返され、情報として保存され、変数に保存されます。

Cでメソッドを定義する方法

関数を定義するとき、最初の行である減速行に必要なものが3つあります。

  1. リターンタイプ

これは最初に使用されるキーワードであり、関数の開始方法は戻り値を示します。

たとえば、次のような関数の場合void say_something(void)、最初のvoidは、関数に戻り値がないことを意味します。

別の関数を使用した別の例ではint main(void)、戻りデータ型(この場合は。)を指定して定義しますint。関数の出力はintデータ型になり、関数が呼び出された場所に返されます。

  1. 関数名

名前は任意の名前にすることができますが、メソッドに意図した内容に基づいて名前を付けるのがベストプラクティスです。

  1. 引数なしまたは1つ以上の引数

これらは関数の入力であり、それらの入力のデータ型です。

void say_something(void)void括弧内は引数のキーワードであり、「nothing」のプレースホルダーです。これは、入力がないことを意味します。このような場合、引数はパラメータとも呼ばれます。

voidパラメータは基本的に、キーワードのように括弧内にある関数で宣言された変数です。これらは、関数の入力データである引数にアクセスするためのプレースホルダーとして機能します。

パラメータは、メソッドに渡される値を参照します。これは、後で関数を呼び出すときに、実際の値、つまり関数への引数を渡すことを意味します。

Cで関数を呼び出す方法

次のような関数を呼び出すことができます。

void say_hi(void)
{
	printf("hello");
}

関数の名前を記述し、その後に括弧で囲まれた引数と。のようなセミコロンを続けますsay_hi();。このsay_hi関数は入力を受け取らず、戻り値もありません。呼び出されると、「hello」が画面に出力されます。

次のような別の関数:

int square(int n)
{
	return n * n
}

前の例と同じ方法で呼び出されます。この場合、square関数は入力を受け取り、戻り値を持ちます(どちらもintsです)。受け取る入力は、関数が呼び出されnたときにを返す、と呼ばれるパラメーターです。int

この単語returnは、何が返されるか、入力nにそれ自体を掛けたものを指定します。

たとえば、関数が呼び出されるとsquare(3);nは、のように、関数に渡されたパラメータを指す変数として機能します3。設定したようなものですn = 3。返される値はです9

関数は再利用することを目的としているため、数値を二乗したいときはいつでも使用できます。

#include <stdio.h>

  int square(int x)
  {
    return x * x;
  }
 
  int main(void)
  {
   printf("%i\n", square(2));
   printf("%i\n", square(4));
   printf("%i\n", square(8));
 }

Cでブール式を使用する方法

ブール式は、trueまたはfalseの2つの値のいずれかに評価される式です。彼らの名前は、数学者、哲学者、論理学者のジョージブールにちなんで付けられました。

スクリーンショット-2021-06-18-at-1.58.33-PM

ジョージブール画像ソースウィキメディアコモンズ

ブール式を使用して2つの値を比較します。これらは、制御フローで特に役立ちます。

ゼロ以外のすべての値はtrueであり、0ですfalse

&&ブール式は、この記事で前述した(and)、||(or)、!(not)などのさまざまな論理演算子を使用して組み合わせることができます。

値と演算子の組み合わせが異なると、出力結果も異なります。これは、真理値表1で表すことができます。これは、または0または同等のtrueまたはに結果をもたらす論理方程式を表すために使用される数表falseです。

(and)演算子を使用して2つのブール値を比較する場合、論理&&積がtrueになるには、両方の値がtrueに等しくなければなりません。

たとえば、誰かが「ピザとサラダが欲しいですか?」と尋ねた場合、表現が真になる唯一の方法は、ピザとサラダの両方が欲しいということです(したがって、私たちの答えは両方に「はい」です)。それらの1つに対する答えが真でない場合、式全体が偽になります。

&&の真理値表

値A値B結果
真実間違い間違い
間違い真実間違い
間違い間違い間違い
真実真実真実

とは異なり&&||演算子では、一方または両方の値がtrueの場合にアクションを実行できます。したがって、この演算子は排他的ではありません。式がtrueと評価されるには、比較のいずれか1つがtrueであるか、両方がtrueである必要があります。

これはコンピューティングに非常に独特です。前に使用した質問の例で、ANDの代わりにORに変更した場合、「ピザとサラダのどちらがいいですか?」というステートメントがあります。両方が欲しいという意味ではありません。どちらか一方が必要ですが、必ずしも両方が一緒である必要はありません。

||の真理値表

値A値B結果
真実間違い真実
間違い真実真実
間違い間違い間違い
真実真実真実

最後に、 (not)演算子は否定に使用されます。!つまり、にtrueなりfalseます。falsetrue

!true is false
!false is true

Cで条件文を使用する方法

条件文は、行われた比較の結果に基づいて特定のアクションを実行します。特定の条件が真である場合に1つのことを実行し、その特定の条件が偽であることが判明した場合に別のことを実行する動作は、制御フローと呼ばれます。

結果や特定のユーザー入力によっては、プログラムの特定の部分が実行されない場合があります。ユーザーは、プログラムの存続期間中に現れる道路のさまざまな分岐点に応じて、さまざまな経路をたどることができます。

条件文を含むプログラムは、主にifブロックを使用します。ifブロックはboolean expressionstrueまたはfalseのみを使用し、結果の値に応じて決定を下します。if中括弧{}、、、および後続のコードのインデンドを使用して、ブロックステートメントを示します。

#include <stdio.h>
int main(void)
{
int x = 2;
int y = 3;

if (x < y)
 
// x < y is a boolean expression,it can only be true or false.
// If whatever is in the parentheses is true 
//-in this case is x is actually less than y-
//run the code that follows
{
	printf("x is less than y"); 

// Because x < y is true that statement will be printed
}

}

ifプログラムがどんどん大きくなるにつれて、ステートメント自体はそれほど役に立ちません。したがって、その場合、ifステートメントにはステートメントが付随しelseます。

これらは、「ifこの条件が真である場合は、次のelseことを実行し、代わりにこれを実行する」ことを意味します。elseキーワードは、if条件がfalseであるために実行されない場合の解決策です。

int main(void)
{ 
int  x = 1;
int  y = 2;

if ( x > y)
{
  printf("x is larger than y");
}

else 

{  
  printf("x is less than y");
// Because  x > y is false ,
// this block of code will be executed
// resulting in printing the statement of the else branch
}

}

2つ以上のオプションから選択し、ステートメントとアクションのバリエーションを増やしたい場合は、else if条件を導入できます。

これは、'この条件が真の場合、これを実行することを意味します。そうでない場合は、代わりにこのことを行ってください。ただし、上記のいずれにも当てはまらない場合は、代わりに最後にこれを実行してください。

#include <stdio.h>
int main(void)
{
  int x = 2;
  int y = 2;

  if(x < y)
   // if this condition is true run this block
  {
    printf("x is less than y");
  }
 else if(x > y)
  / / if the above statement was true run this block instead
 { 
    printf("x is greater than y");
 } 
 else  
   // if this block of code runs 
   //it runs because x < y was false 
  //and so was x > y 
  //so it means x == y
 {
    printf("x is equal to y");
 }
}

Cでループを使用する方法

ループとは、条件が満たされるまで、特定の回数、何度も繰り返される、孤立した動作または特定の一連の命令です。それは同じアクション、同じコードであり、何度も繰り返されます。

Cでループしている間

コードを実行する前に、whileループは条件をチェックする必要があります。それが満たされると、コードが実行されます。そうでない場合、コードは何のアクションも実行しません。したがって、条件が満たされない場合、コードが少なくとも1回実行されることは保証されません。

whileループにはさまざまな種類があります。それらの1つは無限ループです。

#include <stdio.h> 
int main(void)
{

	while(true)
	{
		printf("Hello world");
	}
}

この場合while、キーワードは必須のブール式とともに使用されtrueます(常に保持されますtrue)。

中括弧内にコード行を出力した後、コードを再度実行する必要があるかどうかを継続的にチェックします。答えは常にyes(チェックする必要のある条件は毎回常に真であるため)であるため、コードを何度も何度も実行します。

この例では、プログラムを停止してエンドレスループから脱出する唯一の方法はCtrl + C、ターミナルで実行することです。

条件がの場合、false中括弧内でコードが実行されることはありません。

もう1つのループは、何かを特定の回数繰り返すループです。

#include <stdio.h>
int main(void)
{
	int i = 0;

	while(i < 10)
	{
	//while i is less than 10 run this code
		printf("Hello world");
	// and then increment
		i++
	//check the condition everytime
  //once the code in the curly braces is run, check if i is still less than 10.
  // If so run code + increment again and check again
	//loop will eventually end when i reaches 10
	}
}

Do-whileループ

#include <stdio.h>
 
int main(void)
 {
   int i = 10;
   do {
      printf("the value of i: %i\n", i);
      i++;
   }
  while( i < 20 );
}

whileループと比較して、ループは少なくとも1回実行され、中括弧内のコードを少なくとも1回do- while実行することが保証されています。

最初に何かを実行し、次に条件をチェックします。これは、何かを少なくとも1回、ただし不明な回数だけ繰り返したい場合に役立ちます。

この例では、コードは少なくとも1回実行され、ステートメントは少なくとも1回出力されます。次に、値がインクリメントされます。次に、値が20未満かどうかを確認し、20未満の場合は、コードを再実行します。毎回インクリメントされる値が20以上になると、コードの実行が停止します。

Cの学習を継続するためのリソース

これで、Cプログラミング言語へのこの導入は終わりです。最後までやり遂げるのにいい仕事です。

これにより、言語の「理由」と「方法」、およびCで基本的なプログラムを書き始めるために知っておく必要のある基礎についての洞察が得られたことを願っています。

さらに深く掘り下げ、いくつかのプロジェクトを構築し、Cを使用して問題を解決したい場合は、CS50コンピュータサイエンス入門を試してみてください。

本を読んで学ぶことを楽しむなら、私は以下のものをお勧めします:

ビデオを見たり、コーディングしたりして学習を楽しんでいる場合は、freeCodeCampのYouTubeチャンネルにある初心者向けのCプログラミングチュートリアルのビデオをご覧ください。

読んでくれてありがとう、そして幸せなコーディング! 

このストーリーは、もともとhttps://www.freecodecamp.org/news/what-is-the-c-programming-language-beginner-tutorial/で公開されました。

 #csharp #cprogramming 

Cプログラミング言語とは何ですか?初心者のためのチュートリアル

saba techatom

1652439059

How to make pattern programs in C OR C++?

Most of the pattern programs written in C or C++ are the same, but different in syntax. This is done so that you can have a pattern program, which can be reused and saved in a library. By doing so, you don't have to type the bunch of code over and over again again, and it is a lot faster than writing a new program each time.

Read this article, as they have shown the most asked pattern programs in C.

#c #cpluplus #program #programs #cprogramming 

How to make pattern programs in C OR C++?
Emilie  Okumu

Emilie Okumu

1651546800

Klib | A Standalone and Lightweight C Library

Klib is a standalone and lightweight C library distributed under MIT/X11 license. Most components are independent of external libraries, except the standard C library, and independent of each other. To use a component of this library, you only need to copy a couple of files to your source code tree without worrying about library dependencies.

Klib strives for efficiency and a small memory footprint. Some components, such as khash.h, kbtree.h, ksort.h and kvec.h, are among the most efficient implementations of similar algorithms or data structures in all programming languages, in terms of both speed and memory use.

A new documentation is available here which includes most information in this README file.

Common components

Components for more specific use cases

Methodology

For the implementation of generic containers, klib extensively uses C macros. To use these data structures, we usually need to instantiate methods by expanding a long macro. This makes the source code look unusual or even ugly and adds difficulty to debugging. Unfortunately, for efficient generic programming in C that lacks template, using macros is the only solution. Only with macros, we can write a generic container which, once instantiated, compete with a type-specific container in efficiency. Some generic libraries in C, such as Glib, use the void* type to implement containers. These implementations are usually slower and use more memory than klib (see this benchmark).

To effectively use klib, it is important to understand how it achieves generic programming. We will use the hash table library as an example:

#include "khash.h"
KHASH_MAP_INIT_INT(m32, char)        // instantiate structs and methods
int main() {
    int ret, is_missing;
    khint_t k;
    khash_t(m32) *h = kh_init(m32);  // allocate a hash table
    k = kh_put(m32, h, 5, &ret);     // insert a key to the hash table
    if (!ret) kh_del(m32, h, k);
    kh_value(h, k) = 10;             // set the value
    k = kh_get(m32, h, 10);          // query the hash table
    is_missing = (k == kh_end(h));   // test if the key is present
    k = kh_get(m32, h, 5);
    kh_del(m32, h, k);               // remove a key-value pair
    for (k = kh_begin(h); k != kh_end(h); ++k)  // traverse
        if (kh_exist(h, k))          // test if a bucket contains data
			kh_value(h, k) = 1;
    kh_destroy(m32, h);              // deallocate the hash table
    return 0;
}

In this example, the second line instantiates a hash table with unsigned as the key type and char as the value type. m32 names such a type of hash table. All types and functions associated with this name are macros, which will be explained later. Macro kh_init() initiates a hash table and kh_destroy() frees it. kh_put() inserts a key and returns the iterator (or the position) in the hash table. kh_get() and kh_del() get a key and delete an element, respectively. Macro kh_exist() tests if an iterator (or a position) is filled with data.

An immediate question is this piece of code does not look like a valid C program (e.g. lacking semicolon, assignment to an apparent function call and apparent undefined m32 'variable'). To understand why the code is correct, let's go a bit further into the source code of khash.h, whose skeleton looks like:

#define KHASH_INIT(name, SCOPE, key_t, val_t, is_map, _hashf, _hasheq) \
  typedef struct { \
    int n_buckets, size, n_occupied, upper_bound; \
    unsigned *flags; \
    key_t *keys; \
    val_t *vals; \
  } kh_##name##_t; \
  SCOPE inline kh_##name##_t *init_##name() { \
    return (kh_##name##_t*)calloc(1, sizeof(kh_##name##_t)); \
  } \
  SCOPE inline int get_##name(kh_##name##_t *h, key_t k) \
  ... \
  SCOPE inline void destroy_##name(kh_##name##_t *h) { \
    if (h) { \
      free(h->keys); free(h->flags); free(h->vals); free(h); \
    } \
  }

#define _int_hf(key) (unsigned)(key)
#define _int_heq(a, b) (a == b)
#define khash_t(name) kh_##name##_t
#define kh_value(h, k) ((h)->vals[k])
#define kh_begin(h, k) 0
#define kh_end(h) ((h)->n_buckets)
#define kh_init(name) init_##name()
#define kh_get(name, h, k) get_##name(h, k)
#define kh_destroy(name, h) destroy_##name(h)
...
#define KHASH_MAP_INIT_INT(name, val_t) \
	KHASH_INIT(name, static, unsigned, val_t, is_map, _int_hf, _int_heq)

KHASH_INIT() is a huge macro defining all the structs and methods. When this macro is called, all the code inside it will be inserted by the C preprocess to the place where it is called. If the macro is called multiple times, multiple copies of the code will be inserted. To avoid naming conflict of hash tables with different key-value types, the library uses token concatenation, which is a preprocessor feature whereby we can substitute part of a symbol based on the parameter of the macro. In the end, the C preprocessor will generate the following code and feed it to the compiler (macro kh_exist(h,k) is a little complex and not expanded for simplicity):

typedef struct {
  int n_buckets, size, n_occupied, upper_bound;
  unsigned *flags;
  unsigned *keys;
  char *vals;
} kh_m32_t;
static inline kh_m32_t *init_m32() {
  return (kh_m32_t*)calloc(1, sizeof(kh_m32_t));
}
static inline int get_m32(kh_m32_t *h, unsigned k)
...
static inline void destroy_m32(kh_m32_t *h) {
  if (h) {
    free(h->keys); free(h->flags); free(h->vals); free(h);
  }
}

int main() {
	int ret, is_missing;
	khint_t k;
	kh_m32_t *h = init_m32();
	k = put_m32(h, 5, &ret);
	if (!ret) del_m32(h, k);
	h->vals[k] = 10;
	k = get_m32(h, 10);
	is_missing = (k == h->n_buckets);
	k = get_m32(h, 5);
	del_m32(h, k);
	for (k = 0; k != h->n_buckets; ++k)
		if (kh_exist(h, k)) h->vals[k] = 1;
	destroy_m32(h);
	return 0;
}

This is the C program we know.

From this example, we can see that macros and the C preprocessor plays a key role in klib. Klib is fast partly because the compiler knows the key-value type at the compile time and is able to optimize the code to the same level as type-specific code. A generic library written with void* will not get such performance boost.

Massively inserting code upon instantiation may remind us of C++'s slow compiling speed and huge binary size when STL/boost is in use. Klib is much better in this respect due to its small code size and component independency. Inserting several hundreds lines of code won't make compiling obviously slower.

Resources

  • Library documentation, if present, is available in the header files. Examples can be found in the test/ directory.
  • Obsolete documentation of the hash table library can be found at SourceForge. This README is partly adapted from the old documentation.
  • Blog post describing the hash table library.
  • Blog post on why using void* for generic programming may be inefficient.
  • Blog post on the generic stream buffer.
  • Blog post evaluating the performance of kvec.h.
  • Blog post arguing B-tree may be a better data structure than a binary search tree.
  • Blog post evaluating the performance of khash.h and kbtree.h among many other implementations. An older version of the benchmark is also available.
  • Blog post benchmarking internal sorting algorithms and implementations.
  • Blog post on the k-small algorithm.
  • Blog post on the Hooke-Jeeve's algorithm for nonlinear programming.

Download Details:
 

Author: attractivechaos
Download Link: Download The Source Code
Official Website: https://github.com/attractivechaos/klib 
License: MIT License

#cprogramming #c 

Klib | A Standalone and Lightweight C Library
Beth  Nabimanya

Beth Nabimanya

1643695200

How To Use Data Structures in C

How To Use Data Structures in C

To start with, a data structure is a collection of data items that are kept together under one name or heading and is a specific way of storing and assembling the data so that the data can be used efficiently.

Types

Data Structures are prevalent and used in almost every software system. Some of the most common examples of Data Structures are arrays, queues, stacks, linked lists, and trees.

#c #cprogramming #datastructures 

How To Use Data Structures in C
Abdullah  Kozey

Abdullah Kozey

1643590800

How To Use Recursive Functions In C Programming

C programming recursion; In this tutorial, you will learn recursive functions in c programming with the help of definition, syntax, advantages, disadvantages, uses, and examples.

C Recursion

  • Recursion Function
  • Syntax of Recursive Function
  • Flowchart of Recursion
  • Advantages and Disadvantages of Recursion
  • Example 1 – C Program to Find Factorial of a Number Using Recursive Function
  • Example 2 – C program print first n Fibonacci numbers using recursion

full view

#c #cprogramming 

How To Use Recursive Functions In C Programming
Abdullah  Kozey

Abdullah Kozey

1643569200

Fully Understand Union in C Programming Language with Examples

Unions in c programming; Through this tutorial, you will learn everything about the union in c programming language with the help of examples.

C Programming Unions

  • What is union in C
  • Define a union in C
  • Declare a Union in C
  • Access members of a union
  • Example 1 – Union program for student details in C

Full View

#c #cprogramming 

Fully Understand Union in C Programming Language with Examples
Abdullah  Kozey

Abdullah Kozey

1643547600

Learn About Constructs in C Programming with Examples

Structures in C programming; Through this tutorial, you will learn structures in C programming with the help of examples.

Structures in C

  • Definition of Structures in C
  • Syntax of Structures In C
  • Define Structures in C
  • Example of Structures in C

Full View

#c #cprogramming 

Learn About Constructs in C Programming with Examples
Eric  Bukenya

Eric Bukenya

1643508000

How to Pass Single Array and Multidimensional Array To in C Function

How to Pass Single Array and Multidimensional Array To in C Function

Pass arrays to functions in c programming; Through this tutorial, you will learn how to pass single and multidimensional arrays to a function in C programming with the help of examples.

Pass Arrays to Function in C

There are two possible ways to pass array to function; as follow:

  • Passing array to function using call by value method
  • Passing array to function using call by reference
  • FAQ’s pass array to function in c
    • Passing a Multi-dimensional array to a function

#c #cprogramming 

How to Pass Single Array and Multidimensional Array To in C Function
Eric  Bukenya

Eric Bukenya

1643421600

Learn About Struct Array in C Programming with Examples

Array of structures in c programming; Through this tutorial, you will learn about array of structures in c programming with the help of examples.

Array of Structures in C

  • What is Array of Structures in C
  • Define Array of structures in C
  • C Program using Array of Structures

#c #cprogramming 

Learn About Struct Array in C Programming with Examples