Implementing 8-Connectivity Hoshen-Kopelman Algorithm in C - c
I found here an implementation for Hoshen-Kopelman Algorithm, But it checks neighbors only up and left, meaning that a diagonal connection is not considered a connection.
How can I improve this code so that even a diagonal connection will be considered a connection?
In the following example I expect 1 object and not 7 objects:
4 5
1 0 1 0 1
0 1 0 1 0
1 0 1 0 0
0 0 1 0 0
--input--
1 0 1 0 1
0 1 0 1 0
1 0 1 0 0
0 0 1 0 0
--output--
1 0 2 0 3
0 4 0 5 0
6 0 7 0 0
0 0 7 0 0
HK reports 7 clusters found
This is the implementation (full code can be found here):
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
/* Implementation of Union-Find Algorithm */
/* The 'labels' array has the meaning that labels[x] is an alias for the label x; by
following this chain until x == labels[x], you can find the canonical name of an
equivalence class. The labels start at one; labels[0] is a special value indicating
the highest label already used. */
int* labels;
int n_labels = 0; /* length of the labels array */
/* uf_find returns the canonical label for the equivalence class containing x */
int uf_find(int x)
{
int y = x;
while (labels[y] != y)
y = labels[y];
while (labels[x] != x)
{
int z = labels[x];
labels[x] = y;
x = z;
}
return y;
}
/* uf_union joins two equivalence classes and returns the canonical label of the resulting class. */
int uf_union(int x, int y)
{
return labels[uf_find(x)] = uf_find(y);
}
/* uf_make_set creates a new equivalence class and returns its label */
int uf_make_set(void)
{
labels[0] ++;
assert(labels[0] < n_labels);
labels[labels[0]] = labels[0];
return labels[0];
}
/* uf_intitialize sets up the data structures needed by the union-find implementation. */
void uf_initialize(int max_labels)
{
n_labels = max_labels;
labels = calloc(sizeof(int), n_labels);
labels[0] = 0;
}
/* uf_done frees the memory used by the union-find data structures */
void uf_done(void)
{
n_labels = 0;
free(labels);
labels = 0;
}
/* End Union-Find implementation */
#define max(a,b) (a>b?a:b)
#define min(a,b) (a>b?b:a)
/* print_matrix prints out a matrix that is set up in the "pointer to pointers" scheme
(aka, an array of arrays); this is incompatible with C's usual representation of 2D
arrays, but allows for 2D arrays with dimensions determined at run-time */
void print_matrix(int** matrix, int m, int n)
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
printf("%3d ", matrix[i][j]);
printf("\n");
}
}
/* Label the clusters in "matrix". Return the total number of clusters found. */
int hoshen_kopelman(int** matrix, int m, int n)
{
uf_initialize(m * n / 2);
/* scan the matrix */
for (int y = 0; y < m; y++)
{
for (int x = 0; x < n; x++)
{
if (matrix[y][x])
{ // if occupied ...
int up = (y == 0 ? 0 : matrix[y - 1][x]); // look up
int left = (x == 0 ? 0 : matrix[y][x - 1]); // look left
switch (!!up + !!left)
{
case 0:
matrix[y][x] = uf_make_set(); // a new cluster
break;
case 1: // part of an existing cluster
matrix[y][x] = max(up, left); // whichever is nonzero is labelled
break;
case 2: // this site binds two clusters
matrix[y][x] = uf_union(up, left);
break;
}
}
}
}
/* apply the relabeling to the matrix */
/* This is a little bit sneaky.. we create a mapping from the canonical labels
determined by union/find into a new set of canonical labels, which are
guaranteed to be sequential. */
int* new_labels = calloc(sizeof(int), n_labels); // allocate array, initialized to zero
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
if (matrix[i][j])
{
int x = uf_find(matrix[i][j]);
if (new_labels[x] == 0)
{
new_labels[0]++;
new_labels[x] = new_labels[0];
}
matrix[i][j] = new_labels[x];
}
int total_clusters = new_labels[0];
free(new_labels);
uf_done();
return total_clusters;
}
/* This procedure checks to see that any occupied neighbors of an occupied site
have the same label. */
void check_labelling(int** matrix, int m, int n)
{
int N, S, E, W;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
if (matrix[i][j])
{
N = (i == 0 ? 0 : matrix[i - 1][j]);
S = (i == m - 1 ? 0 : matrix[i + 1][j]);
E = (j == n - 1 ? 0 : matrix[i][j + 1]);
W = (j == 0 ? 0 : matrix[i][j - 1]);
assert(N == 0 || matrix[i][j] == N);
assert(S == 0 || matrix[i][j] == S);
assert(E == 0 || matrix[i][j] == E);
assert(W == 0 || matrix[i][j] == W);
}
}
/* The sample program reads in a matrix from standard input, runs the HK algorithm on
it, and prints out the results. The form of the input is two integers giving the
dimensions of the matrix, followed by the matrix elements (with data separated by
whitespace).
a sample input file is the following:
8 8
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 1
1 0 0 0 0 1 0 1
1 0 0 1 0 1 0 1
1 0 0 1 0 1 0 1
1 0 0 1 1 1 0 1
1 1 1 1 0 0 0 1
0 0 0 1 1 1 0 1
this sample input gives the following output:
--input--
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 1
1 0 0 0 0 1 0 1
1 0 0 1 0 1 0 1
1 0 0 1 0 1 0 1
1 0 0 1 1 1 0 1
1 1 1 1 0 0 0 1
0 0 0 1 1 1 0 1
--output--
1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 1
2 0 0 0 0 2 0 1
2 0 0 2 0 2 0 1
2 0 0 2 0 2 0 1
2 0 0 2 2 2 0 1
2 2 2 2 0 0 0 1
0 0 0 2 2 2 0 1
HK reports 2 clusters found
*/
int main(int argc, char** argv)
{
int m, n;
int** matrix;
/* Read in the matrix from standard input
The whitespace-deliminated matrix input is preceeded
by the number of rows and number of columns */
while (2 == scanf_s("%d %d", &m, &n))
{ // m = rows, n = columns
matrix = (int**)calloc(m, sizeof(int*));
for (int i = 0; i < m; i++)
{
matrix[i] = (int*)calloc(n, sizeof(int));
for (int j = 0; j < n; j++)
scanf_s("%d", &(matrix[i][j]));
}
printf_s(" --input-- \n");
print_matrix(matrix, m, n);
printf(" --output-- \n");
/* Process the matrix */
int clusters = hoshen_kopelman(matrix, m, n);
/* Output the result */
print_matrix(matrix, m, n);
check_labelling(matrix, m, n);
printf("HK reports %d clusters found\n", clusters);
for (int i = 0; i < m; i++)
free(matrix[i]);
free(matrix);
}
return 0;
}
I tried to change the function hoshen_kopelman as described below, but I still get 2 objects instead of 1:
int hoshen_kopelman(int** matrix, int m, int n)
{
uf_initialize(m * n / 2);
/* scan the matrix */
for (int y = 0; y < m; y++)
{
for (int x = 0; x < n; x++)
{
if (matrix[y][x])
{ // if occupied ...
int up = (y == 0 ? 0 : matrix[y - 1][x]); // look up
int left = (x == 0 ? 0 : matrix[y][x - 1]); // look left
// ----------- THE NEW CODE -------------
if (x > 0)
{
if (up == 0 && y > 0) // left+up
up = matrix[y - 1][x - 1];
if (left == 0 && y < m - 1) // left+down
left = matrix[y + 1][x - 1];
}
// ---------- END NEW CODE --------------
switch (!!up + !!left)
{
case 0:
matrix[y][x] = uf_make_set(); // a new cluster
break;
case 1: // part of an existing cluster
matrix[y][x] = max(up, left); // whichever is nonzero is labelled
break;
case 2: // this site binds two clusters
matrix[y][x] = uf_union(up, left);
break;
}
}
}
}
/* apply the relabeling to the matrix */
/* This is a little bit sneaky.. we create a mapping from the canonical labels
determined by union/find into a new set of canonical labels, which are
guaranteed to be sequential. */
int* new_labels = calloc(sizeof(int), n_labels); // allocate array, initialized to zero
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
if (matrix[i][j])
{
int x = uf_find(matrix[i][j]);
if (new_labels[x] == 0)
{
new_labels[0]++;
new_labels[x] = new_labels[0];
}
matrix[i][j] = new_labels[x];
}
int total_clusters = new_labels[0];
free(new_labels);
uf_done();
return total_clusters;
}
The following output is now obtained (I am expecting 1 and got 2):
4 5
1 0 1 0 1
0 1 0 1 0
1 0 1 0 0
0 0 1 0 0
--input--
1 0 1 0 1
0 1 0 1 0
1 0 1 0 0
0 0 1 0 0
--output--
1 0 1 0 1
0 1 0 1 0
2 0 1 0 0
0 0 1 0 0
HK reports 2 clusters found
What is the correct way to correct the code to check all 8 neighbors?
I led you astray saying to check down-left. The algorithm relies on the current node it is examining being after all the neighbors it checks. So you need to check left, up, up-left, and up-right. You can use this in place of your new code:
if (y > 0)
{
if (left == 0 && x > 0) // left+up
left = matrix[y - 1][x - 1];
if (up == 0 && x < n-1) // right+up
up = matrix[y - 1][x + 1];
}
Related
How do I use a switch to offset the start of a for loop?
I am trying to make a game of checkers, and right now I'm building the board. The board is a 2-dimensional array of integers that I'm changing based on where the pieces should be. // Sets up Red Pieces int k = 0; for (i = 0; i < 3; i++) { for (j = k; j < 8; j += 2) { // Red piece is on square at coords [i][j] Board_Squares[i][j] += 2; } printf("\n"); // k starts at 0, and in switch should alternate between 1 and 0, switch (k) { case 0: k = 1; case 1: k = 0; } } However, this code only gives me this: 0 2 0 2 0 2 0 0 2 0 2 0 2 0 0 2 0 2 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Any help would be dope. Warning: I might be dumb. Also, is using the switch statement the right move here anyways?
the problem in your code comes from missing break statements: the code for a case fall through to the code for the next case. Modify it this way: switch (k) { case 0: k = 1; break; case 1: k = 0; break; } The same toggling effect can be obtained with simple expressions: k = 1 - k; k ^= 1; k = !k; k = k == 0; Or some more convoluted and obscure ones: k = !!!k; k = k ? 0 : 1; k = (k + 1) & 1; k = "\1"[k]; k = k["\1"]; k = 1 / (1 + k); The checker board cells can also be initialized directly to 0 and 1 as: Board_Squares[i][j] = (i + j) & 1;
Problems with test cases locally in C
hello my task to write test, which checks if the Minesweeper board (after choosing replay option) is different than the previous one. first of all i wrote the main function the replay. after that I tested it locally if it works and every game, every board was different. there was no issue. so i started to write test cases and now im here. TEST replay_board() { Game *game = create_game(); Board *board = create_board(9, 9, 9); game->board = board; int k = 0; printf("\n"); char mine_list[100]; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { if (game->board->tiles[i][j]->is_mine == true) { mine_list[k] = '1'; printf("1"); } else { mine_list[k] = '0'; printf("0"); } k++; } } printf("\n"); mine_list[k] = '\0'; replay_game(replay, game); char mine_list2[100]; k = 0; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { if (game->board->tiles[i][j]->is_mine == true) { mine_list2[k] = '1'; printf("1"); } else { mine_list2[k] = '0'; printf("0"); } k++; } } printf("\n"); mine_list2[k] = '\0'; int same = 0; if (strcmp(mine_list, mine_list2) != 0) { same = 0; } else { same = 1; } ASSERT_EQ(same, 0); PASS(); destroy_game(game); } in every test it writes that the old boar is the same as the previous one, but locally i can see that they aren't the same. i dont know its ideal to compare two strings, but it was the easiest way to compare them from structure replay function void replay_game(char* replay, Game* game) { while (strcmp(replay, "yes") != 0 && strcmp(replay, "no") != 0 ) { scanf("%s", replay); if (strcmp(replay, "yes") != 0 || strcmp(replay, "no") != 0) { printf("invalid value\n"); } } if (strcmp(replay, "yes") == 0) { destroy_board(game->board); game->game_state = PLAYING; game->board = create_board(9, 9, 9); game->player->score = 0; } } create_board function int generate_random_coordinates(int upper_range) { return rand() % upper_range; } /** * Generates random coordinates to row and column according to mine count value * Randomly sets mines to the Board pointer */ void set_mines_randomly(Board *board) { assert(board != NULL); int board_mine_count = 0; srand(time(NULL)); while (board_mine_count != board->mine_count) { int random_row = generate_random_coordinates(board->row_count); int random_column = generate_random_coordinates(board->column_count); if (board->tiles[random_row][random_column]->is_mine == false) { board->tiles[random_row][random_column]->is_mine = true; board_mine_count++; } } } Board *create_board(int row_count, int column_count, int mine_count) { Board *board = (Board *) calloc(1, sizeof(Board)); board->row_count = row_count; board->column_count = column_count; board->mine_count = mine_count; for (int row = 0; row < board->row_count; row++) { for (int column = 0; column < board->column_count; column++) { board->tiles[row][column] = (Tile *) calloc(1, sizeof(Tile)); board->tiles[row][column]->tile_state = CLOSED; board->tiles[row][column]->is_mine = false; } } set_mines_randomly(board); set_tile_values(board); return board; } main #include <stdlib.h> #include <string.h> #include "game.h" #include "user_interface.h" #include "board.h" int main() { char replay[] = "yes"; Game *game = create_game(); Board *board = create_board(9, 9, 9); game->board = board; read_player_name(game); // impleting the replay function while(strcmp(replay, "yes") == 0) { play_game(game); printf("Chcel by si znova zahrat? (yes/no)\n"); scanf("%3s", replay); printf("\n"); // new part char mine_list[100]; int k = 0; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { if (game->board->tiles[i][j]->is_mine == true) { mine_list[k] = '1'; //printf("1"); } else { mine_list[k] = '0'; //printf("0"); } k++; } } mine_list[k] = '\0'; replay_game(replay, game); char mine_list2[100]; k = 0; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { if (game->board->tiles[i][j]->is_mine == true) { mine_list2[k] = '1'; //printf("1"); } else { mine_list2[k] = '0'; //printf("0"); } k++; } } mine_list2[k] = '\0'; printf("%s\n", mine_list); printf("%s\n", mine_list2); // new part ending heree } destroy_game(game); exit(EXIT_SUCCESS); } running the main after losing output 1 2 3 4 5 6 7 8 9 1 1 1 0 0 0 0 0 0 0 2 X 1 0 1 1 1 0 0 0 3 - 1 0 1 X 1 0 0 0 4 - 1 1 1 1 1 1 1 1 5 - X 1 0 0 0 1 X - 6 - - 2 1 1 1 2 - - 7 - - X - - X - - - 8 - X - - X - - - - 9 - - - - - - X - - Ľutujem tom. Riešenie je nesprávne! Vaše skóre je: 13 Chcel by si znova zahrat? (yes/no) yes after playing that for 2 minutes 1 2 3 4 5 6 7 8 9 1 0 0 0 0 0 1 - 1 0 2 0 0 0 0 1 3 X 2 0 3 0 0 0 0 1 X X 3 1 4 1 1 0 0 1 2 2 2 X 5 X 1 0 0 0 0 0 1 - 6 - 2 1 2 2 3 2 1 - 7 - - X - X X X - - 8 - - - - - - - 1 - 9 - - - - - - - - - Ľutujem tom. Riešenie je nesprávne! Vaše skóre je: 19 Chcel by si znova zahrat? (yes/no) FAILED test result: * Suite test_board: ...... 000000000000001100000010001000100000000000001000100000100010000000000000000000000 000000000000001100000010001000100000000000001000100000100010000000000000000000000 F FAIL replay_board: same != 0 (tests/test_board.c:125) game.h typedef enum { FAILED, PLAYING, SOLVED, } GameState; typedef struct { Board *board; /* Struct of the play field */ Player *player; /* Struct of user who is playing the Game */ GameState game_state; /* Enum for status of the Game */ } Game; * create_game()* Game *create_game() { Game *game = (Game *) calloc(1, sizeof(Game)); Player *player = (Player *) calloc(1, sizeof(Player)); game->player = player; game->player->score = 1; game->game_state = PLAYING; return game; } new ouput after uptadting the main with printf 1 2 3 4 5 6 7 8 9 1 - 1 0 0 0 0 0 0 0 2 X 1 0 0 0 0 1 1 1 3 - 1 0 0 0 0 1 X - 4 - 1 1 0 0 1 2 - - 5 - X 2 1 1 1 X - X 6 1 1 2 X 1 1 2 X X 7 0 0 1 1 1 0 1 3 X 8 0 0 0 0 0 0 0 1 1 9 0 0 0 0 0 0 0 0 0 Ľutujem asd. Riešenie je nesprávne! Vaše skóre je: 17 Chcel by si znova zahrat? (yes/no) yes 000000000100000000000000010000000000010000101000100011000000001000000000000000000 000000001100000000000000000000100011000000000000000010010000000000001000000010000 1 2 3 4 5 6 7 8 9 1 - - - - - - - - - 2 - - - - - - - - - 3 - - - - - - - - - 4 - - - - - - - - - 5 - - - - - - - - - 6 - - - - - - - - - 7 - - - - - - - - - 8 - - - - - - - - - 9 - - - - - - - - -
Here's the problem: char* mine_list[100]; You defined mine_list as an array of char * instead of an array of char. Your compiler should have given you a number of warnings wherever you used it. Change it to an array of char: char mine_list[100];
Did you check that replay_game("yes", game); actually changes game? Either way, there's a much easier and correct way to do this. Allocate a new board* pointer,copy the content of board to the new allocated memory using memcpy, and then call replay_game. Assuming this actually changes board variable you can now simply compare the two boards inside one nested loop.
2D array - I want to find which columns have 1s in them in each row
My input looks like this : 15 5 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 1 0 The first row contains the number of rows and columns of my array. And basically I want to find out where these 1s are in the array. So in the first 3 rows i want to get 3, in the 7th 1, and in the 8th, i want to get 2 3 etc.. My code looks like this so far #include <stdio.h> int main() { int row, column; FILE* input; FILE* output; input = fopen("input.txt", "r"); if (input == 0) { printf("ERROR couldn't open input.txt"); return 1; } if (! fscanf(input, "%d %d", &row, &column)) { printf("ERROR not recognised value"); fclose(input); return 2; } output = fopen("output.txt", "w"); int meteor[row][column]; for (int i = 0; i < row; i++) { for (int j = 0; j < column; j++) { fscanf(input, "%d", &meteor[i][j]); } } int sum; int loc[row]; for (int i = 0; i < row; i++) { sum = 0; for (int j = 0; j < column; j++) { sum += meteor[i][j]; if (meteor[i][j] == 1) { loc[i] = (j + 1); } } printf("%d %d\n", loc[i], sum); } fclose(input); fclose(output); return 0; } My output is this : 3 1 3 1 3 1 0 0 -1 0 1 1 4 2 3 1 5 1 0 0 4214921 0 2 1 5 2 3 1 4 1 The first column shows some of the locations, the second shows how many 1s are in the row, but it all fails when there are only 0s in the row or there is more than one 1. And also I would like to store these values.
You need to initialize loc[].. If you look carefully at your code, you only populate it on the condition of if (meteor[i][j] == 1)... but you print it for every index of i. which would print uninitialized memory (i.e. unknown). To answer the second part of your question, if you want to store the "sum". Simply make loc[] a 2d array just like meteor, but with 2 columns (row and sum). i.e. int loc[row][2].. making sure to initialize both columns of course :)
Recursion find all paths in graph matrix DFS
I'm trying to implement a two functions based on Depth First Search using a recursion method. I'm ultimately trying to compare the runtime against warshall's algorithm (which I already have working). When I print my matrix it's off by a couple off paths. The recursion is what may be throwing me off, it's my weakness. Because of the top if statement if(iIndex1 == iIndex2) return TRUE;, when I try to find if there is a path from (A,A), (B,B), (C,C), etc. I will always get 1 even if there is no path from A to A. typedef enum { FALSE, TRUE } bool; /* Recursive function will determine if there is a path from index 1 to 2 * Based of DFS */ bool recPathExists( Graph G, int iIndex1, int iIndex2 ) { int j; G.nodeArray[iIndex1].visited = TRUE; if(iIndex1 == iIndex2){ return TRUE; } for(j = 0; j < G.iNumNodes; j++){ if(!G.nodeArray[j].visited && G.adjMatrix[iIndex1][j]==1){ if(recPathExists(G, j, iIndex2)) return TRUE; } } return FALSE; } /* Write a function to find all pairs of nodes which have paths between them. * Store this information in the provided pathMatrix. */ void allPathsRecFunc( Graph G , int **pathMatrix ) { int i, j; for(i = 0; i < G.iNumNodes; i++){ for(j = 0; j < G.iNumNodes; j++){ if(recPathExists(G, i , j)== TRUE){ pathMatrix[i][j] = 1; } resetVisited(G); //resets all nodes to FALSE } } } what it should be A 0 1 1 1 1 1 1 1 B 0 1 0 0 1 1 1 1 C 0 1 0 0 1 1 1 1 D 0 0 0 0 0 0 0 0 E 0 0 0 0 0 0 0 0 F 0 1 0 0 1 1 1 1 G 0 1 0 0 1 1 1 1 H 0 1 0 0 1 1 1 1 what I get A 1 1 1 1 1 1 1 1 B 0 1 0 0 1 1 1 1 C 0 1 1 0 1 1 1 1 D 0 0 0 1 0 0 0 0 E 0 0 0 0 1 0 0 0 F 0 1 0 0 1 1 1 1 G 0 1 0 0 1 1 1 1 H 0 1 0 0 1 1 1 1
Your issue may be here: for(j = 0; j < G.iNumNodes; j++) { if(!G.nodeArray[j].visited && G.adjMatrix[iIndex1][j] == 1) { return recPathExists(G, j, iIndex2); } } By returning the result of recursing on recPathExists, you're not checking the other possible nodes that could be reachable in the loop (in essence, you're returning failure too early, and missing possible paths). I believe you want just a little modification: for(j = 0; j < G.iNumNodes; j++) { if(!G.nodeArray[j].visited && G.adjMatrix[iIndex1][j] == 1) { if (recPathExists(G, j, iIndex2)) return TRUE; } } That is, "if a path does exist, return as we've found it. If not, keep looking".
My depth first search uses recursion but it outputs a parent array, though the functionality should be the same. It got a perfect grade so I know it works. Hope it helps. https://github.com/grantSwalwell/Data-Structures/blob/master/Depth%20First%20Search.h Algorithm~ bool array, visited for flagging nodes search number array to measure the depth of access depth to increment and come up with search num Call DFS on 0,0 For each non visited neighbor DFS depth + 1, search = depth, visited = true return parent array, showing the search pattern // Depth First Search recursive helper method void DFS(Graph& G, int v0, Array<bool>* visited, Array<int>* search, int depth) { // set visited (*visited)[v0] = true; // set search num (*search)[v0] = depth; // iterate through neighbors for (int i = 0; i < G.nodes(); i++) { // if i is a neighbor if (G.edge(i, v0)) { // if it has not been visited if (!(*visited)[i]) { // call DFS DFS(G, i, visited, search, depth + 1); } } // end if } // end for } // Depth First Search Array<int>* DFS(Graph& G, int v0) { // visited array Array<bool>* visited = new Array<bool>(G.nodes()); // search number array, order of visitation Array<int>* search = new Array<int>(G.nodes()); // initialize both arrays for (int i = 0; i < G.nodes(); i++) { (*visited)[i] = false; (*search)[i] = 1; } // create depth field int depth = 1; // call DFS DFS(G, v0, visited, search, depth); return search; };
Pass 2D array by reference
I want to be able to pass a 2D array to a function, and have it directly change the array in main, so pass by reference. When I try to compile, I get error: expected expression before { in the switch cases. (boardSize=10, but that is not known at compilation time) void fillBoard(int **, int); int main() { int **board = malloc(sizeof(int *) * boardSize); fillBoard(board, boardSize); } void fillBoard(int **board) { int i, *row = malloc(sizeof(int) * boardSize); for (i=0; i<boardSize; i++) { board[i] = malloc(sizeof(int) * boardSize); switch(i) { case 1: row = {1,0,1,0,1,1,0,0,1,0}; break; default: row = {0,0,0,0,0,0,0,0,0,0}; break; } board[i] = row; } }
There a many different ways to do this. The key is to keep track of what you are addressing where. You can use a single or double pointer to pass and fill board, it all depends on how you want to keep track of the elements. (while the 2-dimensional array, provides a convenience in referencing elements, all values are sequential in memory, and can be accessed with a 1-dimensional reference and offset). There is one important suggestion when allocating memory for numeric arrays. You must always initialize all elements of the array to protect against attempting to access or dereference an uninitialized value (Undefined behavior). The simple way to do this is to allocate with calloc instead of malloc. calloc allocates and initializes all values to zero (NULL). Also be aware of the need to track the memory you allocate over the life of your program and free the memory when you no longer need it. This will prevent memory leaks from developing. In a short bit of code like the following, the memory is freed when the program exits. If this were part of some larger code, you would need to free board and board2 when there data was no longer needed. An example using your original array would be: #include <stdio.h> #include <stdlib.h> #define boardSize 10 void fillBoard_p (int *a); void fillBoard_p2p (int **a); int main() { int i = 0; int j = 0; /* declaring board as an integer pointer */ int *board = calloc (boardSize * boardSize, sizeof (*board)); /* declaring board as a pointer to pointer */ int **board2 = calloc (boardSize, sizeof (*board2)); for (i = 0; i < boardSize; i++) { board2[i] = calloc (boardSize, sizeof (**board2)); } fillBoard_p (board); fillBoard_p2p (board2); printf ("\nboard as an integer pointer:\n"); for (i = 0; i < boardSize * boardSize; i++) { if (i % boardSize == 0) printf ("\n %d", board[i]); else printf (" %d", board[i]); } printf ("\n"); printf ("\nboard2 as an pointer to integer pointer:\n\n"); for (i = 0; i < boardSize; i++) { for (j = 0; j < boardSize; j++) { printf (" %d", board2[i][j]); } printf ("\n"); } printf ("\n"); return 0; } void fillBoard_p(int *a) { // 0=WHITE, 1=BLACK int i = 0; int j = 0; int b [][boardSize] = { {1,0,1,0,1,1,0,0,1,0}, {1,0,1,1,0,0,1,1,1,0}, {0,0,1,0,1,0,1,0,1,1}, {1,1,0,1,1,0,1,0,0,0}, {0,0,1,0,0,0,1,1,0,1}, {1,1,0,1,1,0,0,1,1,0}, {0,0,1,0,0,1,1,0,1,1}, {0,0,1,0,0,1,0,0,0,0}, {1,1,1,1,0,0,1,1,1,1}, {0,1,0,0,1,1,0,0,0,1} }; for (i = 0; i < boardSize; i++) for (j = 0; j < boardSize; j++) a[i*boardSize+j] = b[i][j]; } void fillBoard_p2p (int **a) { // 0=WHITE, 1=BLACK int i = 0; int j = 0; int b [][boardSize] = { {1,0,1,0,1,1,0,0,1,0}, {1,0,1,1,0,0,1,1,1,0}, {0,0,1,0,1,0,1,0,1,1}, {1,1,0,1,1,0,1,0,0,0}, {0,0,1,0,0,0,1,1,0,1}, {1,1,0,1,1,0,0,1,1,0}, {0,0,1,0,0,1,1,0,1,1}, {0,0,1,0,0,1,0,0,0,0}, {1,1,1,1,0,0,1,1,1,1}, {0,1,0,0,1,1,0,0,0,1} }; for (i = 0; i < boardSize; i++) for (j = 0; j < boardSize; j++) a[i][j] = b[i][j]; } output: $ ./bin/fillboard board as an integer pointer: 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 1 1 0 0 0 1 0 1 0 1 0 1 1 1 1 0 1 1 0 1 0 0 0 0 0 1 0 0 0 1 1 0 1 1 1 0 1 1 0 0 1 1 0 0 0 1 0 0 1 1 0 1 1 0 0 1 0 0 1 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 1 0 0 1 1 0 0 0 1 board2 as an pointer to integer pointer: 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 1 1 0 0 0 1 0 1 0 1 0 1 1 1 1 0 1 1 0 1 0 0 0 0 0 1 0 0 0 1 1 0 1 1 1 0 1 1 0 0 1 1 0 0 0 1 0 0 1 1 0 1 1 0 0 1 0 0 1 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 1 0 0 1 1 0 0 0 1 Additionally, since a 2-D array is stored sequentially in memory, you can take advantage of that fact and make use of memcpy (in string.h) to fill the array passed to your function. This can reduce your function to: void fillBoard_mc (int *a) { // 0=WHITE, 1=BLACK int b [][boardSize] = { {1,0,1,0,1,1,0,0,1,0}, {1,0,1,1,0,0,1,1,1,0}, {0,0,1,0,1,0,1,0,1,1}, {1,1,0,1,1,0,1,0,0,0}, {0,0,1,0,0,0,1,1,0,1}, {1,1,0,1,1,0,0,1,1,0}, {0,0,1,0,0,1,1,0,1,1}, {0,0,1,0,0,1,0,0,0,0}, {1,1,1,1,0,0,1,1,1,1}, {0,1,0,0,1,1,0,0,0,1} }; memcpy (a, b, boardSize * boardSize * sizeof (int)); } Were it not for the particularity of the compiler and pointer decay, you could simply use a statically declared array, such as: int board[boardSize][boardSize] = {{0}}; passing the address of the array to your function (becoming a 3-star programmer): fillBoard (&board); with a function similar to: void fillBoard (int *a[][boardSize]) { // 0=WHITE, 1=BLACK int b [][boardSize] = { {1,0,1,0,1,1,0,0,1,0}, {1,0,1,1,0,0,1,1,1,0}, {0,0,1,0,1,0,1,0,1,1}, {1,1,0,1,1,0,1,0,0,0}, {0,0,1,0,0,0,1,1,0,1}, {1,1,0,1,1,0,0,1,1,0}, {0,0,1,0,0,1,1,0,1,1}, {0,0,1,0,0,1,0,0,0,0},A {1,1,1,1,0,0,1,1,1,1}, {0,1,0,0,1,1,0,0,0,1} }; memcpy (a, b, boardSize * boardSize * sizeof (int)); } Due to pointer decay (board[10][10] => board[*][10]), you will receive an incompatible pointer type warning, despite the function successfully copying the memory as intended. Code that does not compile without warning, should not be relied on in practice.