How to fix Segfault due to recursive algorithm - c

I'm trying to code a perfect maze generator, but I have few problems in the code due to the recursion which leads to Segfault when the maze is too big. Here is the main part of the code:
t_maze *init_maze(int w, int h)
{
t_maze *maze;
int j;
int i;
if ((maze = malloc(sizeof(t_maze))) == NULL)
return (NULL);
maze->w = w;
maze->h = h;
if ((maze->cells = malloc(sizeof(char *) * maze->h)) == NULL)
return (NULL);
j = -1;
while (++j < maze->h)
{
if ((maze->cells[j] = malloc(sizeof(char) * maze->w)) == NULL)
return (NULL);
i = -1;
while (++i < maze->w)
maze->cells[j][i] = (j % 2 == 1 || i % 2 == 1) ? (1) : (0);
}
return (maze);
}
void detect_neighbours(t_maze *maze, char *neighbours, int x,
int y)
{
int i;
// I fill the array with 1 (means there is no neighbours)
// If there is a neighours, I set the cell to 0
// In this order: Top, right, bottom, left
i = -1;
while (++i < 4)
neighbours[i] = 1;
if (y - 2 >= 0 && x >= 0 && y - 2 < maze->h
&& x < maze->w && maze->cells[y - 2][x] == 0)
neighbours[0] = 0;
if (x + 2 >= 0 && x + 2 < maze->w && y >= 0 && y < maze->h
&& maze->cells[y][x + 2] == 0)
neighbours[1] = 0;
if (y + 2 < maze->h && y + 2 >= 0 && x >= 0
&& x < maze->w && maze->cells[y + 2][x] == 0)
neighbours[2] = 0;
if (x - 2 >= 0 && x - 2 < maze->w && y >= 0 && y < maze->h
&& maze->cells[y][x - 2] == 0)
neighbours[3] = 0;
}
int there_is_no_neighbours(char *neighbours)
{
int i;
// this function returns 0 if there is at least 1 neigbours
i = -1;
while (++i < 4)
if (neighbours[i] == 0)
i = 41;
if (i == 42)
return (0);
return (1);
}
void set_maze_protected(t_maze *maze, int y, int x, int val)
{
// To prevent segfault when I put values in the maze,
// I check the x and y keys
if (x >= 0 && y >= 0 && x < maze->w && y < maze->h)
maze->cells[y][x] = val;
}
int build_maze(t_maze *maze, int x, int y)
{
char neighbours[4];
int i;
int ret;
ret = 0;
detect_neighbours(maze, neighbours, x, y);
if (there_is_no_neighbours(neighbours) == 1)
return (0);
i = rand() % 4;
while (neighbours[i] == 1)
i = rand() % 4;
if (i == 0)
{
set_maze_protected(maze, y - 1, x, 2);
set_maze_protected(maze, y - 2, x, 2);
ret = build_maze(maze, x, y - 2);
}
if (i == 1)
{
set_maze_protected(maze, y, x + 1, 2);
set_maze_protected(maze, y, x + 2, 2);
ret = build_maze(maze, x + 2, y);
}
if (i == 2)
{
set_maze_protected(maze, y + 1, x, 2);
set_maze_protected(maze, y + 2, x, 2);
ret = build_maze(maze, x, y + 2);
}
if (i == 3)
{
set_maze_protected(maze, y, x - 1, 2);
set_maze_protected(maze, y, x - 2, 2);
ret = build_maze(maze, x - 2, y);
}
while (ret != 0)
ret = build_maze(maze, x, y);
return (1);
}
int main()
{
t_maze *maze;
int w;
int h;
w = 50;
h = 50;
srand(time(NULL) * getpid());
if ((maze = init_maze(w, h)) == NULL)
return (1);
maze->cells[0][0] = 2;
build_maze(maze, 0, 0);
// display_maze shows values in the 2D array (maze->cells)
display_maze(maze);
return (0);
}
I call this function in main with this call:
build_maze(maze, 0, 0);
The function detects is the cell has neighbours, and if it has, the function calls one of them randomly and open the door between the two.
If the x and y args are bigger than 2500 for example, it will segfault. (If it is less than 2500, it will work great)
How to fix this ?
I learnt about tail call but I ignore how to implement that in this case,
Thank you,
Best Regards

You can increase the stack size.
On POSIX systems, you can use the following code.
#include<stdio.h>
#include <sys/resource.h>
#define required_stack_size 0x8000000 // change this to the stack size you need
int main (int argc, char **argv)
{
struct rlimit rl;
int result;
if((result = getrlimit(RLIMIT_STACK, &rl)) < 0)
{
fprintf(stderr, "getrlimit returned result %d\n", result);
return -1;
}
if(rl.rlim_cur<required_stack_size)
{
rl.rlim_cur = required_stack_size;
if((result = setrlimit(RLIMIT_STACK, &rl)) < 0)
{
fprintf(stderr, "setrlimit returned result = %d\n", result);
return -1;
}
}
//the rest code
return 0;
}

Related

Not sure how to deal with the error "excess elements in array initializer"

In line 10 I cannot find out where my problem is at first. I place int a[100][100]={0} but the cpu speed is stuck.
Then, I try to change it into a[n][n] but no output is shown.
Last, I try to change it again as if it resembles the original ones.
However, nothing works instead of a new question.
#include<stdio.h>
int main() {
int n;
while (scanf("%d", &n)) {
n *= 2;
int x = 0, y = 0, num = 1;
int a[n][n] = {0};
a[x][y] = num++;
while (n * n >= num) //定義陣列
{
while (y + 1 < n && !a[x][y + 1]) //向右
a[x][++y] = num++;
while (x + 1 < n && !a[x + 1][y]) //向下
a[++x][y] = num++;
while (y - 1 >= 0 && !a[x][y - 1]) //向左
a[x][--y] = num++;
while (x - 1 >= 0 && !a[x - 1][y]) //向上
a[--x][y] = num++;
}
for (x = 0; x < n; x++) //print 陣列
{
for (y = 0; y < n; y++) {
if (y != n - 1) {
printf("%d ", a[x][y]);
} else {
printf("%d", a[x][y]);
}
}
printf("\n");
}
break;
}
return 0;
}
At least this problem:
Variable Length Arrays (VLA) cannot be initialized via the C standard.
Alternate, assign via memset() after defining a.
// int a[n][n]={0};
int a[n][n];
memset(a, 0, sizeof a);

Trying to understand why my script repeats

I am taking an online course with very little support. I am trying to follow instructions and write a script that takes input and draws two rectangles. Unfortunately, it just repeats infinitely, and I don't know what I'm missing. Any guidance would really help! Thank you so much for your help and time, this is my first post and I apologize for any formatting errors.
#include <stdio.h>
#include <stdlib.h>
/*
* Determines if coord is in range between
* offset (INCLUSIVE) and offset + size (EXCLUSIVE)
*/
int isInRange(int coord, int offset, int size) {
// if coord is in range, return 1
if ((coord >= offset) && (coord < (offset + size))) {
return 1;
}
// else, return 0
else {
return 0;
}
return 0;
}
/*
* Determines if coord is at border of offset or
* offset + size
*/
int isAtBorder(int coord, int offset, int size) {
// if coord is equal to offest or offset + size
if (coord == offset || (offset + size)) {
return 1;
}
// return 1, else return 0
else {
return 0;
}
return 0;
}
void squares(int size1, int x_offset, int y_offset, int size2) {
//compute the max of size1 and (x_offset + size2). Call this w
int w = (size1 + (x_offset + size2));
//compute the max of size1 and (y_offset + size2). Call this h
int h = (size1 + (y_offset + size2));
//count from 0 to h. Call the number you count with y
for (int y = 0; y < h; h++) {
//count from 0 to w. Call the number you count with x
for (int x = 0; x < w; x++) {
//check if EITHER
// ((x is between x_offset and x_offset +size2) AND
if (((isInRange(x, x_offset, size2) == 1) &&
// y is equal to either y_offset OR y_offset + size2 - 1)
(isAtBorder(y, y_offset, size2 - 1) == 1))
// OR
||
// ((y is between y_offset and y_offset + size2) AND
((isInRange(y, y_offset, size2) == 1) &&
// x is equal to either x_offset OR x_offset + size2 -1)
(isAtBorder(x, x_offset, size2-1)))) {
// if so, print a *
printf ("*");
}
//if not,
// check if EITHER
// x is less than size1 AND (y is either 0 or size1-1)
else {
if (((x < size1) && (isAtBorder(y, 0, size1 - 1) == 1))
// OR
||
// y is less than size1 AND (x is either 0 or size1-1)
((y < size1) && (isAtBorder(x, 0, size1 - 1) == 1))) {
//if so, print a #
printf ("#");
}
//else print a space
else {
printf (" ");
}
}
}
//when you finish counting x from 0 to w,
//print a newline
printf ("\n");
}
}
The real problem is, I suppose, in your squares function. Check out your for loop in this snippet:
for (int y = 0; y < h; h++) {
//count from 0 to w. Call the number you count with x
for (int x = 0; x < w; x++) {
In the first loop you're incrementing h, not y. Your "y" variable always stays at value which is equal 0, thus it won't finish this loop, since it will ALWAYS be smaller than "h" variable, unless "h" is less or equal than 0. You probably were aiming to increment "y" variable, not h.
After that, please check out your isAtBorder function. The "or" logical operator:
int isAtBorder(int coord, int offset, int size) {
// if coord is equal to offest or offset + size
if (coord == offset || (offset + size)) {
return 1;
}
// return 1, else return 0
else {
return 0;
}
return 0;
}
in the if statement is always true, so basically this function always returns 1.

why this recursive code only prints one answer?

I made this backtracking recursive code.
this code shows every 4x4 array filled with 1, 2, 3, 4
but no duplication in every one row and line.
but this prints only one answers, what I expected is every answers.
#include <stdio.h>
#include <stdbool.h>
// initializing array
void init_arr(int arr[][4])
{
int x;
int y;
y = 0;
while (y < 4)
{
x = 0;
while (x < 4)
{
arr[y][x] = 0;
x++;
}
y++;
}
}
// check about promising correct
bool promising(int arr[][4], int x, int y)
{
int i;
i = 0;
while (i < 4)
{
if (arr[y][i] == arr[y][x] && i != x)
return (0);
i++;
}
i = 0;
while (i < 4)
{
if (arr[i][x] == arr[y][x] && i != y)
return (0);
i++;
}
return (1);
}
// recursive function
void fill_arr(int arr[][4], int x, int y)
{
int n;
if (x == 0 && y == 0)
init_arr(arr);
if (y == 4)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
printf("%d ", arr[i][j]);
printf("\n");
}
printf("\n");
return ;
}
else if (x == 4)
fill_arr(arr, 0, y + 1);
else
{
n = 1;
while (n < 5)
{
arr[y][x] = n;
if (promising(arr, x, y))
fill_arr(arr, x + 1, y);
n++;
}
}
}
int main(void)
{
int arr[4][4];
fill_arr(arr, 0, 0);
return (0);
}
when I put printf in if(promising), this comes out
it looks like some variables are not initializing, but when I put init function to every other line, it getting messier.
Your fill_arr() isn't cleaning up before it leaves.
Add this line before the final brace:
arr[y][x] = 0;

Sudoku solver that returns number of solutions

I made a working sudoku solver using a basic backtracking algorithm.
It works reasonably well even though there are many optimizations to be done.
I tried modifying my code to return the total number of solutions for a given sudoku grid. To do this I simply changed the solving function to add up every possibility instead of stopping at one.
However I only get 1 or 0.
Here is the code for the basic solver:
int check_row(char **tab, int y, int n)
{
int i;
i = 0;
while (i < 9)
{
if (tab[y][i] == n + '0')
return (0);
i++;
}
return (1);
}
int check_column(char **tab, int x, int n)
{
int j;
j = 0;
while (j < 9)
{
if (tab[j][x] == n + '0')
return (0);
j++;
}
return (1);
}
int check_square(char **tab, int x, int y, int n)
{
int i;
int j;
i = (x / 3) * 3;
while (i < (x / 3) * 3 + 3)
{
j = (y / 3) * 3;
while (j < (y / 3) * 3 + 3)
{
if (tab[j][i] == n + '0')
return (0);
j++;
}
i++;
}
return (1);
}
int solve(char **tab, int x, int y)
{
int n;
if (y >= 9 || x >= 9)
return (1);
if (tab[y][x] == '.')
{
n = 1;
while (n < 10)
{
if (check_row(tab, y, n) && check_column(tab, x, n)
&& check_square(tab, x, y, n))
{
tab[y][x] = n + '0';
if (solve(tab, (x + 1) % 9, y + ((x + 1) / 9)))
return (1);
}
n++;
}
tab[y][x] = '.';
return (0);
}
else
return (solve(tab, (x + 1) % 9, y + ((x + 1) / 9)));
}
And here is the modified function that should count the solutions:
int solve_count(char **tab, int x, int y)
{
int n;
int count;
count = 0;
if (y >= 9 || x >= 9)
return (1);
if (tab[y][x] == '.')
{
n = 1;
while (n < 10)
{
if (check_row(tab, y, n) && check_column(tab, x, n)
&& check_square(tab, x, y, n))
{
tab[y][x] = n + '0';
count += solve_count(tab, (x + 1) % 9, y + ((x + 1) / 9));
}
n++;
}
tab[y][x] = '.';
return (count);
}
else
return (solve_count(tab, (x + 1) % 9, y + ((x + 1) / 9)));
}
The main() and helper functions are as follows:
#include <unistd.h>
int solve(char **tab, int x, int y);
int solve_count(char **tab, int x, int y);
void ft_putchar(char c)
{
write(1, &c, 1);
}
void ft_putstr(char *str)
{
int i;
i = 0;
while (*(str + i) != '\0')
{
ft_putchar(*(str + i));
i++;
}
}
void ft_putnbr(int n)
{
int i;
int vect[20];
long nb;
nb = n;
i = -1;
if (nb < 0)
{
ft_putchar('-');
nb = -nb;
}
if (nb == 0)
ft_putchar('0');
while (nb > 0)
{
i++;
vect[i] = nb % 10;
nb = nb / 10;
}
while (i > -1)
{
ft_putchar('0' + vect[i]);
i--;
}
}
int ft_check_input(int argc, char **argv)
{
int i;
int j;
i = 1;
j = 0;
if (argc != 10)
return (1);
while (i < argc)
{
while (argv[i][j])
j++;
if (j != 9)
return (1);
j = 0;
while (argv[i][j] == '.' || (argv[i][j] > '0' && argv[i][j] <= '9'))
j++;
if (j != 9)
return (1);
j = 0;
i++;
}
if (i != 10)
return (1);
else
return (0);
}
void ft_print_sudoku(char **tab)
{
int i;
int j;
i = 1;
j = 0;
while (i < 10)
{
while (j < 9)
{
ft_putchar(tab[i][j]);
if (j < 8)
ft_putchar(' ');
j++;
}
ft_putchar('\n');
j = 0;
i++;
}
}
int main(int argc, char **argv)
{
if (ft_check_input(argc, argv))
ft_putstr("Error: not a good sudoku\n");
else
{
if (solve(argv + 1, 0, 0))
{
ft_print_sudoku(argv);
ft_putnbr(solve_count(argv + 1, 0, 0));
}
else
ft_putstr("Error: no solution\n");
}
return (0);
}
To get the number of solutions for an empty sudoku you would run ('.' means empty item):
./sudoku "........." "........." "........." "........." "........." "........." "........." "........." "........."
It runs, but still stops at the first solution it finds, and returns 1.
What am I missing? I've been scratching my head for a while now.
Eventually I'm thinking of using this function to create a grid by adding random numbers until there's just one solution.
I Did this a long time ago for fun...
What I did to Solve the most difficult ones was to return for each squares, All possible numbers
And then destroy each possible numbers one by one for each grid...
so even if you get 9 possibilities for the first grid you enter the first and if it doesn't fit. you delete it and try the second.
One of them needs too fit :)
To know how may possible solutions to a soduku puzzle exists that would take a brute force calculation.

Minimum Dist Between 2 Elements in an given array

In a contest, they asked to write a C function which returns the minimum distance between X and Y in the given array, where X and Y are elements of the array Provided X AND Y ARE Distinct.
If have written a piece of code, but that code runs into many if's and else's,
My code (Has Some Bugs):
int getMinXYDist(int arr[],int n,int x,int y){
int i,flag = 0,ele = -1 ,dist = 0;
int minDist = 1000; // SETTING minDist TO MAX VALUE.
for( i = 0 ; i< n; i++)
if(arr[i] == x || arr[i] == y){
if(flag == 0){
flag = 1;
ele = arr[i]==x?x:y;
dist = 0;
}
else{
if(ele == x ){
if(arr[i] == y){
minDist = dist < minDist ? dist : minDist;
dist = 0;
ele = y;
}
else //if(arr[i] == x){
dist = 0;
}
else { //if(ele == y)
if(arr[i] == x){
minDist = dist < minDist ? dist : minDist;
dist = 0;
ele = x;
}
}
}
}
else {
if(flag == 1)
dist++;
}
return minDist;
}
void main(){
int arr = {6,1,5,1,8,6,3,4};
printf("\n%d" ,getMinXYDist(arr,sizeof(arr)/sizeof(int),6,5) ); //Must return 2.
}
Could Any one suggest a smarter way [ Just as in O(n) time complexity ] of calculating the distance?
If x or y is found, record the index it was found at. Once both have been found, each time you find either, compute distance to the last index containing the other value. Update the minimum value if the distance is lower than the previous minimum.
int getMinXYDist(int arr[],int n,int x,int y)
{
int i, indexX, indexY;
int foundX = 0;
int foundY = 0;
int curDist;
int minDist = n;
for (i = 0; i < n; i++)
{
if (arr[i] == x)
{
foundX = 1;
indexX = i;
if (foundX && foundY)
{
curDist = indexX - indexY;
if (curDist < minDist)
{
minDist = curDist;
}
}
}
else if (arr[i] == y)
{
foundY = 1;
indexY = i;
if (foundX && foundY)
{
curDist = indexY - indexX;
if (curDist < minDist)
{
minDist = curDist;
}
}
}
}
return minDist;
}
Basically, I think OP's solution is already optimum, the lower bound for this algorithm is n steps, i.e., done in one iteration.
// if -1 is returned, then none of x and y are in the array
// if n is returned, then one of x and y is not in the array
// otherwise, mindist(x, y) is returned.
int test(int v[], int n, int x, int y)
{
int flag = -1;
int i, a = -1, b = -1, dist = n;
for (i = 0; i < n; ++i) {
if (v[i] == x) {
flag = 0;
a = i;
break;
} else if (v[i] == y) {
flag = 1;
b = i;
break;
}
}
if (flag < 0) return -1; // x and y are both not in array;
for (++i; i < n; ++i) {
if (v[i] == x) {
if (0 == flag) a = i;
else {
flag = 0;
if (i - b < dist) dist = i - b;
a = i;
}
} else if (v[i] == y) {
if (1 == flag) b = i;
else {
flag = 1;
if (i - a < dist) dist = i - a;
b = i;
}
}
}
return dist;
}
int minDistance ( int arr[], int n, int x, int y) {
if(x == y) return 0;
int index1 = -1;
int index2 = -1;
int minvalue = n;
for(int i = 0 ; i < n; i++){
if((arr[i] == x) && ((i-index2) < minvalue)){
index1 = i;
if( index2 != -1)minvalue = i-index2;
}else if((arr[i] == y) && ((i-index1) < minvalue)){
index2 = i;
if( index1 != -1)minvalue = i-index1;
}
}
return minvalue;
}
where
n: size of array.
x and y: two input number of array.
If minvalue returned is n then x or y is not present in array.
complexity: O(n), One Pass.

Resources