Teoría + Problema Propuesto

Iniciado por julianbesso1, 17 Julio 2014, 00:34 AM

0 Miembros y 1 Visitante están viendo este tema.

julianbesso1

Buenas! Acabo de encontrar este foro y pienso que seguro podrán ayudarme con mi problema:

Tengo que resolver los sig ejercicios...

A) Realice un programa para leer un arreglo lineal de N elementos conteniendo palabras de hasta 12 caracteres. Luego el programa deberá informar separadamente: a) El primero de la lista de acuerdo a un orden alfabético. b) Los elementos del arreglo que ocupan las posiciones pares. c) Las palabras que comienzan con la sílaba 'mar' .

B) Ejercicio 6.5. Escriba un programa que permita ingresar una lista de apellidos y nombres
de N personas (apellido y nombre se asignan a una sola variable). El programa debe mostrar las direcciones de correo electrónicos (emails) de ellos. El dominio asignado para ellos para el email
es: gmail.com, y el nombre de usuario se forma con la inicial del nombre y el apellido. Ejemplo: Si el dato es Gomez Nicolas, debe obtenerse: ngomez@gmail.com

...pero no cuento con ningún tipo de teoría acerca de punteros y memoria dinámica. La verdad estoy algo perdido. Me gustaría que me recomienden material para aprender de cero estos conceptos.

Desde ya, muchas gracias. Saludos!


Flakito81

Hola,
No creo que nadie te vaya a hacer esos ejercicios. Si te han puesto esa tarea se entiende que te han explicado los conceptos basicos para hacerlos. Eres tu quien debe de ponerse a pensar durante horas como resolverlo, así es la programación y más en los inicios.

Aun asi creo que te puedo dar una serie de pasos orientativos.

A)
- Declaras un array bidimensional para hacerlo dinamicamente puedes mirar en internet pero el concepto básico es:
Código (cpp) [Seleccionar]

arreglo =(char **) malloc (numero_de_palabras*sizeof(char *));
contador_palabras = 0;
while (contador_palabra < numero_de_palabras){
   arreglo[contador_palabras] = (char *) malloc (13 * sizeof(char));
}
/** NOTA: Si las palabras son de 12 caracteres hay que sumarle uno por el fin de cadena (\x0) **/
/** NOTA 2: Como para leer el nombre tienes que declarar una variable, podrias calcular el tamaño dependiendo del largo de cada palabra. Es decir leer la palabra y en el malloc que esta dentro del bucle sustituyes el 13 por un strlen(variable) + 1

- La insercion de las palabras la puedes hacer directamente al reservar la memoria y solo es usar la funcion strcpy
a) No entiendo bien lo que te piden con eso del primero de acuerdo a un orden alfabetico, pero en todo caso seria recorrer el vector e ir comparando y cuando lo encuentre lo muestras y fin. Te recomiendo que uses un bucle tipo while con alguna bandera para detectar si hay que continuar. El esquema es algo asi:
Código (cpp) [Seleccionar]

i = 0;
encontrado = 0;
while ( i < numero_de_palabras && !encontrado)
{
    if (/** comparacion que sea **/)
    {
         /** codigo que sea **/
        encontrado = 1;
    }
}


b) Un recorrido con saltos pares:
Código (cpp) [Seleccionar]

for (i = 0; i < numero_de_palabras; i+=2)
{
    /** mostrar el elemento i **/
}

c) Es una variente del caso a, piensa un poco. strncmp te ayudará


B) En este caso puedes optar por hacer un array de estructuras (me parece lo mas sencillo) o bien por un array bidimensional. Como supongo que es lo que te piden lo plantearé como un array bidimensional.
- La reserva de memoria es identido al caso A, la diferencia es que la variable con la que leias palabras tiene que ser más larga. (No te olvides del strlen)
- Lees nombre y apellido con la funcion gets o con scanf, tal que scanf("%[^\n]", variable); para que puedas leer los espacios en blanco
- una vez cargados los nombres y apellidos:
-- la posicion 0 es la primeria inicial del nombre
-- la siguiente posicion al espacio en blanco es la primera letra del apellido. Puedes calcular esa posicion recorriendo el vector y cuendo lo encuentres vas mostrando los caracteres encontrados (es una manera simple de hacerlo, aunque no la más alegante)
-- finalmente muestras @gmail.com

Estructura ""pseudocodigo"":
Código (cpp) [Seleccionar]

para todas las palabras hacer
   mostrar arreglo[i][0];
   j =  buscar_espacio_en_blanco(arreglo[i])
   mientras no final de cadena
      mostrar(arreglo[i][j+1])
      incremeto j
   fin_mientras
   mostrar "@gmail.com"
   mostrar_salto_de_linea
  incremento i
fin_para


Los trozos de codigo estan pensados en C, si quieres hacerlo en C++ tienes que investigar el new, en vez del malloc, utilizar los metodos de la clase string en vez de los str[...], en fin ... solo es una orientacion, de ti depende hacerlo.

Suerte!

julianbesso1

Está bien. No era mi intención que me den la solución. La idea era empezar de cero a ver la teoría de esos contenidos. Esto es lo que tengo hasta ahora del primer ejercicio:

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;

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

int c, palabras=0, ac=0;
char pal[13], menor[13]="zzzzz";
char *p;
cout<<"Cantidad de palabras a ingresar: ";
cin>>c;
cout<<"(Recuerde que solo pueden contener hasta 12 caracteres) "<<endl<<endl;
p=new char[c*13];

for(int i=0; i<c*13; i++){
p[i]=' ';
}

        while(palabras<c+1){
cin.getline(pal, 13);
strcpy(&p[ac], pal);
ac+=strlen(pal)+1;
palabras++;
if(strcmp(menor,pal)>0){
strcpy(menor,pal);
}
}

for(int i=0; i<c*13; i++){
cout<<p[i];
}

puts(menor);

return 0;
}


El problema es que puts no devuelve nada. No puedo deducir el motivo. Alguien?

leosansan

#3
Cita de: julianbesso1 en 20 Julio 2014, 03:46 AM
El problema es que puts no devuelve nada. No puedo deducir el motivo. Alguien?

"Creo" que es un problema de limpiar el buffer. Mira a ver así:

Código (cpp) [Seleccionar]
 while (cin.get() != '\n');
 while(palabras<c){
   cin.getline(pal, 13);
   strcpy(&p[ac], pal);
*************************  
 cout<<endl<<menor<<endl;
*************************


Citar
Cantidad de palabras a ingresar: 5
(Recuerde que solo pueden contener hasta 12 caracteres)

dsa
menor= dsa
sad
asd
menor= asd
adf
menor= adf
aas
menor= aas
dsa sad asd adf aas
aas


Y por cierto, ¿por qué usas puts con la consiguiente inclusión de la librería stdio en lugar del cout que previamente si has utilizado?.

¡¡¡¡ Saluditos! ..... !!!!



julianbesso1

#4
Primero quiero agradecer la buena predisposición que tienen para ayudarme a terminar :)

Lamentablemente, me sigue devolviendo lo mismo. Parece ser que dentro del bulce while ocurre algo que luego no me deja imprimir la cadena menor

while(palabras<c+1){
cin.getline(pal, 13);
strcpy(&p[ac], pal);
ac+=strlen(pal)+1;
palabras++;
if(strcmp(menor,pal)>0){
strcpy(menor,pal);
}
}


Aclaro que puse palabras<c+1 porque solo poniendo <c me deja ingresar una palabra menos (creo que se debe a getline)
Quedo a la espera de alguna solución.
Gracias!!!

CalgaryCorpus

Sugiero que pongas las entradas y salidas que obtienes versus la que esperas. Decir que obtienes "lo mismo" no es clarificador, en mi opinion.
Aqui mi perfil en LinkedIn, invitame un cafe aqui

leosansan

#6
Cita de: julianbesso1 en 21 Julio 2014, 01:41 AM
Primero quiero agradecer la buena predisposición que tienen para ayudarme a terminar :)
Lamentablemente, me sigue devolviendo lo mismo. Parece ser que dentro del bulce while ocurre algo que luego no me deja imprimir la cadena menor
................................................
Aclaro que puse palabras<c+1 porque solo poniendo <c me deja ingresar una palabra menos (creo que se debe a getline)
Quedo a la espera de alguna solución.
...............................................

En realidad estas confirmando al poner c+1 que un cin se lleva por delante el '\n' del primer cin, lo que indica que hay que hacer limpieza del buffer, de ahí lo que te indiqué en el mensaje anterior.

A mí si me funciona como te indiqué, que te amplio para que lo veas mejor:

Código (cpp) [Seleccionar]
******************
 p=new char[c*13];
 for(int i=0; i<c*13; i++){
   p[i]=' ';
 }
 while (cin.get() != '\n');
 while(palabras<c){
   cin.getline(pal, 13);
   strcpy(&p[ac], pal);
   ac+=strlen(pal)+1;
   palabras++;
   if(strcmp(menor,pal)>0){
     strcpy(menor,pal);
     cout<<"menor parcial = "<< menor<<endl;
   }
 }
 for(int i=0; i<c*13; i++){
   cout<<p[i];
 }
 cout<<endl<<"menor final = "<<menor<<endl;
***********************


Lo único a tener en cuenta es que como haces distinción de mayúsculas y minúsculas da lugar a que, por ejemplo, "Canvas" sea menor que "anda", ya que que en código ASCII "C" es "menor" que "a".  ;)

No obstante suscribo las palabras de CalgaryCorpus:

Cita de: CalgaryCorpus en 21 Julio 2014, 02:40 AM
Sugiero que pongas las entradas y salidas que obtienes versus la que esperas. Decir que obtienes "lo mismo" no es clarificador, en mi opinion.

Pon un ejemplo en que falle o no obtengas lo esperado indicando que esperabas.

¡¡¡¡ Saluditos! ..... !!!!



julianbesso1

Lo conseguí. Me sugirieron agregar cin.ignore()

El código quedó así:

En este caso, almaceno las palabras en un único vector

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;

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

int c, palabras=0, ac=0;
char pal[13], menor[13]="zzzzz";
char *p;
cout<<"Cantidad de palabras a ingresar: ";
cin>>c;
cout<<"(Recuerde que solo pueden contener hasta 12 caracteres) "<<endl<<endl;

p=new char[c*13];

for(int i=0; i<c*13; i++){
p[i]=' ';
}

cin.ignore();

while(palabras<c){
cin.getline(pal, 12);
strlwr(pal);  //  pasa pal a minusculas para luego comparar con 'mar'
strcpy(&p[ac], pal);
ac+=strlen(pal)+1;
palabras++;
if(strcmp(menor,pal)>0){
strcpy(menor,pal);
}
}
/* //comprobación del vector
for(int i=0; i<c*13; i++){
cout<<p[i];
}

cout<<endl;
*/
cout<<"\nLa palabra que aparece primero segun orden alfabetico es: ";
puts(menor);

cout<<endl<<endl;

cout<<"Los elementos de las posiciones pares son: "<<endl<<endl;

for(int j=2; j<c*13; j+=2){
puts(&p[j]);  //  si se utiliza 'cout' los resultados son distintos (debido a que las palabras se insertan en un único vector)
}

cout<<"Las palabras que contienen la cadena 'mar' son: "<<endl<<endl;

for(int k=0; k<c*13; k++){
if(strncmp(&p[k],"mar", 3)==0)
puts(&p[k]);  //  muestras todas las veces que aparece 'mar' (debido a que las palabras se insertan en un único vector)
}

delete p;

return 0;
}


Mi idea en este momento, es reescribirlo de tal manera que las palabras se almacenen en una matriz dinámica (1 palabra por fila).

Tengo esto:

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;

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

int c, pal=0;
char menor[13]="zzzzz";
cout<<"Cantidad de palabras a ingresar: ";
cin>>c;
cout<<"(Recuerde que solo pueden contener hasta 12 caracteres) "<<endl<<endl;

char** p=new char*[c];

for(int h=0; h<c; h++){
p[h]=new char[13];
}
/*
for(int i=0; i<c; i++){
for(int j=0; j<13; j++){
p[i][j]=' ';
}
}
*/
cin.ignore();

while(pal<c){
cin.getline(p[pal], 12);
strlwr(p[pal]);  //  pasa pal a minusculas para luego comparar con 'mar'
pal++;
if(strcmp(menor,p[pal])>0){
strcpy(menor,p[pal]);
}
}
/* //comprobación del vector
for(int i=0; i<c*13; i++){
cout<<p[i];
}

cout<<endl;
*/
cout<<"\nLa palabra que aparece primero segun orden alfabetico es: ";
puts(menor);

cout<<endl<<endl;

cout<<"Los elementos de las posiciones pares son: "<<endl<<endl;

for(int j=0; j<c; j+=2){
puts(p[j]);  //  si se utiliza 'cout' los resultados son distintos (debido a que las palabras se insertan en un único vector)
}

cout<<"\nLas palabras que contienen la cadena 'mar' son: "<<endl<<endl;

for(int k=0; k<c; k++){
if(strncmp(p[k],"mar", 3)==0)
puts(p[k]);  //  muestras todas las veces que aparece 'mar' (debido a que las palabras se insertan en un único vector)
}

for(int l=0; l<c; l++){
delete[] p[l];
}

delete[] p;

return 0;
}


Compilé y resulto bien solo la primera vez. Cada vez que ingreso las palabras me aparece el mensaje: [nombre_del_archivo] dejó de funcionar. Por si es de utilidad, estoy trabajando con Windows 7 64b.

Me gustaría que se fijen bien el tema de asignación dinámica y doble punteros. Recién estoy aprendiendo, así que no estoy muy seguro del uso de new y delete.

Gracias de antemano!

eferion

Estás programando en C++... no uses includes de C (los que acaban en .h). La librería de C++ dispone de herramientas más que suficientes como para no tener que depender de la librería de C.

Por ejemplo, para manejar cadenas de caracteres en C++ lo suyo es usar la clase "string". Es mucho más segura y sencilla de manejar que los arreglos de C.

Otro ejemplo podría ser usar el contenedor "vector" en vez de memoria dinámica a pelo...

Además, tu código tiene algunos errores:

Código (cpp) [Seleccionar]

while(pal<c){
cin.getline(p[pal], 12);
strlwr(p[pal]);  //  pasa pal a minusculas para luego comparar con 'mar'
pal++; // <<<<<<-------- AQUI!!!!!
if(strcmp(menor,p[pal])>0){
strcpy(menor,p[pal]);
}
}


Si incrementas "pal" antes de hacer la comparación... estás comparando menor con una cadena no definida!!!!


julianbesso1

Si. Me dí cuenta tarde. Igual ya había logrado que funcione reemplazando el bucle while por un for. Muchas gracias por su ayuda