Can´t see reason of overflow.

Segmentation Fault calling fgets or fscanf

Page 1 of 1

7 Replies - 1437 Views - Last Post: 17 August 2009 - 11:28 AM Rate Topic: -----

#1 Sergiux   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 15-November 07

Can´t see reason of overflow.

Post icon  Posted 15 August 2009 - 05:42 PM

Hello.

When Im in interfaz_test() and call fgets or fscanf I get a Segmentation Fault, but can´t see why. Any help would be appreciated. Thanks.

/* Proyecto1.c
* 
*	P r o g r a m a   q u e   c a l i f i c a
*	u n   t e s t   a r b i t r a r i o   y
*	m u e s t r a   r e s u l t a d o s
*/

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include "prototipos.h"

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

	/* variables de control */
	int j=1, i=0, help_int, sistemas_ctrl=0, estudiantes_ctrl=0;
	char *decision, *sistemas, *cantidad_estudiantes;

	/* asignación dinámica (pudo usarse arreglos ya que es una cantidad fija de bytes) */
	if (((sistemas = (char *)calloc(20, sizeof(char))) == NULL) || ((cantidad_estudiantes = (char *)calloc(2, sizeof(char))) == NULL) || ((decision=(char *)malloc(sizeof(char)*2)) == NULL)) {
		fprintf(stderr, "Insuficiente espacio en memoria principal!\n");
		exit(EXIT_SUCCESS);
	}
	
	/* en caso de --help a main */
	if (argc > 1) {
		help_int = help(*(argv+1));
		if (help_int)
			exit(EXIT_SUCCESS);
	}

	/* detección de errores en los argumentos a main */
	if (argc != 1) {
		if (argc == 2) {
			if (!(validacion(*(argv+1))))
				fprintf(stderr, "\n\t****** Argumento número de sistemas inválido, el programa lo ignorará ******\n");
			else
				sistemas_ctrl=1;
		}
		else if (argc == 3) {
			if (!(validacion(*(argv+1))))
				fprintf(stderr, "\n\t****** Argumento número de sistemas inválido, el programa lo ignorará ******\n");
			else
				sistemas_ctrl=1;

			if (!(validacion(*(argv+2))))
				fprintf(stderr, "\n\t****** Argumento número de estudiantes inválido, el programa lo ignorará ******\n");
			else
				estudiantes_ctrl=1;
		}
		else 
			fprintf(stderr, "\n\t****** Número de argumentos inválido, el programa tendrá en cuenta los dos primeros ******\n");
	}		

	/* validacion enteros */
	if (!sistemas_ctrl || (!(validacion(*(argv+1))))) {
		do {
			fprintf(stdout, "Proporcione la cantidad de sistemas de calificación: \n-> ");
			scanf("%20s", sistemas);
		} while (!(sistemas_integer=validacion(sistemas)));
	}
	else
		sistemas_integer = atoi(*(argv+1));

	/* arreglo de enteros para cantidad de estudiantes en cada sistema */
	cantidad_int = (int *)calloc(sistemas_integer, sizeof(int));

	/* mientras haya sistemas */
	while (sistemas_integer) {
		if (!estudiantes_ctrl || (!(validacion(*(argv+1))))) {
			do {
				fprintf(stdout, "Escriba la cantidad de estudiantes del sistema %d \n-> ", j);
				scanf("%2s", cantidad_estudiantes);
			} while (!(*(cantidad_int+i) = validacion(cantidad_estudiantes)));
		}
		else
			*(cantidad_int+i) = atoi(*(argv+2));
		
		/* llamada a la interfaz con los usuarios */
		interfaz_test();
		
		/* control */
		sistemas_integer--;
		i++;
		j++;
	}

	/* escritura en archivo, poco elegante con sistemas_integer... :( */
	sistemas_integer=i;
	escribir_archivo();
	
	/* calificar */
	calificar();

	/* el usuario decide qué hacer */	
	do {
	
		decision = menu(decision);
	
		if (*decision == '1')
			individual();
		else if (*decision == '2')
			colectivo();
		else if (*decision == '3')
			desviacion();
		else
			media();
	} while(*decision != '5');

	exit(EXIT_SUCCESS);
}

/* recibe e imprime los resultados del estudiante de individual() */
void especifico(int sistema, int estudiante)
{
	/* control */
	int j;

	/* apuntador local de la funcion, apunta al sistema */
	ptr_estudiantes ptr_local = *ptr_apuntadores;
	ptr_local = ptr_local+sistema;

	/* apunta al estudiante */
	for (j=0; j<estudiante; j++) {
		ptr_local = ptr_local->siguiente;
	}

	for (j=0; j<estudiante; j++) {
		printf("\n\nNombre: %s\n\tCódigo: %s\n\tRespuestas: %s\n\tCorrectas: ", ptr_local->nombre, ptr_local->codigo, ptr_local->respuestas);
		printf("%d\n\tIncorrectas: %d\n\tNota: %lf\n\n", ptr_local->correctas, ptr_local->incorrectas, (ptr_local->correctas - (ptr_local->incorrectas * 0.5)));
	}
}

/* asigna nota a cada estudiante */
void calificar()
{
	/* apuntador local de la funcion */
	ptr_estudiantes ptr_local = *ptr_apuntadores;

	/* control */
	int j, i;

	for (j=0; j<sistemas_integer; j++)
		ptr_local = ptr_local+j;
		for (i=0; i<*(cantidad_int+j); i++) {
			ptr_local->nota = ptr_local->correctas - (ptr_local->incorrectas * 0.5);
			ptr_local = ptr_local->siguiente;
		}
}

/* interfaz con el usuario */
char *menu(char *decis)
{
	
	printf("\n\n\tEl examen ha terminado. Escoja una opción:\n\n1. Ver resultado individual.\n2. Ver resultado colectivo.");
	printf("\n3. Ver desviación estándar del grupo.\n4. Ver media del grupo.\n5. Salir\n\n-> ");
	scanf("%1s", decis);

	while (*decis != '1' && *decis != '2' && *decis != '3' && *decis != '4' && *decis != '5') {
		printf("\n\n\tArgumento inválido. Escoja una opción:\n\n1. Ver resultado individual.\n2. Ver resultado colectivo.");
		printf("\n3. Ver desviación estándar del grupo.\n4. Ver media del grupo.\n5. Salir\n\n-> ");
		scanf("%1s", decis);
	} 

	return decis;
}

/* halla la media de la suma de todos los estudiantes */
int media()
{
	/* apuntador local de la funcion */
	ptr_estudiantes ptr_local = *ptr_apuntadores;

	/* control */
	int j, i;
	
	/* media aritm tica */
	int media=0;
	
	for (j=0; j<sistemas_integer; j++)
		ptr_local = ptr_local+j;
		for (i=0; i<*(cantidad_int+i); i++) {
			media+=ptr_local->nota;
			ptr_local = ptr_local->siguiente;
		}
	return media;
}

/* imprime los resultados de todos los estudiantes */
void colectivo()
{

	/* apuntador local de la funcion */
	ptr_estudiantes ptr_local = *ptr_apuntadores;

	/* variables de control */
	int j, i;
	
	for (j=0; j<sistemas_integer; j++)
		ptr_local = ptr_local+j;
		for (i=0; i<*(cantidad_int+j); i++) {
			printf("************************\nNombre\tCódigo\tRespuestas\tCorrectas\tIncorrectas\tNota\n\n");
			printf("%s\t%s\t%s\t", ptr_local->nombre, ptr_local->codigo, ptr_local->respuestas);
			printf("%d\t%d\t%lf", ptr_local->correctas, ptr_local->incorrectas, (ptr_local->correctas - (ptr_local->incorrectas * 0.5)));
			printf("\n************************");
			ptr_local = ptr_local->siguiente;
		}	
}

/* verifica si se pasó --help como argumento a main*/
int help(char *argumento)
{
	char *help = (char *)malloc(sizeof(char)*10);
	help = "--help";

	/* Si se proporciona --help... */	
	if (!(strncmp(argumento, help, 6)))
	{
		fprintf(stdout, "\nUso:\n\t ./Proyecto1 2 4 => El programa asume cantidad de sistemas el argumento 2, cada sistema de 4 estudiantes.\n");
		fprintf(stdout, "\tPuede proporcionar un sólo argumento, que sería la cantidad de sistemas, para ser cuestionado durante el programa ");
		fprintf(stdout, " sobre la cantidad de estudiantes de cada uno.\n\n");
		return 0x1;	
	}
	else
		return 0x0;
}

/* imprime la desviaci n est ndar de los resultados */
void desviacion()
{

	int *datos;

	/* variables de control */
	int j, i, util=0;
	
	/* desviacion est ndar */
	int desviacion=0;

	/* apuntador local de la funcion */
	ptr_estudiantes ptr_local = *ptr_apuntadores;
	
	/* escribe en la variable util la cantidad total de estudiantes */	
	for (j=0; j<sistemas_integer; j++) 
		for (i=0; i<*(cantidad_int+j); i++) {
			util++;
		}

	datos = calloc(util, sizeof(int));

	/* halla la desviacion */
	for (j=0; j<sistemas_integer; j++)
		ptr_local = ptr_local+j;
		for (i=0; i<*(cantidad_int+j); i++) {
			desviacion += ptr_local->nota;
			ptr_local = ptr_local->siguiente;
		}
}

/* escribe en un archivo los resultados */
void escribir_archivo()
{
	/* archivo */
	FILE *archivio;

	/* variables de control */
	int j,i;
	
	/* apuntador local de la funcion */
	ptr_estudiantes ptr_local = *ptr_apuntadores;

	/* copiado a archivo */
	if ((archivio = fopen("estudiantes.dat", "w+")) != NULL) {
		for (j=0; j<sistemas_integer; j++) {
			ptr_local = ptr_local+j;
			for (i=0; i<*(cantidad_int+i); i++) {
				fwrite(ptr_local, sizeof(Estudiantes), 1, archivio);
				ptr_local = ptr_local->siguiente;
			}
		}	
	
	}

	/* Si no hay espacio en disco... */	
	else {
		fprintf(stderr, "\n\n***** Insuficiente espacio en disco *****\n\n");
		exit(EXIT_SUCCESS);
	}

	fclose(archivio);	
}

/* escoje 1 estudiante y lo env a a especifico() */
void individual()
{
	/* apuntador local de la funcion */
	ptr_estudiantes ptr_local = *ptr_apuntadores;

	/* variables de control */
	int j, i, sistema_int, estudiante_int;
	char sistema[2];
	char estudiante[2];

	printf("¿De qué estudiante quiere ver los resultados?\n");

	/* despliega las opciones */	
	for (j=0; j<sistemas_integer; j++)
		ptr_local = ptr_local+j;
		for (i=0; i<*(cantidad_int+j); i++) {
			if (i==0)
				printf("Sistema %d\n\n", j+1);
			printf("%d %s", i, ptr_local->nombre);
			ptr_local = ptr_local->siguiente;
		}

	do {
		printf("Elija sistema y estudiante: \nSistema #\n-> ");
		scanf("%2s", sistema);
	} while (!(sistema_int = validacion(sistema)));
	
	do {
		printf("\nEstudiante #\n-> ");
		scanf("%2s", estudiante);
	} while (!(estudiante_int = validacion(estudiante)));

	/* pasa sistema y estudiante a verle el rendimiento */
	especifico(sistema_int, estudiante_int);
}

/* valida enteros */
int validacion (const char * const valor_validar)
{
	/* variables locales */
	int retorno = atoi(valor_validar);
	int a = 0;
	int tope = (pow(2, sizeof(int)*8) / 2 - 1); 
	
	if (retorno <= 0) 
	{
		fprintf (stderr, "Por favor ingrese un numero entero positivo.\n");
		return 0;
	}
	
	if (valor_validar[0] == '+')
		a = 1;
	else
		a = 0;
	
	for (a; valor_validar[a] != '\0'; a++) 
	{
		
		if (!(isdigit(valor_validar[a]))) 
		{
			fprintf (stderr, "Por favor ingrese un numero entero positivo.\n");
			return 0;
		}
	}
	
	if (tope == retorno)
	{
		fprintf(stdout, "Rango por encima del maximo valor permitido, intente de nuevo.\n");
		return 0;
	}

	return retorno;

}

/* interfaz con el usuario */
void interfaz_test()
{
	/* variables de control */
	int i, j, cuantos;
	static int sistema=1, contador=0, k=0;

	/* archivo */
	FILE *preguntas;

	/* apuntador al arreglo de la pregunta, escrito por fread */
	char *pregunta;

	/* nuevo nodo */
	ptr_estudiantes ptr_nuevo=(ptr_estudiantes)calloc(1, sizeof(Estudiantes));

	/* apuntador a apuntadores de estructura; cada uno contiene el primer nodo de del sistema */
	if (sistema==1)
		ptr_apuntadores=(ptr_estudiantes*)calloc(sistemas_integer, sizeof(Estudiantes));

	/* se le asigna el nodo ptr_nuevo al apuntador referenciado por contador */
	ptr_apuntadores[contador]=ptr_nuevo;
	
	/* ciclo "principal" */
	for (i=0; i<*(cantidad_int+k); i++) {
	
	/* asigna memoria para los miembros de la estructura y abre un archivo para actualización */
	if ((ptr_nuevo->siguiente=(ptr_estudiantes)malloc(sizeof(Estudiantes))) != NULL || (ptr_nuevo->nombre=(char*)calloc(20, sizeof(char))) != NULL || (ptr_nuevo->codigo=(char*)calloc(5, sizeof(char))) != NULL || (preguntas=fopen("examen", "r")) != NULL) {
			
			printf("Bienvenido al test, estudiante %d, escriba su nombre\n-> ", i+1);
			fgets(ptr_nuevo->nombre, 20, stdin);
			//fscanf(stdin, "%20s", ptr_nuevo->nombre);

			do {
				printf("Escriba su código\n-> ");
				fscanf(stdin, "%5s", ptr_nuevo->codigo);
			} while (!(ptr_nuevo->codigo_int = validacion(ptr_nuevo->codigo)));
			/* examen */
			cuantos = fscanf(preguntas, "%s");
			pregunta = (char *)calloc(cuantos, sizeof(char));
			fscanf(preguntas, "%s", pregunta);
			

			scanf("%1s", ptr_nuevo->respuestas+0);
		
			while (ptr_nuevo->respuestas[0] != '0' && ptr_nuevo->respuestas[0] != '1') {
				fprintf(stdout, "\n\nRecuerde que sólo se admite 0 para falso y 1 para verdadero\n\n");
				scanf("%1s", ptr_nuevo->respuestas+0);
			}

			scanf("%1s", ptr_nuevo->respuestas+1);
		
			while (ptr_nuevo->respuestas[1] != '0' && ptr_nuevo->respuestas[1] != '1') {
				fprintf(stdout, "\n\nRecuerde que sólo se admite 0 para falso y 1 para verdadero\n\n");
				scanf("%1s", ptr_nuevo->respuestas+1);
			}

			scanf("%1s", ptr_nuevo->respuestas+2);
		
			while (ptr_nuevo->respuestas[2] != '0' && ptr_nuevo->respuestas[2] != '1') {
				fprintf(stdout, "\n\nRecuerde que sólo se admite 0 para falso y 1 para verdadero\n\n");
				scanf("%1s", ptr_nuevo->respuestas+2);
			}

			scanf("%1s", ptr_nuevo->respuestas+3);
		
			while (ptr_nuevo->respuestas[3] != '0' && ptr_nuevo->respuestas[3] != '1') {
				fprintf(stdout, "\n\nRecuerde que sólo se admite 0 para falso y 1 para verdadero\n\n");
				scanf("%1s", ptr_nuevo->respuestas+3);
			}

			scanf("%1s", ptr_nuevo->respuestas+4);
		
			while (ptr_nuevo->respuestas[4] != '0' && ptr_nuevo->respuestas[4] != '1') {
				fprintf(stdout, "\n\nRecuerde que sólo se admite 0 para falso y 1 para verdadero\n\n");
				scanf("%1s", ptr_nuevo->respuestas+4);
			}

			scanf("%1s", ptr_nuevo->respuestas+5);
		
			while (ptr_nuevo->respuestas[5] != '0' && ptr_nuevo->respuestas[5] != '1') {
				fprintf(stdout, "\n\nRecuerde que sólo se admite 0 para falso y 1 para verdadero\n\n");
				scanf("%1s", ptr_nuevo->respuestas+5);
			}
	
			scanf("%1s", ptr_nuevo->respuestas+6);
		
			while (ptr_nuevo->respuestas[6] != '0' && ptr_nuevo->respuestas[6] != '1') {
				fprintf(stdout, "\n\nRecuerde que sólo se admite 0 para falso y 1 para verdadero\n\n");
				scanf("%1s", ptr_nuevo->respuestas+6);
			}

			scanf("%1s", ptr_nuevo->respuestas+7);
		
			while (ptr_nuevo->respuestas[7] != '0' && ptr_nuevo->respuestas[7] != '1') {
				fprintf(stdout, "\n\nRecuerde que sólo se admite 0 para falso y 1 para verdadero\n\n");
				scanf("%1s", ptr_nuevo->respuestas+7);
			}

			scanf("%1s", ptr_nuevo->respuestas+8);
		
			while (ptr_nuevo->respuestas[8] != '0' && ptr_nuevo->respuestas[8] != '1') {
				fprintf(stdout, "\n\nRecuerde que sólo se admite 0 para falso y 1 para verdadero\n\n");
				scanf("%1s", ptr_nuevo->respuestas+8);
			}

			
			scanf("%1s", ptr_nuevo->respuestas+9);
		
			while (ptr_nuevo->respuestas[9] != '0' && ptr_nuevo->respuestas[9] != '1') {
				fprintf(stdout, "\n\nRecuerde que sólo se admite 0 para falso y 1 para verdadero\n\n");
				scanf("%1s", ptr_nuevo->respuestas+9);
			}
			/* fin de examen */
	
			/* lectura respuestas desde archivo */
			FILE *lectura = fopen("respuestas", "r");
			fread(ptr_nuevo->f_v, 1, 10, lectura);
			fclose(lectura);			

			/* cantidad de respuestas correctas e incorrectas */
			for (j=0; j<10; j++) {
				if (ptr_nuevo->respuestas[j] == ptr_nuevo->f_v[j])
					ptr_nuevo->correctas++;
				else
					ptr_nuevo->incorrectas++;
			}

			/* apunta al siguiente nodo */
			ptr_nuevo = ptr_nuevo->siguiente;

			/* si es el último ciclo, establecer último nodo en NULL (convención) */
			if (i==*(cantidad_int+contador)-1)
				ptr_nuevo->siguiente = NULL;
			
		}
		
		/* insuficiente memoria princial */
		else {
			exit(EXIT_FAILURE);
		}
	}	
		/* siguiente sistema */
		sistema++;
		contador++;
		k++;
}


If necessary, can translate it to english so it can be more easy to understand.

Is This A Good Question/Topic? 0
  • +

Replies To: Can´t see reason of overflow.

#2 KYA   User is offline

  • Wubba lubba dub dub!
  • member icon

Reputation: 3213
  • View blog
  • Posts: 19,241
  • Joined: 14-September 07

Re: Can´t see reason of overflow.

Posted 15 August 2009 - 08:48 PM

If I'm reading that correctly (and I'm probably not, as I don't speak Spanish), inside that function you create space for an array of only one element? Why? Why not just make it a pointer to an object, why the array? Not sure if its related, but it struck me as odd:

 /* nuevo nodo */
	ptr_estudiantes ptr_nuevo=(ptr_estudiantes)calloc(1, sizeof(Estudiantes));




Is it same to assume Estudiantes is a struct that was typedefed to ptr_estudiantes? (You didn't poast the header).
Was This Post Helpful? 1
  • +
  • -

#3 JackOfAllTrades   User is offline

  • Saucy!
  • member icon

Reputation: 6260
  • View blog
  • Posts: 24,030
  • Joined: 23-August 08

Re: Can´t see reason of overflow.

Posted 15 August 2009 - 10:55 PM

cuantos = fscanf(preguntas, "%s");
pregunta = (char *)calloc(cuantos, sizeof(char));
fscanf(preguntas, "%s", pregunta);


fscanf returns the number of fields scanned in, so when you use the result of that call as the argument to calloc, you are only allocating a single character.

Also, you are not adding an extra space for the null terminator either.
Was This Post Helpful? 1
  • +
  • -

#4 Sergiux   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 15-November 07

Re: Can´t see reason of overflow.

Posted 16 August 2009 - 03:19 PM

Yes, cuantos gets the number of characters scanned, so only 1 char, thats ok. Overflow happens before that...

Sorry, heres the header:

/* prototipos.h
* contiene los prototipos de las funciones, la estructura de datos
* y variables globales
*/

struct estudiantes {
	char *nombre;
	char *codigo;
	char respuestas[10];
	char f_v[10];
	int correctas;
	int incorrectas;
	int codigo_int;
	double nota;
	struct estudiantes *siguiente;
};
typedef struct estudiantes Estudiantes;
typedef Estudiantes *ptr_estudiantes;

/* variables globales */
int sistemas_integer; 
int *cantidad_int;
ptr_estudiantes *ptr_apuntadores;

void especifico(int, int);
void calificar(void);
char *menu(char *);
int media(void);
void colectivo(void);
int help(char *);
void desviacion(void);
void escribir_archivo(void);
void individual(void);
int validacion(const char * const);
void interfaz_test(void);




The idea of
 /* nuevo nodo */
	ptr_estudiantes ptr_nuevo=(ptr_estudiantes)calloc(1, sizeof(Estudiantes));



is to create a pointer to the structure Estudiantes, this pointer is going to be created in every call to the function, asigned to another pointer, indeed a pointer of pointers, so every pointer points to the first node of the dynamic structure (since I have the other nodes through the member siguiente).

This post has been edited by Sergiux: 16 August 2009 - 03:21 PM

Was This Post Helpful? 0
  • +
  • -

#5 Sergiux   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 15-November 07

Re: Can´t see reason of overflow.

Posted 16 August 2009 - 03:25 PM

So, I have ptr_nuevo assigned to each pointer pointing to the structure, ptr_apuntadores (that is ptr_pointers in english). So every pointer of ptr_apuntadores points to the first node in the context, each one points to different nodes, that is, the first node of each context.

I don´t know if being clear... :S
Was This Post Helpful? 0
  • +
  • -

#6 Sergiux   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 15-November 07

Re: Can´t see reason of overflow.

Posted 16 August 2009 - 03:40 PM

Indeed, Im failing with cuantos and just 1 char cause need an extra for null terminator, but overflow, as I said, comes before... So I THINK is no the problem... It comes where fgets is called and fscanf is commented... exactly during fgets call, it doesn't ask me to type, so ptr_nuevo->nombre keeps it´s original value (i think it is calloced, so it is 0, I guess). Or, another part was success calling fgets, but overflow calling fscanf to get ptr_nuevo->codigo.
But Im getting overflow just calling fgets or fscanf... and I can´t figure it out (tested under clean Linux installs, Gentoo and Fedora, practically it can´t be an error with the libs...)

Thanks for the help.
Was This Post Helpful? 0
  • +
  • -

#7 JackOfAllTrades   User is offline

  • Saucy!
  • member icon

Reputation: 6260
  • View blog
  • Posts: 24,030
  • Joined: 23-August 08

Re: Can´t see reason of overflow.

Posted 16 August 2009 - 05:53 PM

If you're running on Linux, maybe try using valgrind to pinpoint your problem?
Was This Post Helpful? 1
  • +
  • -

#8 Sergiux   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 15-November 07

Re: Can´t see reason of overflow.

Posted 17 August 2009 - 11:28 AM

Hi.

Theres something wrong with
	 if ((ptr_nuevo->siguiente=(ptr_estudiantes)malloc(sizeof(Estudiantes))) != NULL || (ptr_nuevo->nombre=(char*)calloc(20, sizeof(char))) != NULL || (ptr_nuevo->codigo=(char*)calloc(5, sizeof(char))) != NULL || (preguntas=fopen("examen", "r")) != NULL) {


there is no assignment... why is this?
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1