Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - K-YreX

#491
Respecto a tu primer mensaje (para no citarlo entero):
Bueno ya empieza a coger forma aunque hay que terminar de pulir ese código...
El primer error lo tienes en la función <pedirNombre()>. Aunque antes has visto que era equivalente pasar una variable por referencia que pasar un puntero ya que ambas son direcciones de memoria, no es exactamente lo mismo. Por lo que tienes que cambiar el parámetro de un <char> por referencia a un puntero de <char>. Es decir la función debe quedar así:
Código (cpp) [Seleccionar]

int pedirNombre(char*);

No olvides cambiarlo tanto en el prototipo de la función como abajo en la implementación.

Otro error lo tienes en la línea 22: Tenemos una función que debe recibir un puntero a <char> (porque cuando pasamos un array como parámetro lo que pasamos en realidad es un puntero de la primera posición del array) y tú le estás pasando <usuario[30]> que es la posición 30 del array <usuario>, es decir, le estás pasando un <char> (que además está fuera de los límites ya que si el tamaño es 30, las posiciones del array irían del 0 al 29 incluidos). En este caso solo se escribe el nombre del array tal que:
Código (cpp) [Seleccionar]

longitud = pedirNombre(usuario);


Hasta aquí los errores como tal. Una vez corregido eso, el programa ya funcionaría.


Y aquí un par de consejos o trucos:
  • Como antes te he comentado, hay que evitar las variables globales. Por tanto no deberíamos tener las líneas 12 y 13. El nombre de un array corresponde a un puntero que apunta a la primera posición del array. En tu caso:
    Código (cpp) [Seleccionar]

    // creamos un array de <int>
    int vocales[5] = {0}; // Con esto se inicializa la primera posicion al valor que indiques y el resto a 0 por lo tanto todo a 0
    int *puntero = &vocales[0]; // hacemos que <puntero> apunte al comienzo de <vocales>
    // Ahora tenemos dos punteros que apuntan a <vocales[0]>. Uno es <puntero> y el otro es <vocales> (<vocales> equivale a <&vocales[0]> por lo que podemos hacer:)
    int *puntero = vocales; // esto equivale a lo anterior
    // O directamente podemos usar <vocales> y nos ahorramos un puntero global que no nos traera nada bueno


  • La aritmética de puntero no es lo más cómodo digamos. Por lo tanto a no ser que te lo exijan o te guste, puedes usar la indexación:
    Código (cpp) [Seleccionar]

    vocales[i]
    *(vocales+i)

    Estás dos sentencias son exactamente lo mismo. Siempre puedes pasar de una nomenglatura a la otra. Y sí se pueden incrementar punteros pero debes usar paréntesis:
    Código (cpp) [Seleccionar]

    int vocales[5] = {1,2,3,4,5};
    int *puntero = vocales;
    ++puntero; // ahora <puntero> apunta a la siguiente posicion
    ++(*puntero); // ahora incrementamos el valor al que apunta <puntero> que es <vocales[1]> entonces <vocales> = {1,3,3,4,5}
    ++(*(puntero+1)); // incrementamos el valor de la siguiente posicion a la que apunta <puntero>. Ahora <vocales> = {1,3,4,4,5}

    Esto es igual para el -- y tanto si lo ponemos en prefijo como en sufijo.

    Por lo tanto creo que lo mejor es:
  • Crear el array <char nombre[30]> en el <main>
  • Crear el array <int vocales[5]> en el <main>
  • Usar una función <int pedirNombre(char *nombre)> para pedir el nombre al usuario y obtener su longitud.
  • Usar una función <void contarVocales(char *nombre, int longitud, int *vocales)> para contar las vocales.
    Así consigues resolver el programa sin variables globales, sin memoria dinámica y usando únicamente 2 variables (<nombre> y <vocales>) :-X




    Respecto a tu segundo mensaje:
    Te sugiero que modifiques lo que te comento más arriba en tu primer código para no meterte con memoria dinámica (<new>). Es mejor que primero aprendas bien a pasar los parámetros antes de nada.
#492
Lo primero, para tu próxima consulta (o si quieres puedes modificar tu mensaje para añadirlo), coloca tu código entre etiquetas de código GeSHi. Esto hace el código más fácil de ver y evita algunos problemas de etiquetas.


Ahora vamos parte a parte... AVISO: Va a ser un mensaje extenso y con bastante contenido.
Empezando por las librerías: no uses la librería <conio.h>. Esta librería no es estándar por la que no siempre se puede compilar un programa que la incluye. Además sólo la usas para <getch()> (esto lo puedes sustituir por <cin.get()> que pertenece a la librería <iostream> y así ya no la necesitas y el programa sigue igual). Y aunque sea un tema menor, la convención del <.h> en las librerías es típico de C (para C++ empieza por <c> y no lleva <.h>) Ej: <stdlib.h> (C) -> <cstdlib> (C++)

Citar
Tengo un cacao con eso, debo o no debo poner las variables globales dentro del parentesis?¿ por lo que se si lo hago sin ser un puntero y no utiliza & pasaría una copia del valor (para asi no modificar el valor de la variable y usarlo en otra funciones si hace falta) pero en los punteros no veo la diferencia la verdad.
Lo siguiente que vamos a ver es el scope o alcance de una variable y su tiempo de vida. Una variable existe dentro de la función donde se declara y se "destruye" cuando acaba esa función (esto es así también para el <main> que no deja de ser una función) y para poder usarla en otra función debemos mandársela de alguna manera (uso de parámetros). Una variable global existe durante toda la ejecución del programa y es accesible en cualquier punto del programa, por lo que una variable global no es necesario mandarla como parámetro. Por esto último, una variable global se puede modificar desde cualquier lugar y hay que evitar su uso. Se pueden usar variables globales o más bien constantes para determinar valores predefinidos.

Citar
PD: he declarado los punteros de forma global por que no se otra forma de pasarlos a otra función y no se si puede pasar mas de un valor por el return (todos los ejemplos que he visto solo pasan 1 dato por el return).
Un <return> sólo devuelve un valor. Este puede ser un valor de tipo <int>/<char>/... o también puede ser un puntero. Por ejemplo para arrays/arreglos/vectores (las 3 son lo mismo). Existe la excepción de usar el tipo <pair> de la STL que es un par de datos. Por lo que podríamos devolver 2 o más si concatenamos un <pair> dentro de otro. Esto no es lo más habitual y no será necesario tirar de ello pero para que lo conozcas... Como regla general: el <return> devuelve un valor.

En C++ existe lo que es el paso por referencia (lo opuesto al paso por valor). Un parámetro pasado por valor, crea una copia dentro de la función por lo que su valor original no se ve alterado una vez estamos fuera de esa función. En cambio, un parámetro pasado por referencia manda la dirección de memoria original por lo que si su valor se altera dentro de la función, este también se verá alterado fuera. Los punteros guardan direcciones de memoria por lo que pasar un puntero como parámetro es como pasar la dirección de memoria del dato al que apunta (que es equivalente a pasar el dato por referencia).
Código (cpp) [Seleccionar]

int incrementar(int a){
    return ++a;
}
int a = 2;
int b = incrementar(a);

En este caso hemos pasado el parámetro por valor por lo que el original no cambia. (No voy a entrar en el tema de poner ++ antes o después del nombre ya que el resultado varía). La función hace una copia de <a>, la incrementa, se la asigna a <b> y al acabar la función la copia de <a> se "destruye" (porque su alcance sólo existe dentro de la función). Así que a == 2 y b == 3.

Código (cpp) [Seleccionar]

int incrementar(int &a){
    return ++a;
}
int a = 2;
int b = incrementar(a);

En este caso lo estamos pasando por referencia por lo que sí cambia. La función recibe la dirección de memoria de <a> por lo tanto no es ninguna copia. Incrementa <a>, se lo asigna a <b> y se acabó. No hay copia por lo que no se "destruye". Entonces a == 3 y b == 3.

Código (cpp) [Seleccionar]

int incrementar(int *p){
    return ++(*p);
}
int a = 2:
int *pa = &a;
int b = incrementar(pa);

Aquí <pa> tiene como valor la dirección de memoria de <a>. La función recibe un puntero POR VALOR por lo que se hace una copia de su contenido (entonces se copia la dirección de <a> que es el contenido de <pa>). Si te das cuenta al final la función está trabajando con la dirección de memoria de <a> al igual que en el caso anterior por lo que esto es equivalente a hacer un paso por referencia de <a>. El valor entonces es a == 3 y b == 3.

También se puede pasar un puntero por referencia. Esto únicamente será necesario para trabajar sobre la dirección de memoria en la que está el puntero, NO A LA QUE APUNTA (nótese la diferencia, una variable está en una dirección de memoria y guarda un valor pero un puntero está en una dirección de memoria y guarda otra dirección de memoria). Y sólo se trabaja sobre la dirección de memoria del puntero para reservar memoria y liberarla (<new> y <delete>).


Y finalmente vamos a tu problema en concreto. Aunque en tu caso parece que sólo <*p_a> tiene un valor incorrecto, en realidad el fallo es bastante más grande. Entre el vector <usuario> que es local y se "destruye" al terminar la función y la mezcla de punteros globales con direcciones de memoria temporales como lo son las variables para contar las vocales, internamente hay un montón de errores de saltos que dependen de valores no inicializados, posiciones de escritura no válidas...

Creo que la mejor opción que tienes para no modificar mucho tu programa es:
1. Crear el array <nombre> en el <main>. Pasárselo a una función como parámetro y pedir un nombre al usuario. Devolver el tamaño de <nombre>.
2. Usar una función que reciba como parámetros el array <nombre>, la longitud, y una de estas dos opciones:
  • 5 variables por referencia declaradas en el <main> usadas como contadores.
  • Un array de <int> de tamaño 5 que equivale a juntar las 5 variables de la otra opción en un array.

    Prueba los códigos que te he comentado antes y las cosas que no te hayan quedado muy claras y si tienes algún problema de nuevo, no dudes en preguntar pero por favor con el código entre etiquetas de código GeSHi... :-X :-X
#493
Lo primero de todo: El código entre etiquetas de código GeSHi   :-X :-X

Algunos consejos y cosillas que te pueden servir de ayuda;
  • No uses <stdio.h>. Esta librería es típica de C, no de C++ (en C++ es <cstdio>) y además no la usas para nada. Usas las entradas/salidas de <iostream> por lo que no la necesitas. Hay que saber lo que se pone y por qué se pone.
  • Sobre el <cout> y el <endl>: Se pueden concatenar estos últimos y no es necesario poner unas comillas vacías para usarlo por separado. También puedes usarlo antes de una cadena y después. Además puedes usar el caracter especial "\n" para saltos de línea (hay una sútil diferencia entre "\n" y <endl> pero bueno...)
    Código (cpp) [Seleccionar]

    cout << "Texto" << endl;
    cout << "Texto" << endl << endl << endl;
    cout << endl;
    cout << endl << "Texto" << endl;
    cout << "\nTexto" << endl;


    Ahora los errores de tu programa:
  • No estás usando un array/arreglo bidimensional. Esto es una matriz y se declara con dos parejas de corchetes: <tipo> <nombre_matriz>[<filas>][<columnas>].
  • Estás acumulando valores (notas) en <suma> pero no has inicializado <suma> por lo que puede tener cualquier valor.
  • Debes guardar todas las notas y al no usar una matriz, una vez que has utilizado las notas de un alumno, las pierdes porque guardas las notas del siguiente.

    Todos los ejercicios de este tipo tienen una forma estándar de hacerlos que es la siguiente:
    Código (cpp) [Seleccionar]

    #include <iostream>

    using namespace std;

    // Usamos constantes y asi podemos agrandar o reducir los valores del programa sin tener que modificarlo entero
    const int MAX_ALUMNOS = 100; // numero maximo de alumnos que podemos tratar
    const int NUM_NOTAS = 3; // numero de notas por alumno

    int main(){
        // Creamos una matriz. Cada fila son las notas de un alumno y cada columna es una nota
        double notas[MAX_ALUMNOS][NUM_NOTAS];
        int num_alumnos; // numero de alumnos que vamos a tratar. Debe ser menor o igual que <MAX_ALUMNOS>
       
        // El promedio de cada alumno podemos guardarlo (necesitamos un array/arreglo mas entonces) o calcularlo y sobrescribirlo para cada alumno
        double promedio[MAX_ALUMNOS] = {0}; // arreglo para guardarlos con cada celda inicializada en 0
        double promedio = 0; // si no queremos guardarlos, basta con esto. Inicializamos a 0 para poder acumular luego ahi las notas

        // Podemos hacer un filtro para obtener el numero de alumnos a tratar
        // El filtro te pide un valor y te lo sigue pidiendo mientras se cumpla la condicion del <while>
        do{
            cout << "Introduce el numero de alumnos: ";
            cin >> num_alumnos;
        }   while(num_alumnos < 1 || num_alumnos > MAX_ALUMNOS);
        // El programa no pasara el filtro hasta que <num_alumnos> este entre 1 y <MAX_ALUMNOS>
        // A partir de ahora usaremos <num_alumnos> en lugar de <MAX_ALUMNOS>

        // Pedimos las notas de cada alumno
        for(size_t i = 0; i < num_alumnos; ++i){
            cout << "Notas del alumno " << i+1 << endl;
            for(size_t j = 0; j < NUM_NOTAS; ++j){
            // Pedir cada nota
            }
            // Si vamos a guardar todos los promedios en un arreglo, podemos calcularlos aqui
        }
       
        // ...El resto del programa...
    }


    Yo creo que ya tienes una ayuda bastante grande con el programa. Ahora te queda terminarlo a ti (tampoco te lo iba a hacer entero...  :silbar:)
    Si tienes algún problema en alguna parte, coloca tu código (entre etiquetas de código GeSHi) para que podamos ayudarte.
#494
Cita de: dominicanvictor en  8 Agosto 2019, 19:04 PM
Así voy ahora, pero tengo ciertos errores con el modulo 1
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>



#define L_CLAVE 7
#define L_DESCRIPCION 20
#define L_BUFFER 100


struct producto {
char clave[L_CLAVE];
char descripcion[L_DESCRIPCION];
float precio;
};


void captura_producto(){

producto prod;
char buffer[L_BUFFER];

clrscr();
printf("Captura de producto\n\n");


/* captura de clave de producto */
printf("Clave: ");
gets(buffer);
if (strlen(buffer)<=L_CLAVE){
strcpy(prod.clave, buffer);
}
else{
printf("Error en captura de clave");
}

/* captura de descripcion */
printf("Descripcion: ");
gets(buffer);
if (strlen(buffer)<=L_DESCRIPCION){
strcpy(prod.descripcion, buffer);
}
else{
printf("Error en captura de descripcion");
}

/* captura de precio */
printf("Precio: ");
gets(buffer);
prod.precio = atof(buffer);

printf("\n\n\n");

printf("datos capturados\n");
printf("Clave: %s -- Decripcion: %s  Precio: %f ", prod.clave, prod.descripcion, prod.precio);

}


int main(){

captura_producto();
return 0;

}


Primero, te recomiendo no usar funciones no estándar ni librerías no estándar, en tu caso: <clrcsr()> y <conio.h> ya que según el compilador que se use no va a funcionar. Y segundo el único error que tiene ese código es que en C:

struct Producto{
    //...
};

Producto mi_producto; // ERROR!!
struct Producto mi_producto; // Correcto!!

Para no escribir siempre <struct> cuando te refieras al tipo <Producto> puedes usar <typedef>:

typedef struct Producto{
    // ...
} Producto;

Producto mi_producto; // Correcto!!

Dejar claro que así lo que haces es permitirte usar el nombre <Producto> como sustituto de <struct Producto> pero NO estás creando ninguna variable llamada <Producto> de tipo <Producto>. En cambio si quitas <typedef> y haces:

struct Producto{
    // ...
} mi_producto;

Sí estás creando ya una variable de tipo <Producto>. No te recomiendo hacer esto aunque lo verás en muchos sitios ya que entonces la variable es global y no es una buena práctica.

Otros consejos:
  • Usar <fgets()> en lugar de <gets()>
  • Usar <strncpy()> en lugar de <strcpy()>
    Las alternativas que te he puesto permiten un parámetro donde especificar la longitud. Esto hace que las funciones sean más seguras para evitar desbordamientos.
  • Si vas a comprobar si un nombre/clave/etc es demasiado larga, lo suyo sería después de avisar del error, permitir al usuario introducirlo de nuevo.

    Pero vamos que estás cosas son recomendaciones que te digo. Si lo que quieres es acabarlo cuanto antes para entregarlo y ya pues como dicen muchos "Mientras compile..."
#495
Entiendo que lo que quieres hacer es un vector de cadenas de caracteres. Entonces como una cadena de caracteres ya es un vector, pues necesitas un vector de vectores. Un vector de vectores es lo mismo que una matriz.


#include <stdio.h>

#define MAX_ARTICULOS 4
#define MAX_SIZE 100

int main(){
    char descripciones[MAX_ARTICULOS][MAX_SIZE];

    for(size_t i = 0; i < MAX_ARTICULOS; ++i){
        printf("Introduce la descripcion del articulo %d: ", i+1);
        fgets(descripciones[i], MAX_SIZE, stdin);
    }

    for(size_t i = 0; i < MAX_ARTICULOS; ++i)
        printf("Descripcion %d: %s", i+1, descripciones[i]);
}


Ahí tienes un ejemplo de cómo trabajar con vectores de cadenas. Piensa que cada línea es una cadena (una frase) y cada columna es un caracter.
Puedes probar ese pequeño código para que veas cómo funciona o intentar hacer algún cambio para entender el funcionamiento. También puedes por ejemplo pedir el número de artículos a tratar y si es menor que <MAX_ARTICULOS> usarlo como condición del bucle.
#496
No sé de dónde habrás sacado tal ejercicio pero mi respuesta después de haberle dado algunas vueltas es que no puedes encontrar una solución con esos datos. Para ello lo único que voy a hacer es ponerte un ejemplo...
Datos:

numeroLados = 4
perimetro = 20
area = 24


Solución: (Soluciones más bien :rolleyes:)

Rectangulo con base = 6 y altura = 4 (o viceversa)
Rombo con base (lado) = 5 y altura = 4.8

Puedes comprobarlo con las fórmulas... Ambas soluciones satisfacen todas las condiciones por lo que sólo con esos datos es imposible diferenciar si la figura en cuestión es un rectángulo o un rombo.

Revisa el ejercicio ya que puede que te hayas dejado alguna condición como otro dato más o que los valores sólo puedan ser enteros o algo por el estilo. O que la solución englobe al rectángulo y rombo dentro de la misma opción, es decir, distinguir entre: cuadrado, rectángulo/rombo, trapecio.
#497
Tienes que saber cuándo tienes algo en el buffer y cuando no. Si no tienes nada y pones un <getchar()> el programa espera un ENTER, entonces tienes que darlo antes de que te salga el siguiente mensaje y puedas introducir el siguiente dato. En tu caso sobran <getchar()> ya que <fgets()> guarda el ENTER dentro del nombre y no son necesarios pero si tienes problemas será que estás sobrepasando el límite de tamaño que tienes establecido.

Si cambiando el tamaño no consigues solucionarlo coloca un ejemplo de ejecución para poder verlo con más detalle.
#498
No creo que tenga ninguna complicación. En internet habrá infinidad de ejemplos al igual que en otros temas de este foro...

char nombre[50];

printf("Introduce tu nombre: ");
fgets(nombre, 50, stdin);

printf("Tu nombre es: %s", nombre); // se mostrara "Tu nombre es: <nombre>\n" (con salto de linea al final)

PD: Ten cuidado ya que <fgets()> guarda también el salto de línea de cuando das al ENTER.

Y el problema que tendrás será porque tienes cosas en el buffer (saltos de línea seguramente) y no lo limpias. Es cierto que todo el mundo usa la función <fflush(stdin)> de forma incorrecta ya que <fflush()> está diseñada para trabajar con <stdout> pero obviamente no hace lo mismo. Tienes otras alternativas para limpiar el buffer que se comentaron en un tema de este foro de C/C++.
#499
Eso es porque usas condicionales aislados. Es decir, que has utilizado un conjunto de condiciones que son independientes por lo que tu programa las comprueba todas. En estos casos en los que una coincidencia en un <if> excluye que pueda ser verdadera otra coincidencia se usa <if - else if - else if - ... - else>.

Aquí tienes un código sencillo que funciona correctamente pero que no es muy eficiente ya que se compara el valor de <numero> con 1 y coincida o no, se compara con 2 y coincida o no se comprueba que el número sea distinto de 1 y de 2:
(Sé que el código es un poco absurdo pero me parecía un buen ejemplo para mostrarte el problema)

int numero = 1;

if(numero == 1)
    printf("El numero vale 1");
if(numero == 2)
    printf("El numero vale 2");
if(numero != 1 && numero != 2)
    printf("El numero es distinto de 1 y de 2");



Se ve claramente que si el número vale 1 ya no va a valer 2 ni ningún otro valor. Por lo que se puede hacer más eficiente así:

int numero = 2;

if(numero == 1) // si vale 1...
    printf("El numero vale 1");
else if(numero == 2) // si no vale 1, si vale 2...
    printf("El numero vale 2");
else // si no vale 1 ni 2... ya se da por hecho que es distinto de 1 y de 2
    printf("El numero es distinto de 1 y de 2");

En este caso se comprueba cada <if> hasta que uno sea cierto y en el momento que uno es cierto no sigue comprobando el resto de condiciones.

En tu caso compruebas de forma aislada cada mes excepto el último y en el último haces:

si mes == "diciembre" entonces
    12  invierno
sino entonces
    prueba de nuevo
fin si

Entonces ese <sino> se ejecutará siempre que el mes no sea igual a "diciembre".
#500
Si estás empezando, hacerlo a la inversa es un poco más complicado pero te comento lo que deberías mirar:
  • Uso de cadenas de C (arrays de <char>) estáticas (también puedes usar memoria dinámica pero mejor dejar esa parte para más adelante)
  • Algunas funciones para trabajar con cadenas de C. La más útil es para comparar dos cadenas <strcmp()> y <strncmp()> (recomendable usar la segunda porque puedes indicar cuántos caracteres comparar de ambas cadenas). Además para pedir una cadena C al usuario deberás usar <fgets()> en lugar de <scanf()>. Te dejo cómo se usan:

    strcmp(const char *cadena1, const char *cadena2); -> Retorna: -1 (cadena1 < cadena2) / 0 (cadena1 == cadena2) / 1 (cadena1 > cadena2) usando el orden lexicográfico.
    strncmp(const char *cadena1, const char *cadena2, size_t longitud); -> Igual que la anterior pero compara tantos caracteres como se indica en <longitud> o hasta que una cadena termina.
    fgets(char *cadena, int longitud, FILE *stream); -> Almacena en <cadena> lo introducido por la entrada. Usar como <stream> <stdin> para la entrada estándar (teclado). <longitud> determina el número máximo de caracteres que se van a almacenar (normalmente el tamaño de <cadena>).


    Yo te recomendaría una forma poco eficiente pero más simple que sería: de forma manual hacer un bloque de <if-else-if> y en cada uno comparar la entrada con cada uno de los días de la semana (colocar de forma manual el número de caracteres a comparar según el día):

    if(strncmp(cadenaUsuario, "Lunes", 5) == 0)
        // lo que quieras hacer si es lunes
    else if(strncmp(cadenaUsuario, "Martes", 6) == 0)
        // lo que quieras hacer si es martes
    //...

    PD 1: Cuidado con las mayúsculas/minúsculas ya que hacen que una cadena con el mismo contenido se interprete como cadenas distintas.

    Echa un vistazo a lo comentado antes y anímate a intentarlo. Si tienes algún problema, envía tu código para que podamos ver el problema y ayudarte.
    PD 2: No olvides colocar los códigos entre etiquetas de Código GeSHi... :rolleyes: :-X