Curso completo de programación con lenguaje C

gonya707

#120 En realidad la regla de oro de la programación es "alguien lo ha hecho antes que tú".

1
wiFlY

#89 porque has puesto 0.1 y 0.5 en los fprintf de salida de los resultados de las operaciones en el programa de la calculadora? (ejercicio 4)

Estoy atascado con ese ejercicio. Haciendolo de otra manera no se porque leches cuando ejecuto le programa se peta el cmd, aparece el tipico mensaje de "XXXXX ha dejado de funcionar..."

2 respuestas
B

#122 los double sacan de 2+2 : 4.000 , con %0.1f haces que 4.000 se quede en 4.0

Así puedes operar con double y decirle que solo quieres 1, 2, 3, n decimales.

1
gonya707

#122 XXXX ha dejado de funcionar significa que has dividido por cero, has intentado ahcer una raiz cuadrada de un numero negativo o que has hecho un out of bounds de un array. Probablemente te ha pasado lo primero

1
B

Capitulo 5.

Ejercicio 1
Ejercicio 2
Ejercicio 3
Ejercicio 4
Ejercicio 5
Ejercicio 6
Ejercicio 7
Ejercicio 9
Ejercicio 10
Ejercicio 11

Ejercicio 11 hecho después de hacer un par de bucles infinitos, seguro que se puede mejorar :clint:

Iré editando según acabe ejercicios.

1 respuesta
burton92

Tremendo curro, muchas gracias.

Empezando con las primeras lecciones! muy interesante todo.

angelrcd
Lección 3, ejercicio 4
1 comentario moderado
wiFlY

Buenas, estoy haciendo el ejercicio de la calculadora y tengo un problema. Estoy haciendo un programita para hacer operaciones basicas con numeros de una cifra. Los dos numeros los mete el usuario y el mismo elige que operacion desea realizar.

Ademas, el programa debe identificar que la variable que se mete cumpla con los requisitos, es decir, que sea un número del 1 al 9. En vez de hacerlo de la manera convencional, que seria comprobando que pertenece a ese conjunto de numeros, quiero hacerlo al reves, quiero que compruebe que no es ninguna de las otras cosas que puede ser un char.

Mi problema es que una vez asignadas las entradas a las variables char y posteriormente a que hayan sido comprobadas necesito operar con ellas y para ello char no me vale. Entonces, como cojo esa cifra asignada a una variable char y la paso a una variable int, double o float?

1 respuesta
gonya707

#129 en stdlib.h hay definida la funcion que buscas

int atoi(char);

atoi (alpha to int) te convierte un caracter numeral al numero que corresponde

#129 estoy mirando y es posible que tengas que ponerle el & al caracter de entrada igual que se hace con el fscanf

1 1 respuesta
wiFlY

#130 Tal cual y menos mal que me lo dijiste porque me estaba rayando bastante xDD

Lecherito

#125 Como consejo

spoiler

No me hagas eso hombre, el do while solo lo haces una vez por lo que no hace falta tenerlo ahí xD

1 1 respuesta
B

#132 Ahora que lo piensas en frio, tienes razón.

¿Sabes que pasa? Qué en mi cabeza funciona, entonces, hasta que lo que hay en mi cabeza no funciona, no soy feliz :D

Luego lo arreglo, que aún me faltan un par de ejercicios, thx

gonya707

6 - Funciones

Durante todo este tiempo hemos usado funciones para realizar multitud de operaciones, como escribir por pantalla, leer por teclado, realizar diversas operaciones matemáticas con las funciones de math.h y un largo etc. Este capítulo se centrará no en esas funciones que ya conocemos, si no en cómo crear nosotros mismos funciones que necesitemos y cómo usarlas.

El prototipo

Ya se había comentado en un capítulo anterior que era el prototipo de una función, en el que se resumen los elementos de ella en una sola línea: las entradas, la salida y su nombre.

salida nombre(entrada1, entrada2,...);

Tanto la salida como las entradas tienen que corresponder con tipos de variable que existan, ya conocemos unos cuantos como bool, int, float, double, char, etc. También una especial mención a la variable void (vacío), que es la especificada en el caso de que no se quiera ninguna variable.

int funcion1(int, int); // Entradas: 2 números enteros. Salida: un número entero
void funcion2(int); // Entrada: 1 número entero. Salida: Nada
bool funcion3(float, int); // Entradas: 1 número entero y un float. Salida: Un booleano

La única restricción necesaria para estos prototipos es que una función en C solo puede tener una salida. Los prototipos deben escribirse antes de la función main.

Este sería un programa de ejemplo después de escribir nuestros prototipos:

spoiler

La definición

Después de haber decidido nuestros prototipos, ahora toca definir el contenido de cada función. Esta vez después del main se deben volver a escribir los prototipos, aunque sin el punto y coma, abrir unas llaves y darle nombre a todas las entradas.

bool esDivisible(int dividendo,int divisor){

}

En este ejemplo vamos a hacer la función esDivisible, que debería recibir dos entradas, dividendo y divisor, ya hemos nombrado adecuadamente, y devolverá simplemente si es cierto que son números divisibles, por tanto, su salida debe ser un bool.

Una vez dentro de la función se crea un entorno de variables nuevo, un entorno local. Desde aquí dentro no se pueden acceder a las variables que se habían creado dentro de main, sólo se pueden usar las que estén dentro de la propia función, que en este caso son 'dividendo' y 'divisor', que al haber sido declaradas como entradas, ya existen sin necesidad de declararlas.

bool esDivisible(int dividendo,int divisor){
        int resto;
        resto = dividendo % divisor;
        if (0 == resto){
                 return 1;
        }
        else{
                 return 0;
        }
}

En la definición de esDivisible podeis ver otra de las palabras reservadas de C, que ya era conocida, return. return rompe la secuencia del programa, es decir, si se consigue llegar dentro de una función a un return, ahi se saldrá de esa función. El numero que se retorna además, deberá corresponderse con el tipo que se había especificado como salida en el prototipo, en este caso un bool. Si una función no tenía salida (void), no se puede usar return.

Toda esta información puede resultar muy confusa, la mejor manera de interiorizarlo es analizando ejemplos ya hechos, como por ejemplo estos:

char aMinusculas(char letra){
         if (letra > 64 && letra < 91){ //es una letra mayuscula?
                 return (letra + 32); //32 es la distancia entre las mayus y minus 
         else{
                 fprintf(stderr,"El caracter introducido no era una letra may%cscula", 163);
                 return letra;
         }
}

En este caso tenemos una función que recibe un caracter (presumiblemente una letra mayúscula), y devuelve la misma letra, pero en minúsculas. Al entrar a la función se nos han limpiado las variables, pero tenemos ya una creada, 'letra', que contendrá el caracter con el que operar. Se realiza la comprobación de si es efectivamente le entrada esperada. En caso positivo se opera y se retorna el valor en minuscula y en caso negativo se hace aparecer un aviso por la consola (stderr es el fichero estandar de error, que en este caso es la pantalla) y se retorna el valor inalterado de la letra.

El uso de funciones

Una vez definidas y codificadas nuestras funciones solo hace falta una cosa... usarlas! Suponiendo que ya hemos rellenado el prototipo antes de empezar main y hemos escrito todo el contenido de la función después del main. El aspecto de nuestro programa con uno de los ejemplos de antes debería ser algo así:

spoiler

Ahora en nuestro programa haremos las acciones necesarias, además usando nuestra función. Cuando expliqué las cosas que contenía math.h os presenté el prototipo de las instrucciones y a partir de ahí sabíamos usarlo: en las entradas especificamos variables reales de nuestro programa y las salidas se asignan de derecha a izquierda como siempre a otra variable, como por ejemplo

char r;
char s;
fflush(stdin);
fscanf(stdin, "%c", &r);
s = aMinusculas(r);

variables de ámbito local y global

Para terminar con esta lección es importante que hable sobre el ámbito de las variables. Hasta ahora siempre habiamos creado las variables dentro del main y no habiamos tenido ningún problema. Las variables creadas dentro de una función (como es main) solo existen dentro de esa función.

Esto no representaba ningún problema, ya que todos nuestros programas solo consistían en una función main, pero ahora tenemos otras funciones externas y la cosa cambia. Supongamos que tenemos un programa tal que así:

#include <stdio.h>

void funcion1(void);

int main(void){
   int n = 3;
   funcion1();
   return 0;
}

void funcion1(void){
    fprintf(stdout, "%d", n);
}

En este ejemplo cabría esperar que el resultado fuese que se escriba por pantalla el valor de n, que es 3, pero no es así. Lo que ocurrirá es que da error, la variable n no existe dentro de funcion1, ha sido creada en main, y solo puede llamarse desde main. n es lo que se conoce como una variable local. Solo puede ser vista de manera parcial en el programa, concretamente desde la función donde se ha creado.

#include <stdio.h>

void funcion1(int);

int main(void){
   int n = 3;
   int s = 7;

   funcion1(n);
   
fprintf(stdout, "%d", n); fprintf(stdout, "%d", s); } void funcion1(int X){ int s; s = X * 2; }

Ahora otro ejemplo. Esta vez la funcion1 recibe un parámetro de entrada, un número entero y opera con él. Ese parámetro es n, pero una vez que se llega al interior de la función se crea la variable local X, y el n del main permanece intacto. Se crea entonces la variable s, que toma el valor de X * 2, termina la funcion y se destruyen todas las variables locales. De vuelta al main imprimimos el contenido de n y de s, que es lo que se escribe, el valor que se les asignó en main o el valor cambiado de funcion1? La respuesta correcta es la primera, porque si se llama a n y s desde main, se van a tomar las variables locales de main, no las variables locales de una funcion externa, aunque se llamen igual.

Una manera de solucionar este desaguisado es con punteros, que veremos en la siguiente lección. También gracias a los punteros podremos tener varios parámetros de salida en una función. Pero además existe otra manera, creando variables globales, que como su propio nombre indica, pueden ser accedidas desde cualquier punto del programa, tanto el main como las funciones. La manera de crear una variable global es simplemente declararla fuera de cualquier función.

#include <stdio.h>
int n = 3;

void funcion1(void);

int main(void){
   n = n + 3;
   funcion1();
   return 0;
}

void funcion1(void){
    n = n * 2;
    fprintf(stdout, "%d", n);
}

En este caso se crea n como variable global y se le asigna el valor 3. Tened cuidado porque no se puede operar fuera de las funciones con las variables globales, es decir si en la tercera linea pusiese un if o cualquier cosa, el programa va dar error de compilación.

una vez dentro del main sin haber creado variables locales ni nada, se suma 3 al valor de n. n es una variable que ya existe en el scope de la función main, ya que es global, asi que no hay ningun problema. Posteriormente se entra en funcion1 y se vuelve a operar sobre n, a continuación se imprime el valor, que será 12.

Deberes

Esta vez seré benévolo. Los deberes para esta lección será tan solo hacer un programa, aunque será largo. Simplemente consiste en convertir a funciones ejercicios ya realizados anteriormentes, cuyos prototipos serán los siguientes:

int menu(void);
double productoComoSumas(double, double);
double potenciaComoMultiplicaciones(double, double);
int factorial (int);
char aMayusculas(char);
char aMinusculas(char);
bool esLetra(char);
bool esNumero(char);
bool esSigno(char);
void dibujarLinea(int);
void dibujarRectangulo(int);

Supongo que al saber nombres y parametros de entrada/salida lo que tiene que hacer cada funcion se sobreentiende no?

El programa debe contener todos estos prototipos y las funciones codificadas perfectamente funcionales. Para comprobar que efectivamente funciona, escribir en el main una "demo" que muestre por pantalla el funcionamiento de cada funcion.

1 1 respuesta
Maaarc

Una pregunta, el tema de hacer funciones en otra "hoja" como funciona? Que es algo que nunca me han enseñado xD

1 respuesta
gonya707

#135 tengo preparada otra leccion que habla especificamente de eso :p No es tan simple como para explicarlo en dos párrafos

1 1 respuesta
preguntitas

#136, tremendo curro. Deseando llegar a punteros.

Por cierto, en la leccion 6 hay una errata:

La manera de crear una variable local es simplemente declararla fuera de cualquier función

ese "local" deberia ser "global", no?

1 2 respuestas
B

#137 Por cierto, en la leccion 6 hay una errata:

sólo? eso es porque no has leido las anteriores antes de corregirse :P

1 respuesta
gonya707

#137 gracias por el aviso. Tienes razón.

#138 Soy humano xd

Voy a tener que hacer un proofreading a lo bestia cuando quiera recopilar todo y hacer un documento con el curso completo

1 respuesta
Maaarc

#139 Hazlo en LaTeX... es más si lo haces en verano te ayudo y así aprendo a usar LaTeX.

1 respuesta
gonya707

#140 Hombre, daba por hecho hacerlo en LaTeX, hace por lo menos 2 años que no abro el Word xD

1 1 respuesta
B

Capitulo 6 - Deberes

tocho
E

Gracias por tu dedicación cuando tenga tiempo libre me pondré con C.

Gracias!

cabron

Un pequeño apunte sobre #134, no declaréis el protototipo de las funciones sin poner nombres a los parámetros. Me refiero a esto:

int hagoCosas(int, float, char);

En lugar de eso haced:

int hagoCosas (int yoSoyUnacosa, float yoOtra, char yOtraMas);

Desde el punto de vista técnico las dos están bien y no hay ninguna diferencia entre una y otra, el motivo por el que es mejor la segunda, es por que sirve de documentación mientras estás programado, ya que la mayoría de editores e ides se pueden configurar para que cuando escribes una llamada a una función te salga un tooltip con los nombres de los parámetros en el prototipo.

No penséis que os vais a aprender de memoria todos los parámetros de todas las funciones que usáis en un programa, eso solo ocurre si es un programa trivial con 4 cosas, pero en uno normal, entre las funciones que has escrito tú, las que han escrito otros programadores, y las que son de las librerías que estás usando, la mayoría de las veces tienes que mirar que hay que pasarle a la función que vas a llamar, y la idea es poder consultarlo directamente en la línea de código que estás escribiendo.

Para que nos hagamos una idea, si tenemos una función que da de alta un cliente, y la ponemos así:

void nuevoCliente(char* nombre, char* apellidos, char* direccion, char* comentarios);

Cuando vayamos a usar la función, el editor nos mostrará esto:

Mientras que si ponemos:

void nuevoCliente(char, char, char, char);

Con lo cual no sabemos que va primero, el nombre, los apellidos, o qué, ya que solo vemos char char char.

Este ejemplo en particular es un poco estúpido por que para estos casos se usaría un struct pero creo que la idea se entiende.

2 1 respuesta
B

#144 Qué IDE usas?

Lo tendré en cuenta :)

edit; alguno usa Visual Studio para C?

1
HeXaN

Otro consejo: si queréis aprender, no uséis IDE/autocompletar.

Deseando ver los ejercicios que pondrás cuando llegues a punteros xD

Skiuv

¿Que IDEs gratuitos y a ser posible libres utilizáis para c/c++ análogos a lo que podría ser Netbeans o Eclipse para Java?

2 respuestas
HeXaN

#147 Code::Blocks lo usa bastante gente.

http://www.codeblocks.org/

1 1 respuesta
Skiuv

#148 Ese y el CodeLite ya los conozco pero no me acaban de convencer xDDD

1 respuesta
HeXaN

#149 Juraría que puedes usar Netbeans para programar en C también.