Struktury i błąd dostępu do zapisu

Struktury i błąd dostępu do zapisu
GO
  • Rejestracja:około 6 lat
  • Ostatnio:9 dni
  • Postów:92
0

Witam
piszę program, w którym tworzę następujące struktury:

Kopiuj
typedef struct Card
{
	char color;
	int face;
}CardT;

typedef struct Player
{
	char side;
	Card *card;
}PlayerT;

typedef struct Deal
{
	Player *Gracze;
	int PointsNS;
	int PointsEW;
}DealT;

w funkcji main inicjalizuję je poprzez funkcję

Kopiuj
void InitStruct(DealT *Rozdanie)
{
	Rozdanie->Gracze = (PlayerT*)malloc(sizeof(PlayerT) * PLAYERS);
	for (int i = 0; i < 4; i++)
	{
		Rozdanie->Gracze[i].side = '\0';
		Rozdanie->Gracze[i].card = (CardT*)malloc(sizeof(CardT) * FACE);
		for (int j = 0; j < 14; j++)
		{
			
			Rozdanie->Gracze[i].card[j].color = 'A'+j;
			Rozdanie->Gracze[i].card[j].face = 1+j;
			printf("%c%d ", Rozdanie->Gracze[i].card[j].color, Rozdanie->Gracze[i].card[j].face);

		}
		printf("\n");
	}
}

Następnie w funkcji, która operuje na tej strukturze próbuję wczytać dane z pliku i przypisać je do odpowiednich pól

Kopiuj
void WczytajRozdanie(DealT *Rozdanie)
{
	char temp[3] = { '\0' };
	char linia[LINE_SIZE] = { '\0' };
	FILE *FileT = fopen("C:\\Users\\GONSKABALBINKA\\Desktop\\rozdanie.txt", "r");
	if (Rozdanie == NULL)
	{
		printf("Nie mozna otworzyc pliku\n");
		return;
	}

	while (fgets(linia, LINE_SIZE, FileT) != NULL)
	{
		for(int i=0;i<PLAYERS;i++)
		{
			Rozdanie->Gracze[i].side = linia[0];
			for (int j = 0, len =2 ; j < FACE; j++, len += 3)
			{
				sprintf(temp, "%2s", linia + len);

				Rozdanie->Gracze[i].card[j].color = temp[1]; // W tym miejscu wyrzuca mi wyjątek

Kiedy próbuję przypisać dane do odpowiednich pól otrzymuję komunikat: Zgłoszono nieobsługiwany wyjątek: naruszenie dostępu do odczytu.
Gdzie może być błąd

edytowany 1x, ostatnio: gonskabalbinka
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1

i < 4

vs

i<PLAYERS

trochę mnie martwi. Alokujesz PLAYERS graczy, ale inicjalizujesz tylko 4. Analogicznie dalej w jednym miejscu masz jakieś hardkodowane indeksy, a w drugim jakieś stałe i nie wiadomo czy to te same wartości, a pewnie nie.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 2x, ostatnio: Shalom
GO
Bo ma być tylko 4 graczy zdefiniowałem ich liczbę #define PLAYERS 4
GO
Jeśli chodzi o te stałe to jest OK. Tak na szybko to wklejałem i nie poprawiłem wszędzie
Shalom
Analogicznie masz jakeiś j < FACE a w innym miejscu 14 i znów nie wiadomo czy to są te same wartości.
Shalom
W ogóle nie rozumiem czemu rozbijasz to na 2 osobne metody. Czemu nie alokujesz tam gdzie czytasz dane?
GO
Chciałem, żeby to było zrobione w dwóch oddzielnych funkcjach. Próbowałem już alokować dane i wczytywać do nich w jednej funkcji i dalej mam ten sam błąd wyjątek do odczytu. Rozdanie->Gracze[i].side = linia[0]; // tutaj wszystko działa bez zarzutu
AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 3 lata
  • Postów:1493
3
  1. Zbuduj z -ggdb3 -fsanitize=address.
  2. Podaj prawidłowo przeklejony kod, póki co Twoje struktury się nie skompilują nawet. Generalnie zawężenie problemu do minimum bym się przydało. Jak wołasz InitStruct a potem wczytywanie? Podaj MRE albo chociaż pokaż całość kodu od zawołania InitStruct aż do WczytajRozdanie
  3. Jaki jest LINE_SIZE?
    Poza konkursem raczej:
  4. Nie rzutuj malloca.
GO
  • Rejestracja:około 6 lat
  • Ostatnio:9 dni
  • Postów:92
0

Poniżej cały kod

Kopiuj
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>


#define LINE_SIZE 41
#define COLOR 4
#define FACE 13
#define PLAYERS 4

#pragma warning(disable : 4996)

typedef struct Card
{
	char color;
	int face;
}CardT;

typedef struct Player
{
	char side;
	Card *card;
}PlayerT;

typedef struct Deal
{
	Player *Gracze;
	int PointsNS;
	int PointsEW;
}DealT;


void WczytajRozdanie(DealT *Rozdanie)
{
	char temp[3] = { '\0' };
	char linia[LINE_SIZE] = { '\0' };
	FILE *FileT = fopen("C:\\Users\\GONSKABALBINKA\\Desktop\\rozdanie.txt", "r");
	if (Rozdanie == NULL)
	{
		printf("Nie mozna otworzyc pliku\n");
		return;
	}


	Rozdanie->Gracze = (PlayerT*)malloc(sizeof(PlayerT) * PLAYERS);
	while (fgets(linia, LINE_SIZE, FileT) != NULL)
	{
		for(int i=0;i<PLAYERS;i++)
		{
			
			Rozdanie->Gracze[i].card = (CardT*)malloc(sizeof(CardT) * FACE);
			Rozdanie->Gracze[i].side = linia[0];
			for (int j = 0, len =2 ; j < FACE; j++, len += 3)
			{
				sprintf(temp, "%2s", linia + len);

				Rozdanie->Gracze[i].card[j].color = temp[1];

				if ((temp[0] >= '0')&&(temp[0] <= '9'))
					Rozdanie->Gracze[i].card[j].face = temp[0] - '0';
				else if (temp[0] == 'T')
					Rozdanie->Gracze[i].card[j].face = 10;
				else if (temp[0] == 'J')
					Rozdanie->Gracze[i].card[j].face = 11;
				else if (temp[0] == 'Q')
					Rozdanie->Gracze[i].card[j].face = 12;
				else if (temp[0] == 'K')
					Rozdanie->Gracze[i].card[j].face = 13;
				else if (temp[0] == 'A')
					Rozdanie->Gracze[i].card[j].face = 14;
			}
		}

		printf("%s", linia);
		printf("\n\n");

	}

}




int main()
{
	DealT *Rozdanie = (DealT*)malloc(sizeof(DealT)*1);
	WczytajRozdanie(Rozdanie);
	


    return 0;
}

To trochę wygląda tak jakbym odwoływał się do miejsca w pamięci, które nie istnieje, ale przecież przydzielam pamięć mallociem

AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 3 lata
  • Postów:1493
0

To jeszcze dane wejściowe by się przydały do kompletu ale wygląda, że LINE_SIZE przekraczasz.
Dopisz (przed sprintfem)
printf("%d\n", len);
Raz jeszcze: czemu nie chcesz użyć -ggdb3 -fsanitize=address?

EDIT: widzę że to MSVC. Ale nadal w ramach szacunku do czytających wklejaj kompilujący się kod, bo wciąż nie trybi ;P

EDIT2: address sanitizer dla MSVC, proszę bardzo: https://docs.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-160

edytowany 3x, ostatnio: alagner
_13th_Dragon
  • Rejestracja:prawie 20 lat
  • Ostatnio:9 dni
2

Zastanów się nad zmianą modelu:

Kopiuj
typedef enum { spear,club,diamond,heart; } Color;
typedef enum { f2,f3,f4,f5, ... fJ,fQ,fK,fgA } Face;
typedef struct { Color color; Face face; } Card;
typedef enum { tail,player0,player1,player2,player3,player4,player5,player6; } Where;
typedef struct
{
    Where tale[13*4];
} Tale;

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
GO
Nie mogę musi pozostać tak jak jest.
AL
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 3 lata
  • Postów:1493
1

Przeanalizuj jak dokładnie działa %2s w printf i co się stanie jak będzie za dużo. LINE_SIZE - nie wiem,może też przekraczasz, ale na pewno nie tylko.

Hint:

Minimum number of characters to be printed. If the value to be printed is shorter than this number, the result is padded with blank spaces. The value is not truncated even if the result is larger.

edytowany 1x, ostatnio: alagner
GO
  • Rejestracja:około 6 lat
  • Ostatnio:9 dni
  • Postów:92
0
Kopiuj
strncat(temp,linia+len,2);
//albo
strncpy(temp, liniat+len,2);

Program debuguje się prawidłowo i wydaje się, że działa
Dzięki za odpowiedzi. Wielkie dzięki

edytowany 1x, ostatnio: gonskabalbinka
AL
sscanf(linia + len, "%2c", temp); ;) w scanf ta szerokość przy wczytywaniu znaków to dla odmiany ich dokładna liczba.
AL
Ale z dwóch przez Ciebie wymienionych czytelniejszy jest imho strncpy (czy lepszy - rzecz gustu...). BTW, masz też printfy z nką, snprintf np. działają analogicznie i są o tyle lepsze, że wsadzają na końcu stringa '\0', strncpy tego nie robi, sscanf też nie..

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.