
El lenguaje de programación C es increíblemente popular y es fácil ver por qué. La programación en C es eficiente y le da al programador un gran control. Muchos otros lenguajes de programación como C++, Java y Python se desarrollaron usando C.
Cada día aumentan las posibilidades de que, si eres programador, no utilices C exclusivamente para tu trabajo. Sin embargo, hay varios que aprender C es muy beneficioso, incluso si no lo usa con regularidad. Este es el por qué:
Podrá leer y escribir código para software que se puede usar en muchos tipos diferentes de plataformas informáticas, incluido todo, desde pequeños microcontroladores hasta sistemas operativos de escritorio, portátiles y móviles.
Comprenderá mejor qué hacen los lenguajes de alto nivel detrás de escena, como la administración de memoria y la recolección de elementos no utilizados. Esta comprensión puede ayudarlo a escribir programas que funcionen de manera más eficiente.
Si es un especialista en tecnología de la información (TI), también podría beneficiarse de aprender C. Los profesionales de TI a menudo escriben, mantienen y ejecutan scripts como parte de su trabajo. Un script es una lista de instrucciones que debe seguir el sistema operativo de una computadora. Para ejecutar ciertos scripts, la computadora configura un entorno de ejecución controlado llamado shell . Dado que la mayoría de los sistemas operativos ejecutan shells basados en C, C shell es una popular adaptación de secuencias de comandos de C que utilizan los profesionales de TI.
Este artículo cubre la historia detrás de C, analiza por qué C es tan importante, muestra ejemplos de algunos códigos básicos de C y explora algunas características importantes de C, incluidos tipos de datos, operaciones, funciones, punteros y administración de memoria. Aunque este artículo no es un manual de instrucciones para programar en C, cubre lo que hace que la programación en C sea única de una manera que va más allá de los primeros capítulos de la guía de programación en C promedio.
Empecemos por ver de dónde viene el lenguaje de programación C, cómo se ha desarrollado y el papel que tiene en el desarrollo de software en la actualidad.
- ¿Qué es C?
- Edición y compilación de código C
- El programa C más simple
- Conceptos comunes de programación en C
- Funciones en C
- Prototipos de funciones
- Tipos de datos y operaciones en C
- No empieces desde cero, usa bibliotecas
- Algunos punteros sobre punteros en C
- Usar punteros correctamente en C
- La importancia de la gestión de la memoria en C
¿Qué es C?
La forma más sencilla de definir C es llamarlo un lenguaje de programación de computadoras, lo que significa que puede escribir software con él que una computadora puede ejecutar. El resultado podría ser una gran aplicación informática, como su navegador web, o un pequeño conjunto de instrucciones incrustadas en un microprocesador u otro componente informático.
El lenguaje C se desarrolló a principios de la década de 1970 en Bell Laboratories, y se atribuye principalmente al trabajo de Ken Thompson y Dennis Ritchie. Los programadores necesitaban un conjunto de instrucciones más fácil de usar para el sistema operativo UNIX, que en ese momento requería programas escritos en lenguaje ensamblador. Los programas de ensamblaje, que hablan directamente con el hardware de una computadora, son largos y difíciles de depurar, y requerían un trabajo tedioso y lento para agregar nuevas funciones [fuente: King].
El primer intento de Thompson en un lenguaje de alto nivel se llamó B, un tributo al lenguaje de programación de sistemas BCPL en el que se basaba. Cuando Bell Labs adquirió un modelo de sistema UNIX PDP-11 de Digital Equipment Corporation (DEC), Thompson reformuló B para adaptarse mejor a las demandas del nuevo y mejor hardware del sistema. Así nació el sucesor de B, C. En 1973, C era lo suficientemente estable como para que UNIX se pudiera reescribir utilizando este nuevo e innovador lenguaje de nivel superior [fuente: King].
Antes de que C pudiera usarse de manera efectiva más allá de Bell Labs, otros programadores necesitaban un documento que explicara cómo usarlo. En 1978, el libro "El lenguaje de programación C" de Brian Kernighan y Dennis Ritchie, conocido por los entusiastas de C como K&R o el "Libro blanco", se convirtió en la fuente definitiva para la programación en C. Al momento de escribir este artículo, la segunda edición de K&R, publicada originalmente en 1988, todavía está ampliamente disponible. La versión original preestándar de C se llama K&R C y se basa en ese libro.
Para asegurarse de que las personas no crearan sus propios dialectos con el tiempo, los desarrolladores de C trabajaron durante la década de 1980 para crear estándares para el idioma. El estándar estadounidense para C, el estándar X3.159-1989 del American National Standards Institute (ANSI), se hizo oficial en 1989. El estándar de la Organización Internacional para la Estandarización (ISO), ISO/IEC 9899:1990, siguió en 1990. Las versiones de C después de K&R haga referencia a estos estándares y sus revisiones posteriores (C89, C90 y C99). También puede ver C89 denominado "ANSI C", "ANSI/ISO C" o "ISO C".
C y su uso en UNIX fue solo una parte del auge en el desarrollo de sistemas operativos durante la década de 1980. Sin embargo, a pesar de todas sus mejoras con respecto a sus predecesores, C todavía no era fácil de usar para desarrollar aplicaciones de software más grandes. A medida que las computadoras se volvieron más poderosas, aumentó la demanda de una experiencia de programación más sencilla. Esta demanda llevó a los programadores a construir sus propios compiladores y, por lo tanto, sus propios lenguajes de programación nuevos, utilizando C. Estos nuevos lenguajes podrían simplificar la codificación de tareas complejas con muchas partes móviles. Por ejemplo, lenguajes como C++ y Java, ambos desarrollados a partir de C, simplifican la programación orientada a objetos, un enfoque de programación que optimiza la capacidad del programador para reutilizar el código.
Ahora que conoce un poco de historia, echemos un vistazo a la mecánica de C en sí.
Edición y compilación de código C
C es lo que se conoce como un lenguaje compilado, lo que significa que debe usar un compilador para convertir el código en un archivo ejecutable antes de poder ejecutarlo. El código se escribe en uno o más archivos de texto, que puede abrir, leer y editar en cualquier editor de texto, como Notepad en Windows, TextEdit en Mac y gedit en Linux. Un archivo ejecutable es algo que la computadora puede ejecutar (ejecutar). El compilador verifica el código en busca de errores y, si parece estar libre de errores, crea un archivo ejecutable.
Antes de ver qué incluye el código C, asegurémonos de que podemos encontrar y usar un compilador C. Si usa Mac OS X y la mayoría de las distribuciones de Linux (como Ubuntu), puede agregar un compilador de C a su computadora si instala el software de herramientas de desarrollo para ese sistema operativo en particular. Estos compiladores de C gratuitos son herramientas de línea de comandos, lo que significa que normalmente los ejecutará desde un símbolo del sistema en una ventana de terminal. El comando para ejecutar uno de estos compiladores de C es "cc" o "gcc" más algunas opciones y argumentos de la línea de comandos, que son otras palabras escritas después del comando antes de presionar Intro.
Si utiliza Microsoft Windows o prefiere utilizar una interfaz gráfica de usuario en lugar de una línea de comandos, puede instalar un entorno de desarrollo integrado (IDE) para la programación en C. Un IDE es una interfaz única donde puede escribir su código, compilarlo, probarlo y encontrar y corregir errores rápidamente. Para Windows, puede comprar el software Microsoft Visual C++, un IDE para la programación tanto en C como en C++. Otro IDE popular es Eclipse, un IDE gratuito basado en Java que se ejecuta en Windows, Mac y Linux y tiene extensiones disponibles para compilar C y muchos otros lenguajes de programación.
Para C, como para otros lenguajes de programación de computadoras, la versión del compilador que usas es muy importante. Siempre querrá usar una versión del compilador de C que sea tan nueva o más nueva que la versión del lenguaje C que está usando en su programa. Si está utilizando un IDE, asegúrese de ajustar su configuración para asegurarse de que el IDE esté utilizando su versión C de destino para el programa en el que está trabajando. Si está en una línea de comando, puede agregar un argumento de línea de comando para cambiar la versión como en el siguiente comando:
gcc –std c99 –o miprograma.exe miprograma.c
En el comando anterior, "gcc" es la llamada para ejecutar el compilador y todo lo demás es una opción o argumento de la línea de comandos. Se agregó la opción "-std" seguida de "c99" para decirle al compilador que use la versión estándar C99 de C durante su compilación. Se agregó la opción "-o" seguida de "myprogram.exe" para solicitar que el ejecutable, el archivo de salida del compilador, se llame myprogram.exe. Sin "-o", el ejecutable se llama automáticamente a.out en su lugar. El argumento final "myprogram.c" indica el archivo de texto con el código C a compilar. En resumen, este comando dice: "Oye, gcc, compila myprogram.c usando el estándar de programación C99 C y coloca los resultados en un archivo llamado myprogram.exe".
Con su compilador instalado, está listo para programar en C. Comencemos por echar un vistazo a la estructura básica de uno de los programas en C más simples que podría escribir.
El programa C más simple
Veamos un programa C simple y usémoslo para comprender los conceptos básicos de C y el proceso de compilación de C. Si tiene su propia computadora con un compilador de C instalado como se describió anteriormente, puede crear un archivo de texto llamado sample.c y usarlo para seguir mientras avanzamos en este ejemplo. Tenga en cuenta que si omite la .c en el nombre del archivo, o si su editor agrega .txt al nombre, probablemente obtendrá algún tipo de error cuando lo compile.
Aquí está nuestro programa de muestra:
/* Programa de ejemplo */
#incluir
int principal()
{
printf("¡Esta es la salida de mi primer programa!\n");
devolver 0;
}
When compiled and executed, this program instructs the computer to print out the line "This is output from my first program!" and then stop. You can't get much simpler than that! Now let's take a look at what each line is doing:
Line 1 -- This is one way to write comments in C, between /* and */ on one or more lines.
Line 2 -- The #include command tells the compiler to look at other sources for existing C code, particularly libraries, which are files that include common reusable instructions. The references a standard C library with functions for getting input from a user and for writing output to the screen. We'll look at libraries a more closely later.
Línea 3: esta línea es la primera línea de una definición de función. Cada programa C tiene al menos una función, o un bloque de código que representa algo que la computadora debe hacer cuando se ejecuta el programa. La función realiza su tarea y luego genera un subproducto, denominado valor de retorno, que otras funciones pueden utilizar. Como mínimo, el programa tiene una función llamada main como la que se muestra aquí con un valor de retorno con el tipo de datos int, que significa entero. Cuando examinemos las funciones más adelante, verá lo que significan los paréntesis vacíos.
Líneas 4 y 7 -- Las instrucciones dentro de una función están encerradas entre llaves. Algunos programadores comienzan y terminan un bloque entre llaves en líneas separadas, como se muestra aquí. Otros colocarán la llave abierta ({) al final de la primera línea de la definición de la función. Aunque las líneas de código en el programa no tienen que escribirse en líneas separadas, los programadores normalmente colocan cada instrucción en una línea separada, sangrada con espacios, para que el código sea más fácil de leer y editar más tarde.
Línea 5 -- Esta es una llamada de función a una función llamada printf. Esa función está codificada en la biblioteca stdio.h incluida en la Línea 1, por lo que no tiene que escribirla usted mismo. Esta llamada a printf le dice qué imprimir en la pantalla. Sin embargo, el \n al final, entre comillas, no se imprime; es una secuencia de escape que indica a printf que mueva el cursor a la siguiente línea de la pantalla. Además, como puede ver, cada línea de la función debe terminar con un punto y coma.
Línea 6: cada función que devuelve un valor debe incluir una declaración de devolución como esta. En C, la función principal siempre debe tener un tipo de retorno entero, aunque no se use dentro del programa. Sin embargo, tenga en cuenta que cuando está ejecutando un programa en C, básicamente está ejecutando su función principal. Entonces, cuando esté probando el programa, puede decirle a la computadora que muestre el valor devuelto al ejecutar el programa. Se prefiere un valor de retorno de 0, ya que los programadores suelen buscar ese valor en las pruebas para confirmar que el programa se ejecutó correctamente.
Cuando esté listo para probar su programa, guarde el archivo y compile y ejecute el programa. Si está utilizando el compilador gcc en una línea de comando y el programa está en un archivo llamado sample.c, puede compilarlo con el siguiente comando:
gcc -o muestra.exe muestra.c
Si no hay errores en el código, debe tener un archivo llamado sample.exe en el mismo directorio que sample.c después de ejecutar este comando. El error más común es un error de sintaxis, lo que significa que ha escrito algo mal, como dejar un punto y coma al final de una línea o no cerrar comillas o paréntesis. Si necesita hacer cambios, abra el archivo en su editor de texto, arréglelo, guarde sus cambios e intente su comando de compilación nuevamente.
Para ejecutar el programa sample.exe, ingrese el siguiente comando. Tenga en cuenta el ./ que obliga a la computadora a buscar en el directorio actual para encontrar el archivo ejecutable:
./muestra.exe
Esos son los conceptos básicos de la codificación y compilación para C, aunque hay mucho más que puede aprender acerca de la compilación de otros recursos de programación C. Ahora, abramos la caja y veamos qué piezas tiene C para crear programas.
Conceptos comunes de programación en C
Echemos un vistazo a cómo poner en práctica algunos de los conceptos de programación comunes en su código C. El siguiente es un breve resumen de estos conceptos:
Funciones : como se indicó anteriormente, una función es un bloque de código que representa algo que la computadora debe hacer cuando se ejecuta el programa. Algunos lenguajes llaman a estas estructuras métodos, aunque los programadores de C no suelen usar ese término. Su programa puede definir varias funciones y llamar a esas funciones desde otras funciones. Más adelante, veremos más de cerca la estructura de funciones en C.
Variables : cuando ejecuta un programa, a veces necesita la flexibilidad para ejecutar el programa sin saber cuáles son los valores antes de tiempo. Al igual que otros lenguajes de programación, C le permite usar variables cuando necesita esa flexibilidad. Al igual que las variables en álgebra, una variable en la programación de computadoras es un marcador de posición que representa algún valor que no conoce o que aún no ha encontrado.
Tipos de datos : para almacenar datos en la memoria mientras se ejecuta su programa y saber qué operaciones puede realizar con esos datos, un lenguaje de programación como C define ciertos tipos de datos que reconocerá. Cada tipo de datos en C tiene un cierto tamaño, medido en bits o bytes binarios, y un cierto conjunto de reglas sobre lo que representan sus bits. Próximamente, veremos lo importante que es elegir el tipo de datos correcto para la tarea cuando usa C.
Operaciones : en C, puede realizar operaciones aritméticas (como sumas) con números y operaciones con cadenas (como concatenación) con cadenas de caracteres. C también tiene operaciones integradas diseñadas específicamente para cosas que quizás desee hacer con sus datos. Cuando revisemos los tipos de datos en C, también veremos brevemente las operaciones.
Bucles : una de las cosas más básicas que un programador querrá hacer es repetir una acción varias veces en función de ciertas condiciones que surjan mientras se ejecuta el programa. Un bloque de código diseñado para repetirse en función de determinadas condiciones se denomina bucle, y el lenguaje C proporciona estas estructuras de bucle comunes: while, do/while, for, continue/break y goto. C también incluye los condicionales comunes if/then/else y las sentencias switch/case.
Estructuras de datos : cuando su programa tiene una gran cantidad de datos para manejar y necesita ordenar o buscar a través de esos datos, probablemente usará algún tipo de estructura de datos. Una estructura de datos es una forma estructurada de representar varias piezas de datos del mismo tipo de datos. La estructura de datos más común es una matriz, que es solo una lista indexada de un tamaño determinado. C tiene bibliotecas disponibles para manejar algunas estructuras de datos comunes, aunque siempre puede escribir funciones y configurar sus propias estructuras también.
Operaciones del preprocesador : a veces querrás darle al compilador algunas instrucciones sobre qué hacer con tu código antes de compilarlo en el ejecutable. Estas operaciones incluyen la sustitución de valores constantes y la inclusión de código de bibliotecas C (que vio en el código de ejemplo anterior).
C también requiere que los programadores manejen algunos conceptos que muchos lenguajes de programación han simplificado o automatizado. Estos incluyen punteros, administración de memoria y recolección de basura. Las páginas posteriores cubren las cosas importantes que debe saber acerca de estos conceptos al programar en C.
Esta breve descripción general de los conceptos puede parecer abrumadora si aún no eres programador. Antes de pasar a abordar una guía de programación C densa, echemos un vistazo fácil de usar a los conceptos básicos entre los enumerados anteriormente, comenzando con las funciones.
Funciones en C
La mayoría de los lenguajes de programación de computadoras le permiten crear funciones de algún tipo. Las funciones le permiten dividir un programa largo en secciones con nombre para que pueda reutilizar esas secciones en todo el programa. Los programadores de algunos lenguajes, especialmente aquellos que usan técnicas de programación orientada a objetos, usan el término método en lugar de función .
Las funciones aceptan parámetros y devuelven un resultado. El bloque de código que comprende una función es su definición de función. La siguiente es la estructura básica de una definición de función:
{
devolver
}
At a minimum, a C program has one function named main. The compiler will look for a main function as the starting point for the program, even if the main function calls other functions within it. The following is the main we saw in the simple C program we looked at before. It has a return type of integer, takes no parameters, and has two statements (instructions within the function), one of which is its return statement:
int main()
{
printf("This is output from my first program!\n");
return 0;
}
Functions other than main have a definition and one or more function calls. A function call is a statement or part of a statement within another function. The function call names the function it's calling followed by parentheses. If the function has parameters, the function call must include corresponding values to match those parameters. This additional part of the function call is called passing parameters to the function.
But what are parameters? A parameter for a function is a piece of data of a certain data type that the function requires to do its work. Functions in C can accept an unlimited number of parameters, sometimes called arguments. Each parameter added to a function definition must specify two things: its data type and its variable name within the function block. Multiple parameters are be separated by a comma. In the following function, there are two parameters, both integers:
int doubleAndAdd(int a, int b)
{
return ((2*a)+(2*b));
}
Next, let's continue our look at functions by zooming out to look at how they fit within a larger C program.
Function Prototypes
In C, you can add a function definition anywhere within the program (except within another function). The only condition is that you must tell the compiler in advance that the function exists somewhere later in the code. You'll do this with a function prototype at the beginning of the program. The prototype is a statement that looks similar to the first line of the definition. In C, you don't have to give the names of the parameters in the prototype, only the data types. The following is what the function prototype would look like for the doubleAndAdd function:
int doubleAndAdd(int, int);
Imagine prototipos de funciones como la lista de empaque para su programa. El compilador desempaquetará y ensamblará su programa de la misma manera que desempaquetaría y ensamblaría una nueva biblioteca. La lista de empaque lo ayuda a asegurarse de tener todas las piezas que necesita en la caja antes de comenzar a armar la estantería. El compilador usa los prototipos de funciones de la misma manera antes de comenzar a ensamblar su programa.
Si está siguiendo el programa sample.c que vimos anteriormente, abra y edite el archivo para agregar un prototipo de función, una definición de función y una llamada de función para la función doubleAndAdd que se muestra aquí. Luego, compile y ejecute su programa como antes para ver cómo funciona el nuevo código. Puede usar el siguiente código como guía para probarlo:
#incluir
int doubleAndAdd(int, int);
int principal()
{
printf("¡Esta es la salida de mi primer programa!\n");
printf("Si duplicas luego sumas 2 y 3, el resultado es: %d \n", doubleAndAdd(2,3));
devolver 0;
}
int doubleAndAdd(int a, int b)
{
retorno ((2*a)+(2*b));
}
Hasta ahora hemos visto algunos elementos estructurales básicos en un programa C. Ahora, veamos los tipos de datos con los que puede trabajar en un programa C y qué operaciones puede realizar con esos datos.
Declaraciones de funciones
In C, you'll probably hear the term function declaration more than function prototype, especially among older C programmers. We're using the term function prototype in this article, though, because it has an important distinction. Originally, a function declaration did not require any parameters, so the return type, function name and a pair of empty parentheses were sufficient. A function prototype, though, gives the compiler important additional information by including the number and data types of the parameters it will call. Prototypes have become a best practice approach among coders today, in C and other programming languages.
Data Types and Operations in C

From your computer's perspective, data is nothing but a series of ones and zeros representing on and off states for the electronic bits on your hard drive or in your computer's processor or memory. It's the software you're running on a computer that determines how to make sense of those billions of binary digits. C is one of few high-level languages that can easily manipulate data at the bit level in addition to interpreting the data based on a given data type.
A data type is a small set of rules that indicate how to make sense of a series of bits. The data type has a specific size plus its own way of performing operations (such as adding and multiplying) on data of that type. In C, the size of the data type is related to the processor you're using. For example, in C99, a piece of data of the integer data type (int) is 16 bits long in a 16-bit processor while for 32-bit and 64-bit processors it's 32 bits long.
Another important thing for C programmers to know is how the language handles signed and unsigned data types. A signed type means that one of its bits is reserved as the indicator for whether it's a positive or negative number. So, while an unsigned int on a 16-bit system can handle numbers between 0 and 65,535, a signed in on the same system can handle numbers between -32,768 and 32,767. If an operation causes an int variable to go beyond its range, the programmer has to handle the overflow with additional code.
Given these constraints and system-specific peculiarities in C data types and operations, C programmers must choose their data types based on the needs of their programs. Some of the data types they can choose are the primitive data types in C, meaning those built in to the C programming language. Look to your favorite C programming guide for a complete list of the data types in C and important information about how to convert data from one type to another.
C programmers can also create data structures, which combine primitive data types and a set of functions that define how the data can be organized and manipulated. Though the use of data structures is an advanced programming topic and beyond the scope of this article, we will take a look at one of the most common structures: arrays. An array is a virtual list containing pieces of data that are all the same data type. An array's size can't be changed, though its contents can be copied to other larger or smaller arrays.
Though programmers often use arrays of numbers, character arrays, called strings, have the most unique features. A string allows you to save something you might say (like "hello") into a series of characters, which your C program can read in from the user or print out on the screen. String manipulation has such a unique set of operations, it has its own dedicated C library (string.h) with your typical string functions.
The built-in operations in C are the typical operations you'd find in most programming languages. When you're combining several operations into a single statement, be sure to know the operator precedence, or the order in which the program will perform each operation in a mathematical expression. For example, (2+5)*3 equals 21 while 2+5*3 equals 17, because C will perform multiplication before addition unless there are parentheses indicating otherwise.
If you're learning C, make it a priority to familiarize yourself with all of its primitive data types and operations and the precedence for operations in the same expression. Also, experiment with different operations on variables and numbers of different data types.
At this point, you've scratched the surface of some important C basics. Next, though, let's look at how C enables you to write programs without starting from scratch every time.
Don't Start from Scratch, Use Libraries
Libraries are very important in C because the C language supports only the most basic features that it needs. For example, C doesn't contain input-output (I/O) functions to read from the keyboard and write to the screen. Anything that extends beyond the basics must be written by a programmer. If the chunk of code is useful to multiple different programs, it's often put into a library to make it easily reusable.
In our discussion of C so far, we've already seen one library, the standard I/O (stdio) library. The #include line at the beginning of the program instructed the C compiler to loaded the library from its header file named stdio.h. C maintainers include standard C libraries for I/O, mathematical functions, time manipulation and common operations on certain data structures, such as a string of characters. Search the Web or your favorite C programming guide for information about the C89 standard library and the updates and additions in C99.
You, too, can write C libraries. By doing so, you can split your program into reusable modules. This modular approach not only makes it easy to include the same code in multiple programs, but it also makes for shorter program files which are easier to read, test and debug.
To use the functions within a header file, add a #include line for it at the beginning of your program. For standard libraries, put the name of the library's corresponding header file between greater-than and less-than signs (). For libraries you create yourself, put the name of the file between double quotes. Unlike statements in other parts of your C program, you don't have to put a semicolon at the end of each line. The following shows including one of each type of library:
#include
#include "mylib.h"
A comprehensive C programming source should provide the instructions you need to write your own libraries in C. The function definitions you'll write are not any different whether they're in a library or in your main program. The difference is that you'll compile them separately in something called an object file (with a name ending in .o), and you'll create a second file, called a header file (with a name ending in .h) which contains the function prototypes corresponding to each function in the library. It's the header file you'll reference in your #include line in each main program that uses your library, and you'll include the object file as an argument in the compiler command each time you compile that program.
The C features we've explored so far are typical in other programming languages, too. Next, though, we'll talk about how C manages your computer's memory.
Some Pointers about Pointers in C
When your C program is loaded into memory (typically the random-access memory, or RAM, in your computer), each piece of the program is associated with an address in memory. This includes the variables you're using to hold certain data. Each time your program calls a function, it loads that function and all of its associated data into memory just long enough to run that function and return a value. If you pass parameters to the function, C automatically makes a copy of the value to use in the function.
Sometimes when you run a function, though, you want to make some permanent change to the data at its original memory location. If C makes a copy of data to use in the function, the original data remains unchanged. If you want to change that original data, you have to pass a pointer to its memory address (pass by reference) instead of passing its value to the function (pass by value).
Pointers are used everywhere in C, so if you want to use the C language fully you have to have a good understanding of pointers. A pointer is a variable like other variables, but its purpose is to store the memory address of some other data. The pointer also has a data type so it knows how to recognize the bits at that memory address.
When you look at two variables side-by-side in C code, you may not always recognize the pointer. This can be a challenge for even the most experienced C programmers. When you first create a pointer, though, it's more obvious because there must be an asterisk immediately before the variable name. This is known as the indirection operator in C. The following example code creates an integer i and a pointer to an integer p:
int i;
int *p;
Currently there is no value assigned to either i or p. Next, let's assign a value to i and then assign p to point to the address of i.
i = 3;
p = &i;
Here you can see the ampersand (&) used as the address operator immediately before i, meaning the "address of i." You don't have to know what that address is to make the assignment. That's good, because it will likely be different every time you run the program! Instead, the address operator will determine the address associated with that variable while the program is running. Without the address operator, the assignment p=i would assign p the memory address of 3, literally, rather than the memory address of the variable i.
Next, let's look at how you can use pointers in C code and the challenges you'll want to be prepared for.
Using Pointers Correctly in C

Once you have a pointer, you can use that in place of a variable of the same data type in operations and function calls. In the following example, the pointer to i is used instead of i within a larger operation. The asterisk used with the p (*p) indicates that the operation should use the value that p is pointing to at that memory address, not the memory address itself:
int b;
b = *p + 2;
Without pointers, it's nearly impossible to divide tasks into functions outside of main in your C program. To illustrate this, consider you've created a variable in main called h that stores the user's height to the nearest centimeter. You also call a function you've written named setHeight that prompts the user to set that height value. The lines in your main function might look something like this:
int h;
setHeight(h); /* There is a potential problem here. */
This function call will try to pass the value of h to setHeight. However, when the function finishes running, the value of h will be unchanged because the function only used a copy of it and then discarded it when it finished running.
If you want to change h itself, you should first ensure that the function can take a pointer to an existing value rather than a new copy of a value. The first line of setHeight, then, would use a pointer instead of a value as its parameter (note the indirection operator):
setHeight(int *height) { /* Function statements go here */ }
Then, you have two choices for calling setHeight. The first is to use the address operator for h as the passed parameter (&h). The other is to create a separate pointer to h and pass that instead. The following shows both options:
establecerAltura(&h); /* Pasar la dirección de h a la función */
int *p;
p = &h;
establecerAltura(p); /* Pasa un puntero separado a la dirección de h a la función */
La segunda opción revela un desafío común al usar punteros. El desafío es tener múltiples punteros al mismo valor. Esto significa que cualquier cambio en ese valor afecta a todos sus punteros a la vez. Esto podría ser algo bueno o malo, dependiendo de lo que intente lograr en su programa. Una vez más, dominar el uso de punteros es una clave importante para dominar la programación en C. Practique con punteros tanto como sea posible para estar listo para enfrentar estos desafíos.
Las características de C que hemos explorado hasta ahora también son típicas en otros lenguajes de programación. A continuación, sin embargo, veremos las demandas de C para una gestión cuidadosa de la memoria.
La importancia de la gestión de la memoria en C
Una de las cosas que hace que C sea un lenguaje tan versátil es que el programador puede reducir la escala de un programa para ejecutarlo con una cantidad muy pequeña de memoria. Cuando se escribió C por primera vez, esta era una característica importante porque las computadoras no eran tan poderosas como lo son hoy. Con la demanda actual de dispositivos electrónicos pequeños, desde teléfonos móviles hasta dispositivos médicos diminutos, existe un interés renovado en mantener pequeños los requisitos de memoria para algunos programas. C es el lenguaje de referencia para la mayoría de los programadores que necesitan mucho control sobre el uso de la memoria.
To better understand the importance of memory management, consider how a program uses memory. When you first run a program, it loads into your computer's memory and begins to execute by sending and receiving instructions from the computer's processor. When the program needs to run a particular function, it loads that function into yet another part of memory for the duration of its run, then abandons that memory when the function is complete. Plus, each new piece of data used in the main program takes up memory for the duration of the program.
Si desea tener más control sobre todo esto, necesita una asignación de almacenamiento dinámica. C admite la asignación de almacenamiento dinámico, que es la capacidad de reservar memoria cuando la necesita y liberarla tan pronto como termine de usarla. Muchos lenguajes de programación tienen asignación automática de memoria y recolección de basura que manejan estas tareas de administración de memoria. Sin embargo, C permite (y en algunos casos requiere) que sea explícito sobre la asignación de memoria con las siguientes funciones clave de la biblioteca C estándar:
- malloc -- Short for memory allocation, malloc is used to reserve a block of memory of a given size to story a certain type of data your program needs to process. When you use malloc, you're creating a pointer to the allocated memory. This isn't necessary for a single piece of data, such as one integer, which is allocated as soon as you first declare it (as in int i). However, it is an important part of creating and managing data structures such as arrays. Alternate memory allocation options in C are calloc, which also clears the memory when it's reserved, and realloc, which resizes previously reserved memory.
- free -- Use free to force your program to free the memory previously assigned to a given pointer.
La mejor práctica al usar malloc y free es que todo lo que asigne debe liberarse. Cada vez que asigna algo, incluso en una función temporal, permanece en la memoria hasta que el sistema operativo limpia el espacio. Sin embargo, para asegurarse de que la memoria esté libre y lista para usar de inmediato, debe liberarla antes de que finalice la función actual. Esta administración de memoria significa que puede mantener la huella de memoria de su programa al mínimo y evitar pérdidas de memoria. Una pérdida de memoria es una falla del programa en la que continúa usando más y más memoria hasta que no queda nada para asignar, lo que hace que el programa se detenga o se bloquee. Por otro lado, no te angusties tanto por liberar memoria que liberas, y por tanto pierdes, algo que luego necesitas en la misma función.
Throughout this article, you've learned some of the basic structure and core concepts of the C programming language. We've looked at its history, the characteristics it has in common with other programming languages and the important features that make it a unique and versatile option for coding software. Launch over to the next page for lots more information, including some programming guides that will carry you further on your journey into C.
Lots More Information
Related Articles
- The Basics of C Programming
- How Java Works
- How Boolean Logic Works
- How PERL Works
- How BIOS Works
- How CGI Scripting Works
- How Bits and Bytes Work
More Great Links
- C Programming.com Tutorial
- C Programming at Wikibooks
- GNU Compiler Collection (GCC)
- Eclipse Integrated Development Environment Software
Sources
- Kernighan, Brian W., and Ritchie, Dennis M. "C Programming Language, Second Edition." Prentice Hall. 1988.
- King, K.N. "C Programming: A Modern Approach, Second Edition." W.W. Norton & Company, Inc. 2008.