[C] segfault gdzies w okolicach calloc

0

Program zwraca mi segmentation fault. Głównym podejrzanym jest funkcja alokująca pamięć pod tablicę struktur. Wygląda tak.

pole** rysuj (int a, int b, pole** plansza)
{
	int i;
	plansza=(pole**)calloc(a*b, sizeof (pole*));
	if (plansza==NULL)
	{
		printf ("BRAK PAMIECI");
		return NULL;
	}
	for (i=0; i<a; i++)
	{
		plansza[i]=(pole*)calloc(b, sizeof (pole));
		if (plansza[i]==NULL)
		{
			printf ("BRAK PAMIECI");
			return NULL;
		}
	}
	return plansza;
}
0

A nie wystarczy przypadkiem w pierwszej alokacji samo 'a' zamiast 'a*b' ?

W końcu najpierw alokujemy pamięć dla ilości rzędów, a następnie w każdym z nich alokujemy komórki kolumn.... :)

0
  1. po co ci argument plansza skoro od razu przypisujesz do tego własną wartość.
  2. nazwa funkcji jest niewspółmierna do jej funkcjonalności (prosisz się o kolejny błąd).

Ja takie tablice w C alokuję tak:

pole** alokujPlansze(int a, in b)
{
       pole** plansza;

       plansza = (pole**)malloc(a*sizeof(pole*) + a*b*sizeof(pole));

       if(plansza) 
       {
           for (int i=0; i<a; i++)
               plansza[i] = (pole*)(plansza+a)+i*b;
       }

       return plansza;
}

Czyli cała tablica jest w jednym kawałku pamięci, więc potem nawet jest łatwo zwolnić tą pamięć.

0

Niestety ta wersja też daje segfault.

0

A pokaż nam ja zwalniasz tą pamięć, albo jak z niej korzystasz. Bo przypuszczam ze segfault jest przy zwalnianiu /odwołaniu a nie przy alokacji...

0

Zwolnienia jeszcze nie mam zrobionego. Program wygąda tak, definicja struktury jest następująca, a segfault występuje zaraz po pobraniu wymiarów i ilości min.

typedef struct pole
	{
		int bomba;
		int odkryta;
		int zaznaczona;
		int wokol;
	} pole;
 #include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <ncurses.h>
#include <menu.h>
#include "typedefy.h"
#include "funkcjedef.h"

int check (int x, int y, pole** plansza)
{
	if((plansza[x][y].bomba == 1) && (plansza[x][y].odkryta = 1)) return 0;
	else return 1;
}
void losowanie (int miny, pole** plansza)
{
	int kolej, x, y;
	for (kolej=0; kolej==miny; kolej++)
	{
		x=rand()%(a+1);
		y=rand()%(b+1);
		if (plansza[x][y].bomba==0){
		plansza[x][y].bomba=1;}
		else kolej--;
	}
	
}
void zlicz (int x, int y, pole** plansza)
{
	int z = 0;
	if (plansza[x+1][y+1].bomba==1) z++;
	if (plansza[x+1][y].bomba==1) z++;
	if (plansza[x+1][y-1].bomba==1) z++;
	if (plansza[x][y-1].bomba==1) z++;
	if (plansza[x-1][y-1].bomba==1) z++;
	if (plansza[x-1][y].bomba==1) z++;
	if (plansza[x-1][y+1].bomba==1) z++;
	if (plansza[x][y+1].bomba==1) z++;
	z=plansza[x][y].wokol;
}
void rozszerz (int x, int y, pole** plansza)
{
	int k;
	int l;
	for (k=x, l=y; plansza[k][l].wokol!=0; k++, l++)
	{
	zlicz (k, l, plansza);
	rozszerz (k, l, plansza);
	}
	for (k=x, l=y; plansza[k][l].wokol!=0; k++, l--)
	{
	zlicz (k, l, plansza);
	rozszerz (k, l, plansza);
	}
	for (k=x, l=y; plansza[k][l].wokol!=0; k--, l++)
	{
	zlicz (k, l, plansza);
	rozszerz (k, l, plansza);
	}
	for (k=x, l=y; plansza[k][l].wokol!=0; k--, l--)
	{
	zlicz (k, l, plansza);
	rozszerz (k, l, plansza);
	}
}
int gra (pole** plansza)
{
	x=0;
	y=0;
	initscr();
	if (has_colors() == FALSE)
	{
		endwin();
		printf ("Nie mozna rozpocząć gry, terminal nie obsługuje kolorów");
		return 0;
	}
	start_color();
	init_pair(1, COLOR_WHITE, COLOR_BLUE);
	init_pair(2, COLOR_CYAN, COLOR_MAGENTA);
	init_pair(3, COLOR_BLUE, COLOR_RED);
	init_pair(4, COLOR_BLUE, COLOR_GREEN);
	init_pair(5, COLOR_BLUE, COLOR_YELLOW);
	init_pair(6, COLOR_BLUE, COLOR_BLACK);
	clear();
	MENU *mapa;
	mapa=new_menu((ITEM **) plansza);
	noecho();
	cbreak();
	keypad(stdscr, TRUE);
	mvprintw(0, 0, "Wybierz pole przy pomocy strzałek, odsłoń je enterem, lub jeśli uwazasz ze jest tam mina oznacz je spacja");
	char c;
	int highlight;
	for (x=0, y=0; nietrafione==0 && poprawne==miny; sprawdzam(plansza))
	{
		refresh();
		print_menu(stdscr, highlight, plansza);
		while(1)
		{	c = wgetch(stdscr);
			switch(c)
			{	case KEY_UP:
					menu_driver(mapa, REQ_UP_ITEM);
					break;
				case KEY_DOWN:
					menu_driver(mapa, REQ_DOWN_ITEM);
					break;
				case KEY_LEFT:
					menu_driver(mapa, REQ_LEFT_ITEM);
					break;
				case KEY_RIGHT:
					menu_driver(mapa, REQ_RIGHT_ITEM);
					break;
				case 10:
					plansza[x][y].odkryta=1;
					sprawdzam(plansza);
					if ((odkryte==1)&&(plansza[x][y].bomba==1))
					{
						plansza[x][y].bomba=0;
						losowanie (1, plansza);
					}
					if (check (x, y, plansza)==0)
					{
						mvprintw(0, -1, "Przegrana");
						odslon(plansza);
						getchar();
						return 0;
					}
					else 
					{
						zlicz(x, y, plansza);
						mvprintw(y, x, "%d", plansza[x][y].wokol);
					}
					break;
				case ' ':
					if (plansza[x][y].zaznaczona==0) plansza[x][y].zaznaczona=1;
					if (plansza[x][y].zaznaczona==1) plansza[x][y].zaznaczona=0;
					break;
			}
		}
		if (poprawne==miny && nietrafione==0) 
		{
			mvprintw (0, -1, "GRATULACJE! ZWYCIĘSTWO");
			odslon(plansza);
		}
	}
	return 0;
}
void sprawdzam (pole** plansza)
{
	int x, y;
	for (x=0; x<a; x++)
	{
		for (y=0; y<b; y++)
		{
			nietrafione = 0;
			poprawne = 0;			
			if ((plansza[x][y].zaznaczona==1)&&(plansza[x][y].bomba==0)) nietrafione++;
			if ((plansza[x][y].zaznaczona==0)&&(plansza[x][y].bomba==1)) nietrafione++;
			if ((plansza[x][y].zaznaczona==1)&&(plansza[x][y].bomba==1)) poprawne++;
			if (plansza[x][y].odkryta==1) odkryte++;
		}
	}
}
void odslon (pole** plansza)
{
	for (x=0; x<a; x++)
	{
		for (y=0; y<b; y++)
			{
				if ((plansza[x][y].bomba==1)&&(plansza[x][y].odkryta==1)) 
				{
					attron(COLOR_PAIR(3));
					mvprintw (x, y, "X");
					attroff(COLOR_PAIR(3));
				}
				if ((plansza[x][y].bomba==1)&&(plansza[x][y].zaznaczona==1)) 
				{
					attron(COLOR_PAIR(4));
					mvprintw (x, y, "X");
					attroff(COLOR_PAIR(4));
				}
				if ((plansza[x][y].bomba==1)&&(plansza[x][y].zaznaczona==0)) 
				{
					attron(COLOR_PAIR(5));
					mvprintw (x, y, "X");
					attroff(COLOR_PAIR(5));
				}
				if ((plansza[x][y].bomba==0)&&(plansza[x][y].zaznaczona==1)) 
				{
					attron(COLOR_PAIR(6));
					mvprintw (x, y, "X");
					attroff(COLOR_PAIR(6));
				}
				if ((plansza[x][y].bomba==0)&&(plansza[x][y].zaznaczona==0));
				{
					zlicz (x, y, plansza);
					{
						attron(COLOR_PAIR(1));
						mvprintw (x, y, "%d", plansza[x][y].wokol);
						attroff(COLOR_PAIR(1));
					}
				}
			}
	}
}
pole** alokacja (int a, int b)
{
	int i;
	pole** plansza;
	plansza=(pole**)calloc(a, sizeof (pole*));
	if (plansza==NULL)
	{
		printf ("BRAK PAMIECI");
		return NULL;
	}
	for (i=0; i<a; i++)
	{
		plansza[i]=(pole*)calloc(b, sizeof (pole));
		if (plansza[i]==NULL)
		{
			printf ("BRAK PAMIECI");
			return NULL;
		}
	}
	return plansza;
}
void print_menu(WINDOW *menu_win, int highlight, pole** plansza) 
{
	int x, y, i;	

	x = 2;
	y = 2;
	box(menu_win, 0, 0);
	for(i = 0; i < (a*b); ++i)
	{	if(highlight == i + 1)
		{	wattron(menu_win, A_REVERSE); 
			mvwprintw(menu_win, y, x, "%s", plansza[x][y]);
			wattroff(menu_win, A_REVERSE);
		}
		else
			mvwprintw(menu_win, y, x, "%s", plansza[x][y]);
		++y;
	}
	wrefresh(menu_win);
}
void wymiary()
{
	printf ("Witaj w grze Saper\nPodaj ilość wierszy: ");
	
		scanf ("%d", &b);
		if (b<MIN)
		{
			printf ("Za mało wierszy, ustalam ilość jako %d\n", MIN);
			b=MIN;
		}
	
		if (b>MAX)
		{
			printf ("Za dużo wierszy, ustalam ilość jako %d\n", MAX);
			b=MAX;
		}
	

	printf ("Podaj ilość kolumn: ");

		scanf ("%d", &a);
		if (a<MIN)

		{
			printf ("Za mało kolumn, ustalam ilość jako %d\n", MIN);
			a=MIN;
		}
	
		if (a>MAX)
		{
			printf ("Za dużo kolumn, ustalam ilość jako %d\n", MAX);
			a=MAX;
		}

		
	int maxminy = (0.9*(a*b));
	
	printf ("Podaj ilość min: ");

		scanf ("%d", &miny);
		if (miny<MIN)
		{
			printf ("Za mało min, ustalam ilość jako %d\n", MIN);
			miny=MIN;
		}
	
		if (miny>maxminy)
		{
			printf ("Za dużo min, ustalam ilość jako %d\n", maxminy);
			miny=maxminy;
		}
}
int main ()
{
	pole** plansza;
	wymiary ();
	alokacja (a, b);
	for (x=0; x<a; x++)
	{	
		for (y=0; y<b; y++)
		{
			plansza[x][y].bomba=0;
			plansza[x][y].odkryta=0;
			plansza[x][y].zaznaczona=0;
		}
	}
	gra (plansza);
	//tu bedzie zwolnienie
	return 0;
}

0

Poprawiłem linię na plansza=alokacja(a, b). Program przechodzi przez funkcję alokacji (sprawdziłem dodając odpowiednio printfy). Dla zmiany dodałem initscr na początku i wtedy segmentation fault pojawia się zaraz po włączeniu programu. Tutorial ncurses mówi że może czasem do tego dojść gdy brakuje pamięci na alokowanie struktur curses. Mam więc pytanie, czy w alokacji należy brać pod uwagę curses. Do alokacji używam calloca jak w poście wyżej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1