I've been trying to solve a segmentation fault since yesterday, it's driving me crazy...
So I've got this program that I use to implement the sokoban game, in which a map is given, and a plan like "NSEW" is given, meaning that I want the player to move north, then south, then etc... on the map given.
map* replay(map* map_loaded, int length, char* plan){
map* new_map=move(map_loaded,plan[0]);
map* old_map=deep_copy(new_map);
for (int i=1 ; i<length ; i++){
free(new_map->p_char);
free(new_map);
new_map=move(old_map,plan[i]);
free(old_map->p_char);
free(old_map);
old_map=deep_copy(new_map);
}
free(old_map->p_char);
free(old_map);
return new_map;
}
Map is a structure defined as following :
typedef struct map map;
struct map{
int width;
int height;
char* p_char;
};
The move function does one movement ;
The deep_copy makes a deep copy of a map struct :
map* deep_copy(map* map_loaded){
map* new_map=malloc(sizeof(map));
char* p_array=map_loaded->p_char;
int width=map_loaded->width;
int height=map_loaded->height;
new_map->width=width;
new_map->height=height;
char* p_new=malloc(sizeof(char)*width*height);
for (int i=0 ; i<width*height ; i++){
p_new[i]=p_array[i];
}
new_map->p_char=p_new;
return(new_map);
}
And what happens is that if I leave the code like that, if the length chosen ( the number of movements I want the player to do) is too high (depends on the map and the movements), when executing a replay.c program :
int main(int argc, char *argv[]){
if (argc != 4) {
fprintf(stderr, "You must provide a file name or enough elements!\n");
exit(EXIT_FAILURE);
}
map* map_loaded=load(argv[1]);
int length=atoi(argv[2]);
char* plan=argv[3];
map* new_map=replay(map_loaded,length,plan);
print_map(new_map);
free(new_map->p_char);
free(new_map);
free(map_loaded->p_char);
free(map_loaded);
return 1;
}
I get a segmentation fault... But if I do :
//free(old_map->p_char);
//free(old_map);
Everything works perfect !!
I really don't understand why... The problem is if I do those free valgrind tells me I don't have as many free as allocs, which is normal...
I would really appreciate any help given...
Thanks in advance if you've been brave enough to read me until this point !
Edit :
Here is my move function ;
map* move(map* map_loaded, char dir){
int pos=Position(map_loaded);
int width=map_loaded->width;
map* new_map=deep_copy(map_loaded);
char* p_new_array=new_map->p_char;
switch(dir){
case 'N':
if (p_new_array[pos-width]=='#'){ // Si il y a un mur au dessus
return(map_loaded);
}
if ((p_new_array[pos-width]=='$' && p_new_array[pos-2*width]=='$')
||(p_new_array[pos-width]=='$' && p_new_array[pos-2*width]=='*')
||(p_new_array[pos-width]=='*' && p_new_array[pos-2*width]=='$')
||(p_new_array[pos-width]=='*' && p_new_array[pos-2*width]=='*')){ //s'il y a 2 caisses au dessus
return(map_loaded);
}
if ((p_new_array[pos-width]=='$' && p_new_array[pos-2*width]=='#') //s'il y a une caisse au niveau -1 et un mur au niveau -2
||(p_new_array[pos-width]=='*' && p_new_array[pos-2*width]=='#')){
return(map_loaded);
}
// On vérifie d'abord s'il y a une caisse à déplacer
if (p_new_array[pos-width]=='$' || p_new_array[pos-width]=='*'){
if (p_new_array[pos-2*width]=='.'){
p_new_array[pos-2*width]='*';
}
else {
p_new_array[pos-2*width]='$';
}
if (p_new_array[pos-width]=='*'){
p_new_array[pos-width]='.';
}
else{
p_new_array[pos-width]=' ';
}
}
//On change le char en position du joueur
if (p_new_array[pos]=='+'){
p_new_array[pos-width]='#';
p_new_array[pos]='.';
}
else if (p_new_array[pos-width]=='.'){
p_new_array[pos-width]='+';
p_new_array[pos]=' ';
}
else {
p_new_array[pos-width]='#';
p_new_array[pos]=' ';
}
break;
case 'S':
if (p_new_array[pos+width]=='#'){ // Si il y a un mur en dessous
return(map_loaded);
}
if ((p_new_array[pos+width]=='$' && p_new_array[pos+2*width]=='$')
||(p_new_array[pos+width]=='$' && p_new_array[pos+2*width]=='*')
||(p_new_array[pos+width]=='*' && p_new_array[pos+2*width]=='$')
||(p_new_array[pos+width]=='*' && p_new_array[pos+2*width]=='*')){//s'il y a 2 caisses au dessus
return(map_loaded);
}
if ((p_new_array[pos+width]=='$' && p_new_array[pos+2*width]=='#') //s'il y a une caisse au niveau +1 et un mur au niveau +2
||(p_new_array[pos+width]=='*' && p_new_array[pos+2*width]=='#')){
return(map_loaded);
}
// On vérifie d'abord s'il y a une caisse à déplacer
if (p_new_array[pos+width]=='$' || p_new_array[pos+width]=='*'){
if (p_new_array[pos+2*width]=='.'){
p_new_array[pos+2*width]='*';
}
else {
p_new_array[pos+2*width]='$';
}
if (p_new_array[pos+width]=='*'){
p_new_array[pos+width]='.';
}
else{
p_new_array[pos+width]=' ';
}
}
//On change le char en position du joueur
if (p_new_array[pos]=='+'){
p_new_array[pos+width]='#';
p_new_array[pos]='.';
}
else if (p_new_array[pos+width]=='.'){
p_new_array[pos+width]='+';
p_new_array[pos]=' ';
}
else {
p_new_array[pos+width]='#';
p_new_array[pos]=' ';
}
break;
case 'W':
if (p_new_array[pos-1]=='#'){ // Si il y a un mur en dessous
return(map_loaded);
}
if ((p_new_array[pos-1]=='$' && p_new_array[pos-2]=='$')
||(p_new_array[pos-1]=='$' && p_new_array[pos-2]=='*')
||(p_new_array[pos-1]=='*' && p_new_array[pos-2]=='$')
||(p_new_array[pos-1]=='*' && p_new_array[pos-2]=='*')){ //s'il y a 2 caisses à gauche
return(map_loaded);
}
if ((p_new_array[pos-1]=='$' && p_new_array[pos-2]=='#') //s'il y a une caisse au niveau -1 et un mur au niveau -2
||(p_new_array[pos-1]=='*' && p_new_array[pos-2]=='#')){
return(map_loaded);
}
// On vérifie d'abord s'il y a une caisse à déplacer
if (p_new_array[pos-1]=='$' || p_new_array[pos-1]=='*'){
if (p_new_array[pos-2]=='.'){
p_new_array[pos-2]='*';
}
else {
p_new_array[pos-2]='$';
}
if (p_new_array[pos-1]=='*'){
p_new_array[pos-1]='.';
}
else{
p_new_array[pos-1]=' ';
}
}
//On change le char en position du joueur
if (p_new_array[pos]=='+'){
p_new_array[pos-1]='#';
p_new_array[pos]='.';
}
else if (p_new_array[pos-1]=='.'){
p_new_array[pos-1]='+';
p_new_array[pos]=' ';
}
else {
p_new_array[pos-1]='#';
p_new_array[pos]=' ';
}
break;
case 'E':
if (p_new_array[pos+1]=='#') {// Si il y a un mur à droite
return(map_loaded);
}
if ((p_new_array[pos+1]=='$' && p_new_array[pos+2]=='$')
||(p_new_array[pos+1]=='$' && p_new_array[pos+2]=='*')
||(p_new_array[pos+1]=='*' && p_new_array[pos+2]=='$')
||(p_new_array[pos+1]=='*' && p_new_array[pos+2]=='*')){ //s'il y a 2 caisses à droite
return(map_loaded);
}
if ((p_new_array[pos+1]=='$' && p_new_array[pos+2]=='#') //s'il y a une caisse au niveau +1 et un mur au niveau +2
||(p_new_array[pos+1]=='*' && p_new_array[pos+2]=='#')){
return(map_loaded);
}
// On vérifie d'abord s'il y a une caisse à déplacer
if (p_new_array[pos+1]=='$' || p_new_array[pos+1]=='*'){
if (p_new_array[pos+2]=='.'){
p_new_array[pos+2]='*';
}
else {
p_new_array[pos+2]='$';
}
if (p_new_array[pos+1]=='*'){
p_new_array[pos+1]='.';
}
else{
p_new_array[pos+1]=' ';
}
}
//On change le char en position du joueur
if (p_new_array[pos]=='+'){
p_new_array[pos+1]='#';
p_new_array[pos]='.';
}
else if (p_new_array[pos+1]=='.'){
p_new_array[pos+1]='+';
p_new_array[pos]=' ';
}
else {
p_new_array[pos+1]='#';
p_new_array[pos]=' ';
}
break;
}
return(new_map);
}
And here is the load function ;
char* Array_Creator(char* filename){
FILE* p_file = fopen(filename, "r");
char* p_array = NULL;
if (p_file == NULL) {
exit(EXIT_FAILURE);
}
else{
size_t size=1;
int c;
while (getc(p_file)!=EOF) {
size++;
}
fseek(p_file,0,SEEK_SET);
while ((c=getc(p_file))!='\n' && c!=EOF) { //on se débarasse de la première ligne
size--;
}
p_array=(char*)malloc(sizeof(char)*size);
if (p_array!=NULL) { //si jamais le malloc ne fonctionne pas
for(size_t i=0; i<size-1; i++) {
p_array[i]=(char)getc(p_file);
if (p_array[i] == '\n') { // si le caractère est une nouvelle ligne, on s'en sépare
i--; // on ajuste alors la taille et l'indice
size--;
}
}
p_array[size-1]='\0';
}
fclose(p_file);
}
return p_array;
}
//La fonction Dimensions permet de récupérer les dimensions d'une map
couple Dimensions(char *p_char){
FILE *p_file = NULL;
p_file=fopen(p_char, "r");
if (p_file == NULL) {
fprintf(stderr, "Cannot read file %s!\n", p_char);
exit(EXIT_FAILURE);
}
couple dim={0,0}; //la structure couple est déf dans le loader.h
int width = 0;
int height = 0;
int fscanf_result = 0;
fscanf_result = fscanf(p_file, "%d %d\n", &width, &height);
if (fscanf_result != 2) {
fprintf(stderr, "First line is not syntactically correct!\n");
exit(EXIT_FAILURE);
}
dim.x=width;
dim.y=height;
fclose(p_file);
return dim;
}
//La fonction Load est celle demandée et permettant de charger une carte ; elle utilise Dimensions et Array_Creator
map* load(char *filename){
map* map_loaded=malloc(sizeof(map)); //on alloue dynamiquement la map
//Dans un premier temps on récupère les dimensions
couple map_dim={0,0};
map_dim=Dimensions(filename);
map_loaded->width=map_dim.x;
map_loaded->height=map_dim.y;
//Dans un second temps on définit le tableau 1D contenant l'ensemble des éléments de la map
char* p_char=Array_Creator(filename);
map_loaded->p_char=p_char;
return map_loaded;
}
The command line is, for example :
./replay ./data/soko.in 4 7"NSWSESNWW"
In the move function, should change all
return(map_loaded); => return(new_map);
It will map_loaded to be freed twice when the move function returns map_loaded
Code analysis
map *replay(map *map_loaded, int length, char *plan)
{
map *new_map = move(map_loaded, plan[0]); // [2] set new_map to map_loaded
map *old_map = deep_copy(new_map);
for (int i = 1 ; i < length ; i++) {
free(new_map->p_char);
free(new_map); // [3] new_map be freed,
// equivalent map_loaded be freed
new_map = move(old_map, plan[i]);
...
}
...
return new_map;
}
int main(int argc, char *argv[])
...
map *map_loaded = load(argv[1]); // [1] map_loaded be malloc
...
map *new_map = replay(map_loaded, length, plan);
...
free(map_loaded->p_char);
free(map_loaded); // [4] map_loaded be freed
...
}
Related
This question already has answers here:
Why can we not declare a variable after a switch case colon without using curly braces?
(3 answers)
Closed last month.
I have a problem compiling the code in the main file at line 17.
The error is
"a label can only be part of a statement and a declaration is not a statement".
#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED
#define TAILLE_MAX_NOM 50
// Définition du type Compte
typedef struct {
int RIB;
float solde;
char etat[TAILLE_MAX_NOM];
float plafond_credit;
int nb_operations;
float operations[100];
} Compte;
Compte T_Compte[100];
int menu();
void CreerCompte(Compte *C);
int ChercherCompte(Compte T_Compte[],int NC,int RIB );
void AjouterCompte (Compte T_Compte[], int *NC, Compte C);
float Ajouter_Retirer (Compte T_Compte[], int NC, float M,int RIB);
void ListeComptes(Compte T_Compte[], int NC);
void StatCompte (Compte T_Compte[], int NC, int *PNBA,int *PNBR ,int RIB);
void Prime (Compte T_Compte[], int NC);
#endif // HEADER_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "header.h"
int menu() {
int choix;
printf("\n\n -> Menu <- \n\n");
printf(" 1 - Ajouter un Nouveau Compte \n");
printf(" 2 - Afficher les comptes de la banque \n");
printf(" 3 - Ajouter une operation a un compte\n");
printf(" 4 - Attribuer une prime aux meilleurs comptes bancaires \n");
printf(" 0 - Quitte\n");
printf("\n --------------------------------------\n");
do {
printf(" -> Tapez votre choix : ");
scanf("%d",&choix);
printf("\n\n");
} while (choix>4 || choix<0);
return choix;
}
void CreerCompte(Compte *C) {
printf("RIB du compte : ");
scanf("%d", &C->RIB);
printf("Solde initial du compte (supérieur ou égal à 50) : ");
scanf("%f", &C->solde);
while (C->solde < 50) {
printf("Le solde initial doit être supérieur ou égal à 50 !\n");
printf("Solde initial du compte (supérieur ou égal à 50) : ");
scanf("%f", &C->solde);
}
strcpy(C->etat, "debiteur");
printf("Plafond de crédit du compte (strictement négatif supérieur à -500) : ");
scanf("%f", &C->plafond_credit);
while (C->plafond_credit >= 0 || C->plafond_credit <= -500) {
printf("Le plafond de crédit doit être un montant strictement négatif supérieur à -500 !\n");
printf("Plafond de crédit du compte (strictement négatif supérieur à -500) : ");
scanf("%f", &C->plafond_credit);
}
C->nb_operations = 0;
}
int ChercherCompte(Compte T_Compte[], int NC, int RIB) {
for (int i = 0; i < NC; i++) {
if (T_Compte[i].RIB == RIB) {
return i;
}
}
return -1;
}
void AjouterCompte(Compte T_Compte[], int *NC, Compte C) {
if (ChercherCompte(T_Compte, *NC, C.RIB) != -1) {
printf("Un compte avec ce RIB existe déjà !\n");
return;
}
T_Compte[*NC] = C;
(*NC)++;
}
float Ajouter_Retirer(Compte T_Compte[], int NC, float M, int RIB) {
// Vérifie que la somme à ajouter ou retirer est non nulle
if (M == 0) {
printf("La somme à ajouter ou retirer ne peut pas être nulle !\n");
return -1;
}
// Cherche le compte dans le tableau
int pos = ChercherCompte(T_Compte, NC, RIB);
// Vérifie que le compte existe
if (pos == -1) {
printf("Le compte avec le RIB spécifié n'existe pas !\n");
return -1;
}
Compte C = T_Compte[pos];
// Vérifie que l'opération de retrait peut être effectuée
if (M < 0 && (C.solde + M < -C.plafond_credit)) {
printf("Opération de retrait impossible !\n");
return -1;
}
// Effectue l'opération
C.solde += M;
C.nb_operations++;
T_Compte[pos] = C;
return C.solde;
}
void ListeComptes(Compte T_Compte[], int NC) {
printf("Liste des comptes de la banque :\n");
for (int i = 0; i < NC; i++) {
Compte C = T_Compte[i];
printf("RIB : %d, Solde : %.2f, Etat : %s, Plafond de crédit : %.2f, Nombre d'opérations : %d\n",
C.RIB, C.solde, C.etat, C.plafond_credit, C.nb_operations);
}
}void StatCompte(Compte T_Compte[], int NC, int *PNBA, int *PNBR, int RIB) {
// Initialise les compteurs à 0
*PNBA = 0;
*PNBR = 0;
// Cherche le compte dans le tableau
int pos = ChercherCompte(T_Compte, NC, RIB);
if (pos == -1) {
printf("Le compte avec ce RIB n'existe pas !\n");
return;
}
// Parcours les opérations du compte
Compte C = T_Compte[pos];
for (int i = 0; i < C.nb_operations; i++) {
if (C.operations[i] > 0) {
(*PNBA)++;
} else if (C.operations[i] < 0) {
(*PNBR)++;
}
}
}
void Prime(Compte T_Compte[], int NC) {
printf("Attribution de la prime aux meilleurs comptes de la banque :\n");
for (int i = 0; i < NC; i++) {
Compte C = T_Compte[i];
// Vérifie que le compte est débiteur
if (strcmp(C.etat, "debiteur") == 0) {
int nb_ajout = 0;
int nb_retrait = 0;
// Parcours les opérations du compte pour compter le nombre d'opérations d'ajout et de retrait
for (int j = 0; j < C.nb_operations; j++) {
if (C.operations[j] > 0) {
nb_ajout++;
} else if (C.operations[j] < 0) {
nb_retrait++;
}
}
// Vérifie que le nombre d'opérations d'ajout est supérieur aux nombres d'opérations de retrait
if (nb_ajout > nb_retrait) {
float prime = (C.solde / C.nb_operations) * 0.5;
printf("RIB : %d - Prime : %.2f\n", C.RIB, prime);
}
}
}
}
//source file/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "header.h"
int main() {
// Initialize the array of accounts
int NC = 0;
// Display the menu and get the user's choice
int choix = menu();
while (choix != 0) {
switch (choix) {
case 1:
Compte C;
getchar();
CreerCompte(&C);
AjouterCompte(T_Compte, &NC, C);
break;
case 2:
// Display the accounts
ListeComptes(T_Compte, NC);
break;
case 3:
// Add or remove money from an account
printf("RIB du compte : ");
int RIB;
scanf("%d", &RIB);
printf("Somme à ajouter ou retirer : ");
float M;
scanf("%f", &M);
float solde = Ajouter_Retirer(T_Compte, NC, M, RIB);
if (solde != -1) {
printf("Nouveau solde : %.2f\n", solde);
}
break;
case 4:
// Attribute a prize to the best accounts
Prime(T_Compte, NC);
break;
}
// Display the menu and get the user's choice again
choix = menu();
}
printf("Au revoir !\n");
return 0;
}
Here is the main function that uses 4 switches to perform the following functions:
Add a new account
Display the accounts of the bank
Add an operation to an account
Attribute a prize to the best accounts
Is this line 17?
Compte C;
If so, you need to scope the variable C. Change the case 1: handler to this:
case 1:
{
Compte C;
getchar();
CreerCompte(&C);
AjouterCompte(T_Compte, &NC, C);
break;
}
This question already has answers here:
Why is “while( !feof(file) )” always wrong?
(5 answers)
Closed 5 months ago.
I have a program that seems to have a problem displaying the data received from a .txt file with fgets
Basically the program is something similar to a CRUD or ABM (in Spanish).
The problem is that when I show the structs from the file, it shows me a duplicate of the last struct.
The code is the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
// ==== Estructura Empleado ====
typedef struct
{
int legajo; // Numero de 6 digitos
char nombreApellido[30];
float sueldo; // Aleatorio entre 80k-200k
} Empleado;
// Carga un empleado por teclado; Devuelve un struct Empleado
Empleado cargarEmpleadoPorTeclado();
// Carga un vector de Empleado
void cargarEmpleadosPorTeclado(Empleado empleados[], int cantidadEmpleados);
// Recibe un vector de chars y devuelve un struct Empleado
Empleado parsearEmpleado(char datosSinParsear[50], int largoDatos);
// Carga los empleados desde el archivo al vector empleados[]
void cargarEmpleadosEnVector(Empleado empleados[], int cantidadEmpleados);
// Guarda los empleados en el archivo 'empleados.txt'
void guardarEmpleados(Empleado empleados[], int cantidadEmpleados);
// Muestra los empleados cargados en el vector empleados[]
void mostrarEmpleadosDesdeArchivo(int cantidadEmpleados, int eliminados);
// Busca un empleado por legajo en el archivo 'empleados.txt' y lo 'elimina'
void eliminarEmpleadoPorLegajo(Empleado empleados[], int legajo, int cantidadEmpleados, int * eliminados);
void eliminarEmpleadoVectorPorLegajo(Empleado empleados[], int legajo, int cantidadEmpleados, int *eliminados);
void menu(Empleado empleados[], int cantidadEmpleados);
/* ==== Funcion main ==== */
int main()
{
int cantidadEmpleados = 100;
Empleado empleados[cantidadEmpleados];
menu(empleados, cantidadEmpleados);
return 0;
}
/* ==== Implementaciones ==== */
Empleado cargarEmpleadoPorTeclado()
{
Empleado empleado;
printf("\nIngrese el Nombre y Apellido del empleado: ");
fflush(stdin);
gets(empleado.nombreApellido);
printf("\nIngrese el numero de Legajo del empleado: ");
fflush(stdin);
scanf("%d", &empleado.legajo);
empleado.sueldo = 80000 + rand() % (200000-80000);
return empleado;
}
void cargarEmpleadosPorTeclado(Empleado empleados[], int cantidadEmpleados)
{
for (int i = 0; i < cantidadEmpleados; i++)
{
empleados[i] = cargarEmpleadoPorTeclado();
}
guardarEmpleados(empleados, cantidadEmpleados);
}
Empleado parsearEmpleado(char datosSinParsear[], int largoDatos)
{
Empleado empleado;
int delimitador1 = -1;
int delimitador2 = -1;
char auxiliarLegajo[10] = " ";
char auxiliarNombreApellido[30] = " ";
char auxiliarSueldo[10] = " ";
for(int i = 0; i < largoDatos; i++)
{
// Recorro el string hasta encontrar la primera ocurrencia
// Notese que i = largoDatos es para forzar la salida del for y no sobreescribir el valor de delimitador1
// con la segunda ocurrencia
if(datosSinParsear[i] == ';')
{
delimitador1 = i;
i = largoDatos;
}
}
// Recorro el string a partir de la posicion siguiente de la primera ocurrencia
for (int i = delimitador1 + 1; i < largoDatos; i++)
{
if (datosSinParsear[i] == ';')
{
delimitador2 = i;
}
}
if ((delimitador1 != -1) && (delimitador2 != -1))
{
// Desde 0 hasta delimitador1 tenemos el legajo
for (int i = 0; i < delimitador1; i++)
{
auxiliarLegajo[i] = datosSinParsear[i];
}
// Desde delimitador1+1 hasta delimitador2 tenemos el nombre y apellido
for (int i = delimitador1 + 1; i < delimitador2; i++)
{
auxiliarNombreApellido[i - delimitador1 - 1] = datosSinParsear[i];
}
// Desde delimitador2+1 hasta largoDatos tenemos el sueldo en float
for (int i = delimitador2 + 1; i < strlen(datosSinParsear); i++)
{
auxiliarSueldo[i - delimitador2 - 1] = datosSinParsear[i];
}
empleado.legajo = atoi(auxiliarLegajo);
strcpy(empleado.nombreApellido, auxiliarNombreApellido);
empleado.sueldo = atof(auxiliarSueldo);
return empleado;
}
}
void cargarEmpleadosEnVector(Empleado empleados[], int cantidadEmpleados)
{
// Intentamos abrir el archivo y verificamos si no es un puntero nulo
FILE * archivoEmpleados = fopen("empleados.txt", "r");
if(archivoEmpleados != NULL)
{
int i = 0;
while (!feof(archivoEmpleados) && (i < cantidadEmpleados))
{
char datosSinParsear[50] = "";
Empleado empleadoActual;
// Leemos los datos y lo parseamos
fgets(datosSinParsear, 50, archivoEmpleados);
empleadoActual = parsearEmpleado(datosSinParsear, 50);
// Lo asignamos a la posicion actual del vector 'empleados[]'
empleados[i] = empleadoActual;
i++;
}
fclose(archivoEmpleados);
}
// Si el archivo no existe o no lo encuentra
else
{
printf("\nImposible leer los empleados\nEl archivo \"empleados.txt\" no existe o no se encuentra en la ruta actual");
exit(-1);
}
}
void guardarEmpleados(Empleado empleados[], int cantidadEmpleados)
{
// Intentamos abrir el archivo y verificamos si no es un puntero nulo
FILE * archivoEmpleados = fopen("empleados.txt", "w");
if(archivoEmpleados != NULL)
{
for (int i = 0; i < cantidadEmpleados; i++)
{
// Grabamos los datos linea por linea con el formato 'legajo;nombreapellido;sueldo'
fprintf(archivoEmpleados, "%d;%s;%.2f\n", empleados[i].legajo, empleados[i].nombreApellido, empleados[i].sueldo);
}
printf("\nEmpleados guardados exitosamente en \"empleados.txt\"");
fclose(archivoEmpleados);
}
// Si el archivo no existe o no lo encuentra
else
{
printf("\nImposible guardar los empleados\nEl archivo \"empleados.txt\" no existe o no se encuentra en la ruta actual");
exit(-1);
}
}
void mostrarEmpleadosDesdeArchivo(int cantidadEmpleados, int eliminados)
{
FILE * archivoEmpleados = fopen("empleados.txt", "r");
int i = 0;
while(!feof(archivoEmpleados) && i < (cantidadEmpleados-eliminados))
{
char datosSinParsear[50] = "";
fgets(datosSinParsear, 50, archivoEmpleados);
Empleado empleadoActual;
empleadoActual = parsearEmpleado(datosSinParsear, 50);
printf("\nEmpleado");
printf("\n\t* Numero de legajo: %d", empleadoActual.legajo);
printf("\n\t* Nombre y Apellido: %s", empleadoActual.nombreApellido);
printf("\n\t* Sueldo (en pesos): %.2f", empleadoActual.sueldo);
i++;
}
fclose(archivoEmpleados);
}
/*
Esta funcion no elimina en si la linea que pertenezca al empleado
Sino mas bien, la omitiria cuando la lea, escribiendo un archivo nuevo con el mismo nombre
De esa forma, estariamos haciendo lo mismo
*/
void eliminarEmpleadoPorLegajo(Empleado empleados[], int legajo, int cantidadEmpleados, int *eliminados)
{
// Intentamos abrir el archivo y verificamos si no es un puntero nulo
FILE * archivoEmpleados = fopen("empleados.txt", "r");
// Creamos un nuevo archivo para escribir los datos
FILE * nuevoArchivoEmpleados = fopen("empleados2.txt", "w");
if(archivoEmpleados != NULL)
{
int i = 0;
while (!feof(archivoEmpleados) && i < cantidadEmpleados)
{
char datosSinParsear[50] = "";
Empleado empleadoActual;
// Recibimos los datos y los parseamos
fgets(datosSinParsear, 50, archivoEmpleados);
empleadoActual = parsearEmpleado(datosSinParsear, 50);
/*
Cuando no coincida el legajo, escribe
Si es que llega a coincidir (justamente ese debemos eliminar), no lo escribimos,
simplemente, hacemos una iteración y continuamos el bucle
*/
if (empleadoActual.legajo != legajo)
{
fprintf(nuevoArchivoEmpleados, "%d;%s;%.2f\n", empleadoActual.legajo, empleadoActual.nombreApellido, empleadoActual.sueldo);
i++;
}
else
{
i++;
continue;
};
}
fclose(archivoEmpleados);
fclose(nuevoArchivoEmpleados);
remove("empleados.txt");
rename("empleados2.txt", "empleados.txt");
eliminarEmpleadoVectorPorLegajo(empleados, legajo, cantidadEmpleados, &eliminados);
*eliminados = *eliminados + 1;
printf("\nEmpleado con legajo numero %d eliminado exitosamente", legajo);
}
// Si el archivo no existe o no lo encuentra
else
{
printf("\nImposible eliminar al empleado\nEl archivo \"empleados.txt\" no existe o no se encuentra en la ruta actual");
exit(-1);
}
}
void eliminarEmpleadoVectorPorLegajo(Empleado empleados[], int legajo, int cantidadEmpleados, int *eliminados)
{
int posicionDelElemento = -1;
for (int i = 0; i < cantidadEmpleados; i++)
{
if(empleados[i].legajo == legajo)
{
posicionDelElemento = i;
i = cantidadEmpleados;
}
}
for(int i = posicionDelElemento - 1; i<cantidadEmpleados-1; i++)
{
empleados[i] = empleados[i + 1];
}
cantidadEmpleados--;
}
void menu(Empleado empleados[], int cantidadEmpleados)
{
int sigue = 1;
int eliminados = 0;
int cantidadEmpleadosVar = 0;
printf("\nMenu Empleados\n");
printf("\nOpciones:\n");
printf("\n\t1. Listar los empleados");
printf("\n\t2. Agregar un empleado");
printf("\n\t3. Eliminar un empleado");
printf("\n\t4. Salir");
do
{
int opcion;
int legajo;
printf("\nIngrese opcion > ");
scanf("%d", &opcion);
switch (opcion)
{
case 1:
printf("\nMostrando empleados cargados");
mostrarEmpleadosDesdeArchivo(cantidadEmpleados, eliminados);
break;
case 2:
printf("\nAgregar un empleado:");
printf("\nCuantos empleados desea cargar? > ");
scanf("%d", &cantidadEmpleadosVar);
cargarEmpleadosPorTeclado(empleados, cantidadEmpleadosVar);
break;
case 3:
printf("\nEliminando un empleado:");
printf("\nIngrese el numero de legajo del empleado a eliminar > ");
scanf("%d", &legajo);
eliminarEmpleadoPorLegajo(empleados, legajo, cantidadEmpleados, &eliminados);
break;
case 4:
sigue = 0;
break;
default:
printf("\nLa opcion \"%d\" no es valida, ingrese otra vez\n\n", opcion);
continue;
break;
}
} while (sigue);
}
And the empleados.txt file is the following:
555666;Leandro;80041.00
232433;Juan;80945.00
234443;Antonio;90485.00
119304;Manuel;102943.00
The output is:
Code output linked on imgur
Does anyone know what this error could be?
There are many issues in your code, here are some important ones:
you must not use gets(): read Why is the gets function so dangerous that it should not be used?
you should test the return value of fgets() to determine if a line was read or if end of file has been reached.
using feof() for this purpose as you do is incorrect. You should read Why is “while( !feof(file) )” always wrong?
you should always test for fopen() success before calling any stream function with the FILE pointer.
Also use more spaces for indentation, 4 is recommended for readability.
I'm trying to read a bunch of information about a player from a binary file in c through the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// structure joueur
typedef struct Joueur {
char nom[20];
int num_lieu;
int liste_objet[10];
}Joueur;
// question a
void sauvegarder_jeu(char* nom_partie, Joueur* joueur) {
// ouverture du fichier
FILE *flot;
flot = fopen(nom_partie, "wb");
if (flot == NULL) {
printf("Erreur dans l'ouverture du fichier!\n");
return;
}
// écriture du nom du joueur
fwrite(joueur->nom, sizeof(joueur->nom), 1, flot);
// écriture du numero du lieu
fwrite(&(joueur->num_lieu), sizeof(joueur->num_lieu), 1, flot);
// écriture de la liste des objets
fwrite(joueur->liste_objet, sizeof(joueur->liste_objet), 1, flot);
// fermeture du fichier
fclose(flot);
}
// question b
void charger_jeu(char* nom_partie, char* nom, int* num_lieu, int* liste_objet) {
// ouverture du fichier
FILE *flot;
flot = fopen(nom_partie, "rb");
if (flot == NULL) {
printf("Erreur dans l'ouverture du fichier!\n");
return;
}
// joueur temp pour sizeof
Joueur *temp = (Joueur*)malloc(sizeof(Joueur));
// lecture du nom du joueur
fread(nom, sizeof(temp->nom), 1, flot);
// écriture du numero du lieu
fread(&num_lieu, sizeof(temp->num_lieu), 1, flot);
// écriture de la liste des objets
fread(liste_objet, sizeof(temp->liste_objet), 1, flot);
// suppression du joueur temporaire
free(temp);
// fermeture du fichier
fclose(flot);
}
int main() {
// variables
char *nom_partie = "save.sve";
int i;
int* num_lieu_lecture;
int* liste_objet_lecture;
char* nom_lecture;
// creation d'un joueur qui possede tous les objets
Joueur *j1 = (Joueur*)malloc(sizeof(Joueur));
strcpy(j1->nom, "Omar");
j1->num_lieu = 12;
for (i = 0; i < 10; i++) {
j1->liste_objet[i] = 1;
}
// sauvegarde de la partie
sauvegarder_jeu(nom_partie, j1);
printf("Sauvegarde terminee!\n");
// lecture de la partie
charger_jeu(nom_partie, nom_lecture, num_lieu_lecture, liste_objet_lecture);
printf("Chargement terminee!\n");
// affichage des donnees de la partie
printf("%s\n", nom_lecture);
printf("%d\n", *num_lieu_lecture);
for (i = 0; i < 10; i++) {
printf("liste_objet[%d] = %d\n", i, liste_objet_lecture[i]);
}
// liberation de la memoire
free(j1);
return 0;
}
The function "sauvegarder_jeu()" writes the player's data into a binary file, and the "charger_jeu()" is supposed to read that data and store into variables that I would print out.
The output, where all the values are correct expect for the "num_lieu_lecture" value:
Omar
32759
liste_objet[0] = 1
liste_objet[1] = 1
liste_objet[2] = 1
liste_objet[3] = 1
liste_objet[4] = 1
liste_objet[5] = 1
liste_objet[6] = 1
liste_objet[7] = 1
liste_objet[8] = 1
liste_objet[9] = 1
I don't know where the problem stems from.
The variables you're passing to charger_jeu() do not need to be pointers. num_liste_objet should be int, and liste_objet_lecture and nom_lecture should be arrays.
Then you should pass the address of num_liste_objet to charger_jeu(), so it will update the variable. In charger_jeu() you don't need to use & before num_lieu because it's already a pointer.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// structure joueur
typedef struct Joueur {
char nom[20];
int num_lieu;
int liste_objet[10];
}Joueur;
// question a
void sauvegarder_jeu(char* nom_partie, Joueur* joueur) {
// ouverture du fichier
FILE *flot;
flot = fopen(nom_partie, "wb");
if (flot == NULL) {
printf("Erreur dans l'ouverture du fichier!\n");
return;
}
// écriture du nom du joueur
fwrite(joueur->nom, sizeof(joueur->nom), 1, flot);
// écriture du numero du lieu
fwrite(&(joueur->num_lieu), sizeof(joueur->num_lieu), 1, flot);
// écriture de la liste des objets
fwrite(joueur->liste_objet, sizeof(joueur->liste_objet), 1, flot);
// fermeture du fichier
fclose(flot);
}
// question b
void charger_jeu(char* nom_partie, char* nom, int* num_lieu, int* liste_objet) {
// ouverture du fichier
FILE *flot;
flot = fopen(nom_partie, "rb");
if (flot == NULL) {
printf("Erreur dans l'ouverture du fichier!\n");
return;
}
// joueur temp pour sizeof
Joueur *temp = (Joueur*)malloc(sizeof(Joueur));
// lecture du nom du joueur
fread(nom, sizeof(temp->nom), 1, flot);
// écriture du numero du lieu
fread(num_lieu, sizeof(temp->num_lieu), 1, flot);
// écriture de la liste des objets
fread(liste_objet, sizeof(temp->liste_objet), 1, flot);
// suppression du joueur temporaire
free(temp);
// fermeture du fichier
fclose(flot);
}
int main() {
// variables
char *nom_partie = "save.sve";
int i;
int num_lieu_lecture;
int liste_objet_lecture[10];
char nom_lecture[20];
// creation d'un joueur qui possede tous les objets
Joueur *j1 = (Joueur*)malloc(sizeof(Joueur));
strcpy(j1->nom, "Omar");
j1->num_lieu = 12;
for (i = 0; i < 10; i++) {
j1->liste_objet[i] = 1;
}
// sauvegarde de la partie
sauvegarder_jeu(nom_partie, j1);
printf("Sauvegarde terminee!\n");
// lecture de la partie
charger_jeu(nom_partie, nom_lecture, &num_lieu_lecture, liste_objet_lecture);
printf("Chargement terminee!\n");
// affichage des donnees de la partie
printf("%s\n", nom_lecture);
printf("%d\n", *num_lieu_lecture);
for (i = 0; i < 10; i++) {
printf("liste_objet[%d] = %d\n", i, liste_objet_lecture[i]);
}
// liberation de la memoire
free(j1);
return 0;
}
#include<stdio.h>
#include<stdio.h>
#include<windows.h>
typedef int tab[20];
int Size,Operation;
void SaisirNombreComptes(void)
{
printf("Merci davoir saisir le nombre des comptes bancaire: ");scanf("%i",&Size);
}
void SaisirComptesEtSoldes(tab TabComptes, tab TabSoldes, int Size)
{
for(int i=1;i<=Size;i++)
{
printf("donner le numero du compte %i: ",i);scanf("%i",&TabComptes[i]);
printf("saisir l& solde du compte {%i} TND: ",TabComptes[i]);scanf("%i",&TabSoldes[i]);
}
}
void AfficherComptesInfo(tab TabComptes, tab TabSoldes, int Size)
{
printf("Tableau des comptes");
printf("\n");
for(int i=1;i<=Size;i++)
{
printf("[%i]",TabComptes[i]);
}
printf("\n");
printf("Tableau des Soldes");
printf("\n");
for(int i=1;i<=Size;i++)
{
printf("[%i]",TabSoldes[i]);
}
printf("\n");
printf("\n");
}
int RechercherComptePos(tab TabComptes, int Size, int x)
{
int i=1;
int Pos;
while( (i<=Size) && (TabComptes[i] != x) )
{
i+=1;
}
if(i<=Size)
Pos = i;
else
Pos = -1;
return Pos;
}
void AjouterCompte(tab TabComptes, tab TabSoldes, int *Size, int Compte, int Montant)
{
*Size = *Size + 1;
TabComptes[*Size] = Compte;
TabSoldes[*Size] = Montant;
}
void SupprimerCompte(tab TabComptes, tab TabSoldes, int *Size, int Compte)
{
int ComptePos = RechercherComptePos(TabComptes,*Size,Compte);
for(int i=ComptePos;i<=*Size;i++)
{
TabComptes[i] = TabComptes[i+1];
TabSoldes[i] = TabSoldes[i+1];
}
*Size = *Size - 1;
}
void DesposerSoldes(tab TabComptes, tab TabSoldes, int Size, int Compte, int Montant)
{
int ComptePos = RechercherComptePos(TabComptes,Size,Compte);
TabSoldes[ComptePos]+=Montant;
}
void RetirerSoldes(tab TabComptes, tab TabSoldes, int Size, int Compte, int Montant)
{
int ComptePos = RechercherComptePos(TabComptes,Size,Compte);
TabSoldes[ComptePos]-=Montant;
}
void TransfererSoldes(tab TabComptes, tab TabSoldes,int Size,int Compte1, int Compte2, int Montant)
{
int Transferer = RechercherComptePos(TabComptes,Size,Compte1);
int Recevoir = RechercherComptePos(TabComptes,Size,Compte2);
if(TabSoldes[Transferer]>=Montant)
{
TabSoldes[Transferer] -= Montant;
TabSoldes[Recevoir] += Montant;
}
else
{
printf("Operation echoue, solde insuffisante");
}
}
void Menu(void)
{
system("cls");
printf("\n\nChoisir un Operation a faire :\n1:Ajouter un Compte:\n2:Supprimer un Compte\n3:Desposer un Solde\n4:Retirer un solde\n5:Transfer un montant\n6:Afficher les information du compte\nTaper quelque touche pour quitter" );
scanf("%i",&Operation);
}
int main()
{
tab TabSoldes,TabComptes;
int NumCompte,Montant,NumCompte1,NumCompte2,i;
bool encore = true;
char AfficheMenu;
i = 0;
SaisirNombreComptes();
SaisirComptesEtSoldes(TabComptes,TabSoldes,Size);
Menu();
while(encore == true)
{
switch(*Operation)
{
case 1:
printf("Donner le numero du compte a ajouter :");scanf("%i",&NumCompte);
printf("Donner le Montant");scanf("%i",&Montant);
AjouterCompte(TabComptes,TabSoldes,&Size,NumCompte,Montant);
printf("Voulez-vous voir le menu Taper 'O' pour OUI 'N' pour NON");scanf("%c",&AfficheMenu);
if((AfficheMenu=='O') || (AfficheMenu=='o'))
{
Menu();
}
else if(AfficheMenu=='N' || AfficheMenu=='n')
encore = false;
else
printf("error");
break;
case 2:
printf("Donner le numero du compte a supprimer :");scanf("%i",&NumCompte);
SupprimerCompte(TabComptes,TabSoldes,&Size,NumCompte);
printf("Voulez-vous voir le menu Taper 'O' pour OUI 'N' pour NON");scanf("%c",&AfficheMenu);
if((AfficheMenu == 'O') || (AfficheMenu == 'o'))
{
Menu();
}
else if(AfficheMenu == 'N' || AfficheMenu =='n')
encore = false;
else
printf("error");
break;
case 3:
printf("Donner le numero du compte pour desposer d'argent: ");scanf("%i",&NumCompte);
printf("Donner le montant: ");scanf("%i",&Montant);
DesposerSoldes(TabComptes,TabSoldes,Size,NumCompte,Montant);
printf("Voulez-vous voir le menu Taper 'O' pour OUI 'N' pour NON");scanf("%c",&AfficheMenu);
if((AfficheMenu == 'O') || (AfficheMenu == 'o'))
{
Menu();
}
else if(AfficheMenu == 'N' || AfficheMenu =='n')
encore = false;
else
printf("error");
break;
case 4:
printf("Donner le numero du compte pour retirer d'argent: ");scanf("%i",&NumCompte);
printf("Donner le montant: ");scanf("%i",&Montant);
RetirerSoldes(TabComptes,TabSoldes,Size,NumCompte,Montant);
printf("Voulez-vous voir le menu Taper 'O' pour OUI 'N' pour NON");scanf("%c",&AfficheMenu);
if((AfficheMenu == 'O') || (AfficheMenu == 'o'))
{
Menu();
}
else if(AfficheMenu == 'N' || AfficheMenu =='n')
encore = false;
else
printf("error");
break;
case 5:
printf("Donner le numero du compte: ");scanf("%i",&NumCompte1);
printf("Donner le numero du compte destinaire: ");scanf("%i",&NumCompte2);
printf("Donner le montant a transferer");scanf("%i",&Montant);
TransfererSoldes(TabComptes,TabSoldes,Size,NumCompte1,NumCompte2,Montant);
printf("Voulez-vous voir le menu Taper 'O' pour OUI 'N' our NON");scanf("%c",&AfficheMenu);
if((AfficheMenu == 'O') || (AfficheMenu == 'o'))
{
Menu();
}
else if(AfficheMenu == 'N' || AfficheMenu =='n')
encore = false;
else
printf("error");
break;
case 6:
AfficherComptesInfo(TabComptes,TabSoldes,Size);
printf("Voulez-vous voir le menu Taper 'O' pour OUI 'N' our NON");scanf("%c",&AfficheMenu);
if((AfficheMenu == 'O') || (AfficheMenu == 'o'))
{
Menu();
}
else if(AfficheMenu == 'N' || AfficheMenu =='n')
encore = false;
else
printf("error");
break;
}
i=i+1;
printf("\n%i\n",i);
}
}
This program correct in syntaxe but there a probleme in excution mode (Output) when i try for exemple to add an account number it adds it twice in the table Consider we have two tables.
TabAccounts:[112566][256325][122662]
TabMoney :[ 200$ ][ 400$ ][ 257$ ]
So if i choose from the menu "1" : wihch mean add an account with montant it will add the account and montant twice like this for exemple:letssay i wanna add another account with number of 10066854 and montant 300$ it will output like this
TabAccounts:[112566][256325][122662][10066854 ][10066854 ]
TabMoney :[ 200$ ][ 400$ ][ 257$ ][ 300$ ][ 300$ ]
if anyone can help i will apperciate that i spend 3 days looking for the problem
When I try to execute my program, I get an error. I can't read the last value in "ch":
int choi(char *Tvide[48])//permet de choisir la place selon les choix de l utilisateur
{
char fum, classe, pos;
printf("\n S.V.P choisissez votre Classe (A:1 ere classe )/(B: 2 eme classe): ");
classe = getche();
printf("\n Est ce que vous etes fumeur (O:fumeur)/(N:non fumeur):");
fum = getche();
printf("\n S.V.P vous preferez s''assoir pres de la fenetre ou du couloir(C:couloir )/(F:fenetre):");
pos=getche();
int Tfum[24] = {3,4,7,8,11,12,15,16,19,20,23,24,27,28,31,32,35,36,39,40,43,44,47,48};
int Tnfum[24] = {1,2,5,6,9,10,13,14,17,18,21,22,25,26,29,30,33,34,37,38,41,42,45,46};
int Tfen[24] = {1,4,5,8,9,12,13,16,17,20,21,24,25,28,29,32,33,36,37,40,41,44,45,48};
int Tcol[24] = {2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31,34,35,38,39,42,43,46,47};
int k;
char Tdispo[48];
for(k=1; k<=48; k++) { Tdispo[k]='o'; } // on met içi le tableau des places vides
if (classe=='A')
{
for(k=9;k<=48;k++) { Tdispo[k]='n'; }
}
if (classe=='B')
{
for(k=1;k<=9;k++) { Tdispo[k]='n'; }
}
if (fum=='O')
{
for(k=1;k<=24;k++) { Tdispo[Tnfum[k]]='n'; }
}
if (fum=='N')
{
for(k=1;k<=24;k++) { Tdispo[Tfum[k]]='n'; }
}
if (pos=='C')
{
for(k=1;k<=24;k++) { Tdispo[Tfen[k]]='n'; }
}
if (pos=='F')
{
for(k=1; k<=24; k++) { Tdispo[Tcol[k]]='n'; }
}
int s;
printf("Les places disponibles sont:");
for(s=1; s<=48; s++)
{
if(Tdispo[s] == 'o') { printf("%d",s,"~"); }
}
int ch;
printf("\n S.V.P introduire votre choix :");
scanf("%d",ch);
Tvide[ch]=='n';
int ch1 = ch;
return ch1;
}
What could be causing this behavior?
You should have
scanf("%d",&ch);
not
scanf("%d",ch);
Because the result of scanf gets stored in the variable named ch.
Your main problem is that C uses 0-based arrays. A array of size 24 iss accessed 0 to 23) but you access them from 1 to 24, thus the last access is outside the array.