En este tutorial aprenderemos unos aspectos básicos, pero no por ello menos importantes, que sin ellos, sería muy dificil completar un programa con éxito. Para entender algunas partes de este tutorial, es mejor saber algo de C, que se puede aprender aquí. Ante todo, no se recomienda tener C como primer lenuaje pues es susceptible coger vicios, malas costumbres y se tiene muy facil el acceso a un bajo nivel de programación.
ATENCION: Este tutorial puede ser editado en cualquier momente para agregar información.
ATENCION2: El tutorial puede contener errores, se agradacería su reporte para que se solucionen.
La programación en C, es sencilla, pero si no se aprende bien se pueden llegar a adoptar malas costumbres de programación. Aquí se presentan algunas tanto malas como buenas con unos ejemplos para ser mejor comprendidas:
En C es recomendable dar a las variables externas un valor inicial de 0, pues al declararlas, aunque se les de automáticamente un valor inicial de 0, es preferible inicializarlas para no dejarlas con los valores bailando.
En las funciones es conveniente, aun cuando no hace falta, poner return 0. Esto se considera una buena costumbre de la programación en C.
Ejemplo:
#include <stdio.h> int main(){ //Declaraciones int sumaconreturn(); void sumasinreturn(); int a = 10, b = 5; int c; c = a + b; printf("Resultado de a + b sin funcion: %i\n",c); printf("Desde main, pero llamando a funcion con return (necesario) es:%i\n", sumaconreturn(a, b)); sumasinreturn(a, b); getchar(); //Observad que hasta a la función main se la coloca un return return 0; //Esta linea también podría haberse escrito 'return;' } //Función que suma dos variables int sumaconreturn(a, b){ int c; c = a + b; //En esta función si que es necesario, por eso se pone return c; } //Función que suma dos variables muestra ese valor en pantalla //OJO, aunque se llame sin return, no quiere decir que no lo tenga, sino que no lo necesita void sumasinreturn(a, b){ int c; c = a + b; printf("La suma de a + b en una funcion sin return es el mismo, es: %i", c); //Y aquí va el return que, qunque no haga falta se pone return; //Se podría haber escrito return; }
Se observa que aun no necesitándose, se pone un return
La salida que generará este programa será:
Resultado de a + b sin funcion: 15 Desde main, pero llamando a funcion con return (necesario) es:15 La suma de a + b en una funcion sin return es el mismo, es: 15
ATENCIÓN: goto está considerada como una manera pobre y de mala forma de programación, y si se expone aquí es por el mero hecho de existir, pero no se recomienda su uso en ningún ámbito. Aún así, hay casos en los que no queda elección, pero aunque nos toque uno de estos casos, se deberá comentar en todo momento el porqué del goto y a dónde redirecciona. Esto, claro que no es obligatorio, pero, como ya se dijo, es una mala manera de programación.
El uso de goto es el siguiente:
goto etiqueta;
En donde etiqueta, va el nombre de una etiqueta previamente definida en el programa. Esto es, que el programa buscará la etiqueta a lo largo del programa y nos redireccionará dando el control a la linea donde se localizó etiqueta.
Una etiqueta se define así:
etiqueta:
Ejemplo de uso de goto
//Definición de bibliotecas #include <stdio.h> int main(){ int a = 5; int c; printf("Valor de C: "); scanf("%i", c); switch (c + a){ case 5: printf("\nEl valor de c es: 0"); case 7: printf("\nEl valor de c es: 2"); default: goto etiqueta; } ... etiqueta: printf("El valor de c es distinto de 0 y de 2"); getchar(); return 0; }
Por supuesto, en este ejemplo ni mucho menos es necesario poner goto, pero es un mero ejemplo.
Normalmente, goto se debería usar en lugares donde se precise de repetir la misma pieza de código repetidas veces, pero la gran parte de estas, es sustituible por una función:
//Ejemplo de como sustituir un goto por una función #include <stdio.h> int main(){ int a, b; float c; printf("Media de dos números"); repetir: printf("\nPor favor, escribe dos números. 0 en uno de los dos para finalizar"); printf("\na = "); scanf("%i", a); printf("\nb = "); scanf("%i", b); if (a == 0 || b == 0) goto repetir; else c = (a + b) / 2; getchar(); return 0; }
//Ejemplo de como sustituir un goto por una función #include <stdio.h> int main(){ void hallarmedia(); int nada; printf("Media de dos numeros\n"); hallarmedia(); scanf("%i", &nada); return 0; } void hallarmedia(){ int a, b; float c; do { printf("Por favor, escribe dos numeros distintos de 0. 0 para finalizar:\n"); printf("\na = "); scanf("%i", &a); printf("\nb = "); scanf("%i", &b); c = (a + b)/2; printf("La media de los dos valores es %.2f\n\n", c); }while(a != 0 && b != 0) return; }
El programa en sí con una función puede ser más largo, pero no más dificil de comprender, por eso es preferible que se haga con una función. Además, una función es facilmente ampliable y modificable, a diferencia de un goto, que habría que adaptar el código prácticamente entero para poder modificarlo.
goto, aunque en C esté visto como una mala costumbre de programación, en lenguajes de bajo nivel se suele utilizar mucho.
Estructurar un programa en diversas funciones es una buena costumbre de programación, es decir, en vez de poner todo en main(), donde se tendría que repetir la misma pieza de código 1000 veces, se pone en una función y se la llama cada vez para no tener que volver a escribirlo entero. Esta es otra ventaja del uso de funciones frente a goto.
Es una buena práctica de la programación declarar las funciones dentra de las que va a ser accedida aún en momentos que no es necesario. Es decir, si se pone la función al principio del programa, esta no necesitará una declaración, pero es preferible ponerla por ser una buena práctica de la programación. Aquí en este ejemplo se ha modificado el ejemplo anterior para demostrar que aunque no sea necesario se pone. Se han eliminado los tipos de los argumentos de la función para evitar confusiones:
#include <stdio.h> //Función int sumadatos(int a, int b){ int c; c = a + b; return c; } int main(){ //Declaracion de variables int a = 10; int b = 20; int c; //Se observa que se incluye la declaración aún sin ser necesaria. int sumadatos(); printf("Suma de dos valores.\n"); c = sumadatos(a, b); printf("El resultado es: %i", c); getchar(); return 0; }
Para evitar errores en el momento de la compilación, es preferible poner el tipo de los argumentos en las declaraciones, es decir, entre los paréntesis de la declaración, se pone el tipo de cada argumento:
#include <stdio.h> int main(){ //Declaracion de variables int a = 10; int b = 20; int c; //Ojo, se ponen los tipos de datos separados dentro de los paréntesis por comas. //Corresponden a los argumentos actuales int sumadatos(int, int); printf("Suma de dos valores.\n"); c = sumadatos(a, b); printf("El resultado es: %i", c); getchar(); return 0; } //Función int sumadatos(int a, int b){ int c; c = a + b; return c; } /* Eso se puede escribir: int sumadatos(int , int ) int a; int b; { int c; c = a + b; return c; } */
Se ponen en la declaración de la función los tipos
de los argumentos actuales.
Las funciones, si se obvia el tipo, automáticamente tendrán un tipo de int, y como en el código ASCII los caracteres equivalen a números enteros, estas también lo tendrán por defecto. Pero aún sin haber sido necesario, en todos los ejemplos expuestos hasta ahora se pone, pues es una buena práctica de la programación.
Break no está considerado como una mala costumbre de programación porque es necesario en las sentencias switch. Pero no está bien visto usarla en otro contexto
El código ASCII es un estandard (American Standard Code for Information Interchange, o lo que es lo mismo, Código estandar Estadounidense para intercambio de información), es un conjunto de códigos que engloba unos valores para escribir mensajes. En la actualidad, está constituido por 127 caracteres, de los cuales son imprimibles sólo los que están entre el 32 al 126, ambos inclusive; el resto de caracteres son sentencias de control utilizadas para complementar textos, la mayoría de ellas obsoletas.
Es un código de 7 bits, pero antiguamente era de 8 bits, pues se empleaba un bit adicional (bit de pariedad). El código ISO 8859-1, es un complemento para el código ASCII, para poder representar algunos idiomas que precisan de caracteres especiales no presentes en el antes mencionado (el español, por ejemplo).
*Tabla del código ASCII
La mayoría de las sentencias de escape van incluidas en el código ASCII, por eso se ponen como un subapartado de este.
Las más importantes y utilizadas son:
Cuando vayamos a crear un programa en C, lo más probable es que necesitemos usar una de las funciones anteriormente mencionadas. Pero para poder usarlas de un modo correcto, precisamos de saber como usarlas. Aunque a simple vista parezca muy simple, no lo es. Esto no quiere decir que sean complejas, ni mucho menos, pero tiene algunas cosas que puede llegar a rompernos la cabeza por no saber usarlas bien si somo novatos (experiencia propia). Uno de los apartados más importantes, es la introducción y salida de valores de variables. Con esto quiero decir que nos hará falta saber unos conversores con el fin de usarlas bien, si no queremos que a un entero le aparezca un exponente.
En este pseudo-código se muestra una función printf:
printf("Mensaje: %tipo %tipo", nombrevariable1, nombrevariable2);
%tipo sirve para que en su lugar aparezca el valor de la variable situado después del mensaje. Es decir, los valores aparecen respectivamente. La salida de este código, representaría que nombredevariable1 vaya donde el primer %tipo y el segundo con el otro.
Donde tipo, no va el nombre del tipo, es decir, no tendremos que poner %int o nos saltará esa cosa que adoramos tanto, error. Los tipos a escribir se exponen a continuación:
Además, C permite otros parámetros en la función printf, que se han de añadir antes de la letra de conversión y despues del porcentaje:
Ejemplo de un programa que usa esto:
//Librerías #include <stdio.h> //Funcion principal int main(){ //Declaración de variables int i = 0; int a = 16; float b = 132.5; long double c = 432.634; char d = d; char cadena[80]; //pedir el valor de cadena: printf("Introduce una cadena cualquiera:\n"); scanf("%[^n]", cadena); //Mostrar todo de distintas maneras printf("%i %x %o %+u %f %e %g %lf %s %c %10.50s %4lf", a, a, a, a, b, b, b, c, cadena, d, cadena, c); return 0; }
Seguro que en el futuro más de una vez necesitaréis usar un conversor de tipo. Los conversores de tipo, así de una manera simple, sirven para convertir el tipo de datos de una variable a otro tipo. Es to es muy sencillo de usar, pero también hay que saber como hacerlo, porque podremos crear un bonito programa que no funciona como queremos por la lógica del código. Esto es, si necesitamos un tipo, pero nosotros queremos convertir nuestra variable que tiene otro tipo, hay que tener cuidado de que tipo se usa, porque podremos perder información (no os asustéis que si perdéis algo es el valor de la variable, no otra cosa), o que el resultado no sea el esperado.
(tipo) nombre de variable;
#include <stdio.h> int main(){ float a; int b, c; printf("Introduce un valor de coma flotante para a:\n"); scanf("%f",&a); printf("\nIntroduce un valor entero para b:\n"); scanf("%i",&b); c = ((int) a) + b; printf("\nEl valor de c es: %i\n", c); system("PAUSE"); return 0; }
El resultado de este código, nos mostrará en pantalla un par de preguntas a responder y nos dará la suma de a truncada (es decir, si era 3.2456, se convierte en 3) más b.
Introduce un valor de coma flotante para a: 3.56 Introduce un valor entero para b: 2 El valor actual de c es: 5
Para realizar conversiones de tipo, no es necesario utilizar estos indicadores, es decir, se puede realizar operaciones con varios tipos, pero los resultados podrían ser inesperados, es decir, que podría salir un tipo o una pérdida del valor de la función que no se desea porque no es el objetivo del programa.
Grupo de preferencia Operador/es Asociatividad
Función, array, miembro de estructura, () [] · -> De izq a der
puntero a miembro de estructura.
Operadores unarios - ++ -- ! ~ * & sizeof (tipo) De der a izq
Multiplicación aritmética, división y resto * / % De izq a der
Suma y resta aritméticas + - De izq a der
Operadores de desplazamiento << >> De izq a der
Operadores relacionales < <= >= > De izq a der
Operadores de igualdad == != De izq a der
'And' a nivel de bits & De izq a der
'o exclusiva' a nivel de bits ^ De izq a der
'o' a nivel de bits | De izq a der
'y' lógica && De izq a der
'o' lógica || De izq a der
Operador condicional ?: De der a izq
Operadores de asignación = += -= *= /= %= De der a izq
&= ^= |= <<= >>=
Operador coma , De izq a der
Como detalles pequeños, que no merecen tener un apartado por ellos solos:
Comentarios
Con respecto a eso de las
Con respecto a eso de las buenas y malas costumbres, quisera preguntar: Que tan bueno o malo es ahorrarse el return(0); del final poniendo void main(void){ en lugar del int main(){ ??
Saludos ;)
La pregunta del millón
Lo cierto es que esa pregunta es más difícil de contestar de lo que parece. Concretamente la función main, tiene mucha polémica, y he visto muchos flames en foros de programación sobre ello. Parece ser que el "estándar" correcto es usar int main(). El uso de void main(), aunque ahora extendido, puede dar avisos o errores con algunos compiladores, sobretodo antiguos.
La forma "purista" de hacerlo sería con int y no devolviendo cero, sino EXIT_SUCCESS, que si bien vale 0 es la forma correcta de indicar el valor.
Como consejo, que es lo que hago y no tiene porqué ser lo mejor: si no quieres devolver ningún valor usa el void main().
Si te vas a meter en un proyecto "serio" de miles de lineas de código, que aunque hoy tu función main no devuelva nada, es posible que lo haga en unos meses, mejor hacer las cosas "con las reglas" y usar int main() return EXIT_SUCCESS.
LuaDiE: Crea en Lua sin teclear código. Compatible HM7, HMv2, LuaPlayer, LuaDEV y PGE.
ok ;)
Menos mal, yo pensaba que estaba agarrando una "mala costumbre" jejejejejeje, gracias por la aclaracion ;)
Saludos :)
mi opinión...
El 'return 0' del main (o EXIT_SUCCESS), es la forma que tiene tu programa de indicarle al sistema u otros programas que la ejecución ha sido correcta. Y en casa de error, indicarlo con un valor distinto de 0 (que uno aprovecha como identificador del error).
Si uno hace un programa que ejecuta a otro, enseguida se da cuenta de lo pràctico que es que el programa le indique si todo ha ido bien, como si de una llamada a otra función se tratara.
Puedes comprobar como todas las aplicaciones de linea de comandos (da igual windows, linux...) devuelven correctamente un número. Haz una ejecución correcta y te devolveran un cero, haz una ejecución por ejemplo con paràmetros incorrectos y devolverán un número distinto de 0.
Discutir sobre como definir el main es un poco ridículo. Si tu programa es tan simple que siempre va a devolver 0, da igual que uses int o void para el main. Pero en cualquier otro caso, un programa que no devuelva diferentes códigos de error, e incorpore un documento donde se expliquen, es simlemente un programa incompleto.
Buen tuto, igual que el
Buen tuto, igual que el anteriior, todo muy bien explicado.
Aunque yo discrepo en una cosa, sobre lo que comentas al principio de que todas las funciones tienen que devolver un valor 0. No estoy de acuerdo en absoluto, de hecho, para eso C tiene el void. Ahorra confusiones.
Ejemplo, tenemos en un header imaginario (p.ej numericos.h), la declaración de una función, que imprime el doble de un número. Viendo su sintaxis:
int ImprimeElDoble(int n);
Podemos deducir lo que hace. pero ¿porqué devuelve un int?, ¿se usa para algo?, ¿es un código de error si el número excede el capacidad?. La función no devuelve nada (bueno, devuelve siempre 0), pero sin ver la documentación o el código fuente, no podemos estar seguros de ello. Sin embargo poniendo su declaración como.
void ImprimeElDoble(int n);
Tenemos la seguridad de que no devuelve ningún valor así que no hace falta preocuparse en poder "recoger" ese posible valor. Quizás en una función tan simple sea muy lógico, pero por ejemplo la función qsort del mismo C que podemos encontrar en la stdlib.h:
void qsort(void *base, size_t nmemb, size_t size, int (*compare)(const void *, const void *));
La función de por sí ya es compleja, pero al menos vemos que no devuelve nada, un dato menos a tener en cuenta. Si devolviera un int, tendríamos que mirar la documentación para ver que devuelve... ¡siempre 0!
En lenguajes como Pascal (me encanta ese lenguaje), el tema se soluciona de una forma muy fácil: Si devuelve un valor se le llama función, si no lo devuelve, se le llama procedimiento.
Quitando ese matiz, no tengo nada más que objetar, felicitate de nuevo por el gran esfuerzo que estás haciendo introduciendo el C en la comunidad de Coders, a ver si se deciden de una vez a dar "el gran salto" y dejan a Lua.
Un saludo.
LuaDiE: Crea en Lua sin teclear código. Compatible HM7, HMv2, LuaPlayer, LuaDEV y PGE.
gracias, ya quite el 0
gracias, ya quite el 0
Sabes eso ultimo que dices,
Sabes eso ultimo que dices, tienes toda la razón. Seria bueno introducir otros lenguajes a la scene(java, C#, etc) y crear poyectos en conjunto, con fines de desarrollar mas programadores. Por si te interesa armar algo en pos de introducir otros lenguajes o a alguien mas, pues estaria dispuesto a ayudar(aportar) con lo poco que se y en lo que pueda.
Saludos
Muy buen tutorial.
Pedazo de tuto te has pegado P22, muy bueno y muy bien explicado.
Un saludo.
0_o
Zzzz por esto mismo no me gusta la programacion xD, mis totales respetos para los programadores, pero me lo pueden explicar como si tubiera 10 años xD
Procura seguir los tutoriales
Procura seguir los tutoriales de aquí, ahí puedes empezar desde 0. Están sin terminar, pero yo los estoy continuando. Saludos
yo creo necesitar algo mas
yo creo necesitar algo mas básico :S