Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Infraccion en acceso

Estas en el tema de Infraccion en acceso en el foro de C/C++ en Foros del Web. Hola tengo el siguiente codigo: @import url("http://static.forosdelweb.com/clientscript/vbulletin_css/geshi.css"); Código C++: Ver original #include "stdafx.h"   struct _nodo {     int numero ;     _nodo ...
  #1 (permalink)  
Antiguo 10/06/2013, 07:24
Avatar de patilanz  
Fecha de Ingreso: enero-2012
Mensajes: 880
Antigüedad: 12 años, 3 meses
Puntos: 29
Infraccion en acceso

Hola tengo el siguiente codigo:

Código C++:
Ver original
  1. #include "stdafx.h"
  2.  
  3. struct _nodo{
  4.     int numero;
  5.     _nodo *siguiente;
  6. };
  7.  
  8. void add(struct _nodo *&p);
  9. int main(void){
  10.     struct _nodo *principio;
  11.     principio=new struct _nodo;
  12.     add(*&principio);
  13.     fflush(stdin);
  14.     printf("\nEl numero es: %d",principio->numero);
  15. }
  16.  
  17. void add(struct _nodo *&p){
  18.     struct _nodo *nuevo_nodo;
  19.     struct _nodo *aux;
  20.     nuevo_nodo=new struct _nodo;
  21.     aux=new struct _nodo;
  22.     printf("Escriba un numero: ");
  23.     scanf_s("%d",&nuevo_nodo->numero);
  24.     nuevo_nodo->siguiente=NULL;
  25.     if(p!=NULL){
  26.         aux=p;
  27.         while(aux->siguiente!=NULL){
  28.             aux=aux->siguiente;
  29.         }
  30.         aux->siguiente=nuevo_nodo;
  31.     }else{
  32.         p=nuevo_nodo;
  33.     }
  34. }


El problema es que en la linea del while al ejecutar el programa me muestra este error:

Código error:
Ver original
  1. Excepción no controlada en 0x0125149F en test listas 2.exe: 0xC0000005: Infracción de acceso al leer la ubicación 0xCDCDCDD1.

El codigo lo copie de un libro de c/c++ . No se que esta mal?
  #2 (permalink)  
Antiguo 10/06/2013, 13:11
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 11 años, 8 meses
Puntos: 83
Respuesta: Infraccion en acceso

"...El codigo lo copie de un libro de c/c++ ...."

Me da la impresion que el original no debia ser asi, no se es lo que me parece. Voy a seguir el flujo de datos de tu codigo para ver lo que hace:

Código:
struct _nodo *principio;
principio = new struct _nodo;//bloqueas mem para un nodo
    
add(principio);//envias el nodo a la funcion
Cuando bloqueas memoria (dinamica o estatica dentro de funciones) se asigna un bloque de memoria que no necesariamente es nulo, es decir que puede contener datos basura de otros usos de ese bloque de memoria. Si bloqueas memoria y no la inicializas entonces no puedes usar los comparadores contra nulo porque pueden no funcionar (lo normal es que no funcionen). Sigo con el flujo sin corregir lo de inicializar:

Código:
//dentro de 'add'
...
if(p != NULL) {
        aux = p;
        while(aux->siguiente != NULL) { //violacion de acceso en el 2º ciclo
            aux = aux->siguiente;
        }
....
El 'p' es el nodo que creaste en el main pero no inicializaste sus campos, es decir que contienen datos basura (con mucha suerte seran nulos, pero no es lo normal); la comprovacion aux->siguiente != NULL se cumple cuando los datos basura del 'p' no inicializado no son nulos (es decir casi siempre por no decir siempre); en el primer ciclo se cumple porque no inicializaste a nulo el 'p->siguiente', luego asignas 'aux->siguiente' a 'aux' y entras en el segundo ciclo suponiendo que 'aux' esta apuntando a una direccion de memoria accesible por la aplicacion cuando en verdad esta apuntando a una direccion de memoria basura no accesible (o de momento no accesible), por eso cuando intentas buscar el campo 'siguiente' de un bloque de memoria no accesible se produce la violacion de acceso.

Por que crees que en la funcion 'add' estas asignando nulo a nuevo_nodo->siguiente? Por eso mismo, para no dejar datos no inicializados.

Otra cosa, fflush() no sirve para stdin (echa un vistazo a cualquier manual de la funcion fflush). Y la funcion main es de tipo entero por lo que debe retornar un entero.

Saludos
vosk
  #3 (permalink)  
Antiguo 10/06/2013, 14:15
Avatar de patilanz  
Fecha de Ingreso: enero-2012
Mensajes: 880
Antigüedad: 12 años, 3 meses
Puntos: 29
Respuesta: Infraccion en acceso

Cita:
Iniciado por vosk Ver Mensaje
"...El codigo lo copie de un libro de c/c++ ...."

Me da la impresion que el original no debia ser asi, no se es lo que me parece. Voy a seguir el flujo de datos de tu codigo para ver lo que hace:

Código:
struct _nodo *principio;
principio = new struct _nodo;//bloqueas mem para un nodo
    
add(principio);//envias el nodo a la funcion
Cuando bloqueas memoria (dinamica o estatica dentro de funciones) se asigna un bloque de memoria que no necesariamente es nulo, es decir que puede contener datos basura de otros usos de ese bloque de memoria. Si bloqueas memoria y no la inicializas entonces no puedes usar los comparadores contra nulo porque pueden no funcionar (lo normal es que no funcionen). Sigo con el flujo sin corregir lo de inicializar:

Código:
//dentro de 'add'
...
if(p != NULL) {
        aux = p;
        while(aux->siguiente != NULL) { //violacion de acceso en el 2º ciclo
            aux = aux->siguiente;
        }
....
El 'p' es el nodo que creaste en el main pero no inicializaste sus campos, es decir que contienen datos basura (con mucha suerte seran nulos, pero no es lo normal); la comprovacion aux->siguiente != NULL se cumple cuando los datos basura del 'p' no inicializado no son nulos (es decir casi siempre por no decir siempre); en el primer ciclo se cumple porque no inicializaste a nulo el 'p->siguiente', luego asignas 'aux->siguiente' a 'aux' y entras en el segundo ciclo suponiendo que 'aux' esta apuntando a una direccion de memoria accesible por la aplicacion cuando en verdad esta apuntando a una direccion de memoria basura no accesible (o de momento no accesible), por eso cuando intentas buscar el campo 'siguiente' de un bloque de memoria no accesible se produce la violacion de acceso.

Por que crees que en la funcion 'add' estas asignando nulo a nuevo_nodo->siguiente? Por eso mismo, para no dejar datos no inicializados.

Otra cosa, fflush() no sirve para stdin (echa un vistazo a cualquier manual de la funcion fflush). Y la funcion main es de tipo entero por lo que debe retornar un entero.

Saludos
vosk

Muchas gracias, lo que me explicaste no tenia ni idea de esto. Ahora ya lo corregi asignando a principio->siguiente=NULL

La funciona main es de tipo entero pero igual funciona sin que retorne nada. Para que es necesario que retorne algo?

Lo de fflush() vi un tutorial. No sabia que se usa para vaciar el buffer de los ficheros. Yo lo utilizo para vaciar el buffer del teclado. Esto se explica en el libro, y el stdin no se para que se pone.

Saludos
  #4 (permalink)  
Antiguo 10/06/2013, 15:37
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 11 años, 8 meses
Puntos: 83
Respuesta: Infraccion en acceso

El main funciona sin que retorne nada porque te lo autocompleta el compilador. El retorno de main es un valor referente a la ejecucion, y se toma por defecto 0 para indicar que la aplicacion terminó correctamente. Si p.ej. tu aplicacion necesita bloquear memoria pero no hay suficiente, en vez de retornar 0 retornas 1 para indicar que no termino correctamente (es decir, terminó sin fallos pero no pudo iniciar o no pudo completar la tarea que se esperaba), luego en el manual de tu aplicacion indicas que retorna 1 cuando no encuentra memoria disponible. Cuando A llama a B para que manipule los datos C, si B retorna !=0 es que A no puede retomar los datos C porque en B se produjo algun error. Si siempre retornas 0 implicará que tu aplicacion siempre funciona correctamente. Seguramente habras visto la funcion 'exit(1)', lo que hace es salir retornando 1, si la aplicacion fue ejecutada directamente por el usuario al salir con 1 se notifica al s.o. que esa aplicacion encontro algun problema.

Lo de fflush en el manual de fflush indica que está definida para trabajar con streams de salida (escritura) y para streams nulos, pero para streams de entrada (lectura) depende de la implementacion de la libreria (es decir que no hay un funcionamiento estandar).

El stdin es el standard input stream que normalmente será el teclado (nota: el stdout es el stream de salida estandar que normalmente será la pantalla, y el stderr será el stream de salida estandar de errores que normalmente tambien sará la pantalla; los tres streams estan disponibles de forma automatica desde el inicio de la aplicacion, y se cierran al final). Cualquier tecla que pinches se guardará en ese buffer, luego con las funciones de lectura de teclado (getchar, scanf, etc) se iran leyendo esos datos (hay funciones que los leen hasta encontrar determinado caracter, algunas funciones permiten formatear la entrada, etc...). Cuando quieres vaciar el buffer de entrada por teclado debes usar una funcion que vacia ese stream pero no el fflush porque su funcionamiento no está previsto para stdin:

Código:
//creas tu propia funcion, está en C pero sirve para c++
//simplemente lee todos los caracteres del stdin y los omite
//algunas implementaciones de esta funcion se limitan a comparar solo contra \n
void fflush_stdin() {
    while ((ch = getchar()) != EOF && ch != '\n');
}

//luego en cualquier sitio que tengas fflush(stdin) cambias por fflush_stdin()
add(principio);
fflush_stdin();
printf("\nEl numero es: %d", principio->numero);
Otra cosa, vacias stdin porque scanf deja restos en stdin, luego si el problema viene de scanf lo normal es que vacies el stdin immediatamente despues del scanf (o cuando ya no necesites los datos restantes de esa operacion) en vez de hacerlo fuera de la funcion ok? No es que no funcione, sino que sirve para organizar el codigo. Mientras el usuario entra un numero por teclado y le da al enter, en el stdin se guarda ese numero mas el caracter \n (enter); luego en el scanf lees de stdin el formato %d, es decir que scanf sacará de stdin solo el primer numero y dejara el resto que en este caso es \n; cuando sabes seguro que n ovas a necesitar ese resto limpias el stdin sin esperar a que finalice la funcion.

Saludos
vosk

Etiquetas: int, programa, struct
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 21:07.