Problemas con mostrar un registro

Iniciado por Sword9K, 9 Abril 2020, 23:18 PM

0 Miembros y 2 Visitantes están viendo este tema.

Sword9K

Hola, es sobre un problema que estoy teniendo a la hora de mostrar unos datos con punteros, lo que pasa es que uno de los datos que ingreso se "cambia" por un carácter especial o algo así.

Aquí esta parte del código, perdón si esta asi, lo copie rápido.

Código (cpp) [Seleccionar]

#include <string.h>
#include <iostream>
#include <windows.h>
#include <conio.h>

using namespace std;

void gt(int x, int y){             // -Posicion X y Y en el Programa
HANDLE Manipulador;  //Puntero
COORD Coordenadas; //Coordenadas
Manipulador = GetStdHandle(STD_OUTPUT_HANDLE); //Contenedor del Programa
Coordenadas.X = x; //Posicion en X
Coordenadas.Y = y; //Posicion en Y
SetConsoleCursorPosition(Manipulador,Coordenadas); //Envia el Contenedor y variable para la posicion
}

void formu(){
system("cls");
gt(15,9); cout<<"Codigo: ";
gt(15,11); cout<<"Nombres: ";
gt(15,12); cout<<"Apellidos: ";
gt(15,14); cout<<"Nota 1: ";
gt(15,15); cout<<"Nota 2: ";
gt(15,17); cout<<"Su Nota Definitiva es: ";
}

struct notas{
char nom[50];
char apel[50];
char cod[50];
float n1, n2;
float defi;
}alu, *pun=&alu;

void capt();
void list();
void consul();
int ne;

int main(){
char op;
do{
system("cls");
gt(20,10); cout<<"MENU REGISTROS";
gt(22,12); cout<<"1. Capturar.";
gt(22,13); cout<<"2. Consultar registros.";
gt(22,14); cout<<"3. Salir.";

gt(23,16); cout<<char(167)<<"Digite un numero: "; op = getch();

switch(op){
case '1':
capt();
break;
case '2':
consul();
break;
case '3':
gt(6,18); cout<<"Saliendo...";
Sleep(200);
gt(5,25); exit(1);
break;
default:
gt(6,18); cout<<"Debe digitar un numero del 1 al 3...";
system("pause");
break;
}
}
while(op != '3');
}

void capt(){
system("cls");
gt(15,10); cout<<"Digite el Numero de Formularios a agregar: "; cin>>ne;
const int ju = ne;

for(int i=0;i<ju;i++){
formu();
fflush(stdin);
gt(23,9); gets((pun+i)->cod);
gt(24,11); gets((pun+i)->nom);
gt(26,12); gets((pun+i)->apel);
gt(23,14); cin>>(pun+i)->n1;
gt(23,15); cin>>(pun+i)->n2;

(pun+i)->defi=((pun+i)->n1+(pun+i)->n2)/2;
gt(38,17); cout<<(pun+i)->defi;
system("pause");
}
ne = ju;
}

void consul(){
char op;
do{
system("cls");
gt(20,10); cout<<"MENU - Consultas";
gt(22,12); cout<<"1. Listar.";
gt(22,13); cout<<"2. Volver al menu anterior";
gt(22,14); cout<<"3. Salir";

gt(23,16); cout<<"Digite un numero: "; op = getch();

switch(op){
case '1':
list();
break;
case '2':
gt(6,18); cout<<"Volviendo...";
Sleep(200);
main();
break;
case '3':
gt(6,18); cout<<"Saliendo...";
Sleep(200);
gt(5,25); exit(1);
break;
default:
gt(6,18); cout<<"Digite un numero del 1 al 3...";
system("pause");
break;
}
}
while(op != '4' || op == '2');
system("pause");
}

void list(){
system("cls");
fflush(stdin);
if((pun)->defi == 0){
gt(15, 10); cout<<"No se Encontraron Registros...";
}
else{
gt(16,8); cout<<"--- REGISTROS ---";

gt(3,10); cout<<"No.";
gt(7,10); cout<<"Codigo";
gt(17,10); cout<<"Nombre";
gt(33,10); cout<<"Apellido";
gt(47,10); cout<<"Nota 1";
gt(57,10); cout<<"Nota 2";
gt(67,10); cout<<"Definitiva";

for(int i=0;i<ne;i++){
gt(3,i+12); cout<<i+1;
gt(7,i+12); cout<<(pun+i)->cod;
gt(17,i+12); cout<<(pun+i)->nom;
gt(32,i+12); cout<<(pun+i)->apel;
gt(47,i+12); cout<<(pun+i)->n1;
gt(57,i+12); cout<<(pun+i)->n2;
gt(67,i+12); cout<<(pun+i)->defi;
}
system("pause");
}
}


Y asi me queda cuando quiero mostrar los registros.

               --- REGISTROS ---

  No. Codigo    Nombre          Apellido      Nota 1    Nota 2    Definitiva

  1   32GRE     ANDRES         SUR            45        20        32.5
  2   AH3H2     ♥              PEREZ          34        50        42
  3   4H2BG     ESTEBAN        HONZ           45        35        40Presione una tecla para continuar . . .

ThunderCls

Tu declaracion de "pun" es la siguiente:

Código (cpp) [Seleccionar]
struct notas{
char nom[50];
char apel[50];
char cod[50];
float n1, n2;
float defi;
}alu, *pun=&alu;


Significa que "pun" es simplemente un puntero a una variable de tipo estructura "notas". Luego mas adelante haces algo como:

Código (cpp) [Seleccionar]
(pun+i)->cod

Significa que estas accediendo a una posicion en memoria de la que no tienes control (intentas acceder mas alla de los limites de tu variable con pun+i). Cuando accedes a una zona de memoria no reservada, el contenido es incierto ya que tu aplicacion o cualquier otra puede usarla. Una posible solucion es declarar "pun" como un array de estructuras, o mejor aun, como un contenedor dinamico (vector, list).

He modificado solamente la declaracion y uso de la variable "pun" para que tengas una idea:

Código (cpp) [Seleccionar]
#include <string.h>
#include <iostream>
#include <windows.h>
#include <conio.h>
#include <vector>

using namespace std;

void gt(int x, int y) {             // -Posicion X y Y en el Programa
HANDLE Manipulador;  //Puntero
COORD Coordenadas; //Coordenadas
Manipulador = GetStdHandle(STD_OUTPUT_HANDLE); //Contenedor del Programa
Coordenadas.X = x; //Posicion en X
Coordenadas.Y = y; //Posicion en Y
SetConsoleCursorPosition(Manipulador, Coordenadas); //Envia el Contenedor y variable para la posicion
}

void formu() {
system("cls");
gt(15, 9); cout << "Codigo: ";
gt(15, 11); cout << "Nombres: ";
gt(15, 12); cout << "Apellidos: ";
gt(15, 14); cout << "Nota 1: ";
gt(15, 15); cout << "Nota 2: ";
gt(15, 17); cout << "Su Nota Definitiva es: ";
}

struct notas {
char nom[50];
char apel[50];
char cod[50];
float n1, n2;
float defi;
}alu;
vector<notas> pun;

void capt();
void list();
void consul();
int ne;

int main() {
char op;
do {
system("cls");
gt(20, 10); cout << "MENU REGISTROS";
gt(22, 12); cout << "1. Capturar.";
gt(22, 13); cout << "2. Consultar registros.";
gt(22, 14); cout << "3. Salir.";

gt(23, 16); cout << char(167) << "Digite un numero: "; op = _getch();

switch (op) {
case '1':
capt();
break;
case '2':
consul();
break;
case '3':
gt(6, 18); cout << "Saliendo...";
Sleep(200);
gt(5, 25); exit(1);
break;
default:
gt(6, 18); cout << "Debe digitar un numero del 1 al 3...";
system("pause");
break;
}
} while (op != '3');
}

void capt() {
system("cls");
gt(15, 10); cout << "Digite el Numero de Formularios a agregar: "; cin >> ne;
const int ju = ne;

for (int i = 0; i < ju; i++) {
struct notas nota;
formu();
fflush(stdin);
gt(23, 9); cin >> nota.cod;
gt(24, 11); cin >> nota.nom;
gt(26, 12); cin >> nota.apel;
gt(23, 14); cin >> nota.n1;
gt(23, 15); cin >> nota.n2;

nota.defi = (nota.n1 + nota.n2) / 2;
gt(38, 17); cout << nota.defi;
pun.push_back(nota);
system("pause");
}
ne = ju;
}

void consul() {
char op;
do {
system("cls");
gt(20, 10); cout << "MENU - Consultas";
gt(22, 12); cout << "1. Listar.";
gt(22, 13); cout << "2. Volver al menu anterior";
gt(22, 14); cout << "3. Salir";

gt(23, 16); cout << "Digite un numero: "; op = _getch();

switch (op) {
case '1':
list();
break;
case '2':
gt(6, 18); cout << "Volviendo...";
Sleep(200);
main();
break;
case '3':
gt(6, 18); cout << "Saliendo...";
Sleep(200);
gt(5, 25); exit(1);
break;
default:
gt(6, 18); cout << "Digite un numero del 1 al 3...";
system("pause");
break;
}
} while (op != '4' || op == '2');
system("pause");
}

void list() {
system("cls");
fflush(stdin);
if (pun.empty()) {
gt(15, 10); cout << "No se Encontraron Registros...";
}
else {
gt(16, 8); cout << "--- REGISTROS ---";

gt(3, 10); cout << "No.";
gt(7, 10); cout << "Codigo";
gt(17, 10); cout << "Nombre";
gt(33, 10); cout << "Apellido";
gt(47, 10); cout << "Nota 1";
gt(57, 10); cout << "Nota 2";
gt(67, 10); cout << "Definitiva";

for (int i = 0; i < ne; i++) {
auto nota = pun.at(i);
gt(3, i + 12); cout << i + 1;
gt(7, i + 12); cout << nota.cod;
gt(17, i + 12); cout << nota.nom;
gt(32, i + 12); cout << nota.apel;
gt(47, i + 12); cout << nota.n1;
gt(57, i + 12); cout << nota.n2;
gt(67, i + 12); cout << nota.defi;
}
system("pause");
}
}


Saludos
-[ "...I can only show you the door. You're the one that has to walk through it." – Morpheus (The Matrix) ]-
http://reversec0de.wordpress.com
https://github.com/ThunderCls/

Sword9K

Gracias.

Ya pude entender mejor donde estaba el problema de los punteros, voy a intentar hacerlo con un array de estructuras, no entiendo muy bien la libreria vector xD.

Lo del problema es que, como el puntero accedia a un memoria que no tenia reservada, me cambiaba algunas variables, por ejemplo.

Código (cpp) [Seleccionar]

void capt(){
system("cls");
gt(15,10); cout<<"Digite el Numero de Formularios a agregar: "; cin>>ne;
const int ju = ne;

for(int i=0;i<ju;i++){
formu();
fflush(stdin);
gt(23,9); gets((pun+i)->cod);
gt(24,11); gets((pun+i)->nom);
gt(26,12); gets((pun+i)->apel);
gt(23,14); cin>>(pun+i)->n1;
gt(23,15); cin>>(pun+i)->n2;

(pun+i)->defi=((pun+i)->n1+(pun+i)->n2)/2;
gt(38,17); cout<<(pun+i)->defi;
system("pause");
}
ne = ju;
}


Con ne, la variable para pedir el numero de formularios para el for, como que cambiaba su valor y no salia del for, por eso agregue una constante "const int ju", digamos para solucionarlo y que su valor no cambiara, pero aun asi tambien cambiaba los demas valores.

Ya lo unico que me no entiendo es,  si pongo un numero cualquiera en el for, ya me salen los datos bien. Como ejemplo, pongo que solo se hagan 3 formularios, y eso ya arregla el problema.

Código (cpp) [Seleccionar]

void capt(){
system("cls");

for(int i=0;i<3;i++){
formu();
fflush(stdin);
gt(23,9); gets((pun+i)->cod);
gt(24,11); gets((pun+i)->nom);
gt(26,12); gets((pun+i)->apel);
gt(23,14); cin>>(pun+i)->n1;
gt(23,15); cin>>(pun+i)->n2;

(pun+i)->defi=((pun+i)->n1+(pun+i)->n2)/2;
gt(38,17); cout<<(pun+i)->defi;
system("pause");
}
}


RayR

Primero, algunas sugerencias/correciones. fflush(stdin) es incorrecto. La función fflush sólo se debe usar para flujos de salida, como stdout. Hacerlo con stdin es una violación a las reglas del propio lenguaje y aunque te pueda funcionar en Windows (en los otros sistemas operativos falla), no hay garantía de que siempre lo haga. En C++, una forma de limpiar el buffer es:
Código (cpp) [Seleccionar]
#include <limits>
...
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

O al estilo C, con while y getchar. Son básicamente las únicas maneras correctas de hacerlo. A veces recomiendan una con fseek, pero es tan incorrecta como fflush(stdin).
También deberías evitar gets. Es una función insegura y que desde hace años ya no es parte oficial de C o C++, y algunos compiladores incluso te darán error. En su lugar usa getline, cin.getline, o fgets.

En cuanto a tu problema, como ya te comentaron, es un error acceder a memoria que no reservaste. pun+1, pun+2, etc. apuntan a direcciones de memoria que no deberías tocar. Lo que sucede cuando lo haces es que estás escribiendo a direcciones que podrían estar ocupadas por otras variables (o que otras variables van a ocupar más adelante en la ejecución de tu programa), e incluso puedes ocasionar que tu programa se cierre inesperadamente, al estar accediendo a memoria que el sistema operativo no reservó para tu programa.

En tu caso, por lo que comentas, lo que debe estar pasando es que ptr+1 se refiere a la dirección de memoria ocupada por ne. Por lo tanto, cuando modificas ne, a la vez estás modificando un campo de ptr+1, y viceversa. Al usar la variable ju, evitas que tus gets modifiquen indirectamente a ne, pero al final de esa función, en la línea: ne = ju; al modificar ne, indirectamente estás modificando un campo de ptr+1, y de ahí los símbolos que mencionas. Por cierto, ju ni siquiera necesitaba ser const. Al ser variable local de capt, se encontrará en una posición de la memoria algo alejada de alu, que es variable global, por lo que no se superponen. Además, el calificador const sólo impide que en tu código manualmente modifiques la variable, pero todavía se puede modificar indirectamente si tienes un puntero a su dirección. De cualquier forma, el problema es que jamás debes acceder a memoria que no hayas reservado. Aunque algunas veces un programa que lo haga parezca funcionar correctamente, nunca es así. Internamente modifica algo que no debería y eventualmente causará problemas.

Sword9K

#4
gracias, ya he podido arreglar el programa. Sobre el problema, lo hice con el depurador y vi que, al poner un numero en el for, al menos el ciclo si terminaba, si utilizaba ne, después de usar pun+i, cambiaba el valor de ne y no terminaba, o cambiaba el valor de los string.

En el programa deje solo un puntero en el struct.

Código (cpp) [Seleccionar]

struct notas{

...

}*pun;


y luego en la funcion capt(), puse un arreglo dinamico.

Código (cpp) [Seleccionar]

void capt(){
system("pause");
gt(15,10); cout<<"Digite el Numero de Formularios a agregar: "; cin>>ne;

pun = new notas [ne];

for(int i=0;i<ne;i++){
...
}


Ademas, cambie el fflush() con el cin.ignore() y utilice el cin.getline() con los punteros.