Checking neighboring cells in a dynamically allocated 2D array - c

I am working on a project in which I need to check neighboring cells of a specific cell in a dynamically allocated 2D char array. Basically, If certain neighboring cells are 'X' for example, then the current cell you are on becomes '-'. To allocate the 2D array, I used a single malloc call:
char *array = (char *)malloc(numRows * numCols * sizeof(char));
To access an element while using a double for loop, I use this:
for (int i = 0; i <= getNumRows(); i++)
{
for (int j = 0; j < getNumCols(); j++)
{
printf("%c ", **(array + i * getNumCols() + j));
}
printf("\n");
}
How would I access and view the neighboring cells of the current element?

The code posted to display the matrix has problems:
the outer loop should stop when i == getNumRows() and
the printf argument should use a single * dereferencing operator
Here is a modified version:
for (int i = 0; i < getNumRows(); i++) {
for (int j = 0; j < getNumCols(); j++) {
printf("%c ", *(array + i * getNumCols() + j));
}
printf("\n");
}
Which can also be rewritten to avoid recomputing the matrix sizes repeatedly:
for (int i = 0, row = getNumRows(), cols = getNumCols(); i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%c ", array[i * cols + j]);
}
printf("\n");
}
Accessing the neighbouring cells of cell r,c depends on how you deal with boundaries:
if boundaries should not be crossed, you must test if r and/or c are on a boundary to produce between 3 and 8 neighbours.
if boundaries wrap as a torus, you can just compute r+/-1 % rows and c+/-1 % cols to always produce 8 neighbours.
To simplify the first case, you can allocate the matrix with 2 extra columns and rows, with char *array = malloc(sizeof(char) * (numRows + 1) * (numCols + 2)); and use the inner space (active area) this way:
for (int i = 1; i <= getNumRows(); i++) {
for (int j = 1; j <= getNumCols(); j++) {
printf("%c ", *(array + i * getNumCols() + j));
}
printf("\n");
}
If you initalize the boundary rows and columns in the matrix as ' ', you can always access the 8 cells at r+/-1, c+/-1 and check for 'X' without special casing the boundary rows of the active part.
Accessing these neighbouring cells can be done according to the implementation choices:
int rows = getNumRows(), cols = getNumCols();
char *cellp = array + r * cols + c;
// using extra rows and columns
char top_1 = cellp[-cols - 1];
char top_2 = cellp[-cols];
char top_3 = cellp[-cols + 1];
char mid_1 = cellp[-1];
char mid_2 = cellp[+1];
char bot_1 = cellp[+cols - 1];
char bot_2 = cellp[+cols];
char bot_3 = cellp[+cols + 1];
// using torus-like wrapping
char top_1 = array[(r + rows - 1) % rows * cols + (c + cols - 1) % cols];
char top_2 = array[(r + rows - 1) % rows * cols + c];
char top_3 = array[(r + rows - 1) % rows * cols + (c + 1) % cols];
char mid_1 = array[r * cols + (c + cols - 1) % cols];
char mid_2 = array[r * cols + (c + 1)];
char bot_1 = array[(r + 1) % rows * cols + (c + cols - 1) % cols];
char bot_2 = array[(r + 1) % rows * cols + c];
char bot_3 = array[(r + 1) % rows * cols + (c + 1) % cols];
// using tests
char top_1 = (r == 0 || c == 0 ) ? 0 : cellp[-cols - 1];
char top_2 = (r == 0 ) ? 0 : cellp[-cols];
char top_3 = (r == 0 || c == cols - 1) ? 0 : cellp[-cols + 1];
char mid_1 = ( c == 0 ) ? 0 : cellp[-1];
char mid_2 = ( c == cols - 1) ? 0 : cellp[+1];
char bot_1 = (r == rows - 1 || c == 0 ) ? 0 : cellp[+cols - 1];
char bot_2 = (r == rows - 1 ) ? 0 : cellp[+cols];
char bot_3 = (r == rows - 1 || c == cols - 1) ? 0 : cellp[+cols + 1];

I would use a pointer to the array. It makes array indexing much easier. Example prints neighbouring cells.
void print_n(void *arr, size_t nrows, size_t ncols, size_t col, size_t row)
{
int (*array)[nrows][ncols] = arr;
if(col) printf("Left: %d\n", (*array)[row][col - 1]);
if(col < ncols - 1) printf("Right: %d\n", (*array)[row][col + 1]);
if(row) printf("Top: %d\n", (*array)[row - 1][col]);
if(row < nrows - 1) printf("Right: %d\n", (*array)[row + 1][col]);
}
int main(void)
{
size_t ncols = 10, nrows = 20;
int (*array)[nrows][ncols] = malloc(sizeof(*array));
for(size_t row = 0; row < nrows; row++)
for(size_t col = 0; col < ncols; col++)
(*array)[row][col] = row * 100 + col;
print_n(array, nrows, ncols, 6, 7);
free(array);
}
https://godbolt.org/z/7Yoff5

Related

scanf not reading the whole string

I was writing a program in C for lexicographically sorting the strings entered by user , but whenever i am entering a string with string length greater than 3 my code shows some garbage values and i am not able to understand why ?
My line of Code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void lexiiographic_sort(char** , int );
int main(void)
{
int n;
scanf_s("%d", &n);
char** arr;
arr = (char**)malloc(n * sizeof(char*));
for (int i = 0; i < n; i++)
{
if ((*(arr + i) = (char*)malloc(1024 * sizeof(char))) == NULL) { exit(1); }
scanf_s("%s", *(arr + i),sizeof(*(arr + i)));
if ((*(arr + i) = (char*)realloc(*(arr + i), strlen(*(arr + i)) + 1)) == NULL) { exit(1); }
printf("%s\n", *(arr + i));
}
lexiiographic_sort(arr, n);
for (int i = 0; i < n; i++)
{
printf("%s\n", *(arr + i));
}
}
void lexiiographic_sort(char** string, int size)
{
char* temp;
for (int i = 1; i < size; i++)
{
for (int j = 1; j < size; j++)
{
if ((int)(*(*(string + j - 1))) > (int)(*(*(string + j))))
{
if ((temp = (char*)malloc(strlen(*(string + i - 1)) * sizeof(char) + 1)) == NULL) { exit(1); }
temp = *(string + j - 1);
if((temp = ((char*)realloc(temp, strlen(*(string + j)) * sizeof(char) + 1))) == NULL){exit(1); }
*(string + j - 1) = *(string + j);
*(string + j) = temp;
}
}
}
}
}
You cannot get size of dynamically allocated buffer via sizeof. sizeof(*(arr + i)) is the size of a pointer char*. It seems it is 4 in your environment and it is the reason of the 3-character limit (one is left for terminating null-character).
You used the hard-coded number 1024 as the buffer size, so use that instead.
scanf_s("%s", *(arr + i),1024);
Defining a macro for buffer size and using them will improve your code more.

Maximum sized square sub-matrix

I have a matrix of size N*M filled with 0's and 1's.
For each query K, I have to answer the maximum sized square sub-matrix in which minimum(number of 1's, number of 0's)=k where 1<=K<=10^9. For example consider the matrix of size 8*8:
10000000
01000000
00000000
00000000
00000000
00000000
00000000
00000000
k= 1 answer= 7
k=2 answer= 8
k=0 answer= 6
k=1001 answer= 8
I understood that for k=1, the sub-matrix (1,1) to (7,7) works for k=2, the largest square sub-matrix is the original matrix itself.
For k=1, we have to get all the 7*7 square sub-matrix. Find their min(no. of 1's,no. of 0's) and then get the minimum of all those as the answer.
I am not able to generate all the pairs of square sub-matrix. Can anyone help me in achieving that? Also, if any shorter way is available, that will be good as well because this takes very much time.
Is this an interview question? This problem is very similar to that of the maximum submatrix sum (https://www.geeksforgeeks.org/maximum-sum-rectangle-in-a-2d-matrix-dp-27/), whose DP solution you should be able to adapt for this.
EDIT:
The following is O(n^3) time O(n^2) memory
The import piece to realize is that the area D = Entire Area - B - C + A
| A B |
| C D |
#include <stdlib.h>
#include <stdio.h>
int **create_dp(int **matrix, int **dp, int row, int col) {
dp[0][0] = matrix[0][0];
for (int i = 1; i < row; ++i)
dp[i][0] = matrix[i][0] + dp[i - 1][0];
for (int j = 1; j < col; ++j)
dp[0][j] = matrix[0][j] + dp[0][j - 1];
for (int i = 1; i < row; ++i)
for (int j = 1; j < col; ++j)
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] + matrix[i][j] - dp[i - 1][j - 1];
}
int min(int x, int y) {
if (x > y) return y;
return x;
}
int max_square_submatrix(int **matrix, int row, int col, int query) {
// the value dp[i][j] is the sum of all values in matrix up to i, j
// i.e. dp[1][1] = matrix[0][0] + matrix[1][0] + matrix[0][1] + matrix[1][1]
int **dp = malloc(sizeof(int*) * row);
for (int i = 0; i < row; ++i) dp[i] = malloc(sizeof(int) * col);
create_dp(matrix, dp, row, col);
int global_max_size = 0;
// go through all squares in matrix
for (int i = 0; i < row; ++i) {
for (int j = 0; j < col; ++j) {
// begin creating square matrices
// this is the largest size a square matrix could have
int max_size = min(row - i, col - j) - 1;
for (; max_size >= 0; --max_size) {
// you need to see above diagram in order to visualize this step
int num_ones = dp[i + max_size][j + max_size];
if (i > 0 && j > 0)
num_ones += -dp[i + max_size][j - 1] - dp[i - 1][j + max_size] + dp[i - 1][j - 1];
else if (j > 0)
num_ones += -dp[i + max_size][j - 1];
else if (i > 0)
num_ones += -dp[i - 1][j + max_size];
if (num_ones <= query) break;
}
if (global_max_size < max_size + 1) global_max_size = max_size + 1;
}
}
// free dp memory here
return global_max_size;
}
int main() {
#define N 8
#define M 8
int **matrix = malloc(sizeof(int*) * N);
for (int i = 0; i < N; ++i) matrix[i] = malloc(sizeof(int) * M);
for (int i = 0; i < N; ++i)
for (int j = 0; j < M; ++j)
matrix[i][j] = 0;
matrix[0][0] = matrix[1][1] = 1;
printf("%d\n", max_square_submatrix(matrix, 8, 8, 1));
printf("%d\n", max_square_submatrix(matrix, 8, 8, 2));
printf("%d\n", max_square_submatrix(matrix, 8, 8, 0));
printf("%d\n", max_square_submatrix(matrix, 8, 8, 1001));
}

matrix rotation..for loop changes the value of pointer

In the final value of array only first element becomes zero and that too when it again goes to the for loop(checked using gdb)..i have mentioned the problem using comments at the bottom of code.Help me out.. I have no clue of what is going wrong.
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, b, c;
printf("enter the size of matrix");
scanf("%d%d",&a,&b);
printf("enter the number of rotations");
scanf("%d",&c);
int *arr = malloc (sizeof(int) * a * b);
int x = (a >= b)? a : b;
printf("enter the values of matrix");
// scanning the values
for(int i = 0; i < a; i++)
{
for(int j = 0; j < b; j++)
{
scanf("%d",(arr + i * b + j));
}
printf("\n");
}
// main code starts
for(int y = 0; y < c; y++)
{
// declared a new array
int *arr1 = malloc (sizeof(int) * a * b);
for(int k = 0; k < x / 2; k++)
{
for(int i = k; i < a - k; i++)
{
for(int j = k; j < b - k; j++)
{
if (i == k && j > k)
{
*(arr1 + i * b + j - 1) = *(arr + i * b + j);
}
else if (i == a - k - 1 && j < b - k - 1)
{
*(arr1 + i * b + j + 1) = *(arr + i * b + j);
}
else if (j == k && i < a - k - 1)
{
*(arr1 + i * b + j + b) = *(arr + i * b + j);
}
else if (j == b - k - 1 && i > k)
{
*(arr1 + i * b + j - b) = *(arr + i * b + j);
}
}
}
if (x % 2 != 0 && a == b)
*(arr1 + x / 2 * b + (b / 2)) = *(arr + x / 2 * b + (b / 2));
}
// changing the old array to new array
arr = arr1;
// first value is getting printed correctly here
printf("%d\n",*(arr));
printf("%p\n",&(*arr));
free(arr1);
}
// printing the output
for(int i = 0; i < a; i++)
{
for(int j = 0; j < b; j++)
{
printf("%d ",*(arr + i * b + j));
}
printf("\n");
}
// first value is getting printed incorrectly here, outside the loop
printf("\n%d\n",*(arr));
printf("%p",&(*arr));
}
C doesn't support array assignment. You have:
int *arr = malloc (sizeof(int) * a * b);
…
int *arr1 = malloc (sizeof(int) * a * b);
…
arr = arr1;
…
free(arr1);
The assignment means you've lost your original array (memory leak) and you then invalidate your new array with the free().
Array copying requires more code — usually a function call such as memmove() or memcpy(), possibly wrapped in a function.
For example, add #include <string.h> and use this in place of the arr = arr1; assignment:
memmove(arr, arr1, sizeof(int) * a * b);
free(arr1); // No longer needed
Alternatively:
free(arr);
arr = arr1;
This code runs cleanly under valgrind on Mac OS X 10.11.5 with GCC 6.1.0 with the 'Either' or the 'Or' options for handling the array assignments.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void dump_matrix(const char *tag, int *arr, int a, int b)
{
printf("Matrix: %s\n", tag);
for (int i = 0; i < a; i++)
{
for (int j = 0; j < b; j++)
printf(" %3d", arr[i * b + j]);
putchar('\n');
}
}
int main(void)
{
int a, b, c;
printf("enter the size of matrix: ");
scanf("%d%d", &a, &b);
printf("enter the number of rotations: ");
scanf("%d", &c);
int *arr = malloc(sizeof(int) * a * b);
int x = (a >= b) ? a : b;
printf("enter the values of matrix: ");
// scanning the values
for (int i = 0; i < a; i++)
{
for (int j = 0; j < b; j++)
{
if (scanf("%d", (arr + i * b + j)) != 1)
{
fprintf(stderr, "failed to read value arr[%d][%d]\n", i, j);
return EXIT_FAILURE;
}
}
printf("\n");
}
dump_matrix("Initial input", arr, a, b);
// main code starts
for (int y = 0; y < c; y++)
{
// declared a new array
int *arr1 = malloc(sizeof(int) * a * b);
for (int k = 0; k < x / 2; k++)
{
for (int i = k; i < a - k; i++)
{
for (int j = k; j < b - k; j++)
{
if (i == k && j > k)
{
*(arr1 + i * b + j - 1) = *(arr + i * b + j);
}
else if (i == a - k - 1 && j < b - k - 1)
{
*(arr1 + i * b + j + 1) = *(arr + i * b + j);
}
else if (j == k && i < a - k - 1)
{
*(arr1 + i * b + j + b) = *(arr + i * b + j);
}
else if (j == b - k - 1 && i > k)
{
*(arr1 + i * b + j - b) = *(arr + i * b + j);
}
}
}
if (x % 2 != 0 && a == b)
*(arr1 + x / 2 * b + (b / 2)) = *(arr + x / 2 * b + (b / 2));
}
// Changing the old array to new array
// Either:
// memmove(arr, arr1, sizeof(int) * a * b);
// free(arr1);
// Or:
free(arr);
arr = arr1;
dump_matrix("After rotation", arr, a, b);
}
dump_matrix("Finished", arr, a, b);
free(arr);
return 0;
}
Note the use of the dump_matrix() function. Writing such a function once means it can be used multiple places in the code. The tag argument simplifies the use. The 'commercial grade' variant takes a FILE *fp argument too and writes to the specified file stream.
Note the error checking on the main input loop scanf(). I should also have checked the two other scanf() statements. Errors are reported on standard error, of course.
Example run:
$ ./mat31
enter the size of matrix: 3 4
enter the number of rotations: 2
enter the values of matrix: 1 2 3 4 10 11 12 13 99 98 97 96
Matrix: Initial input
1 2 3 4
10 11 12 13
99 98 97 96
Matrix: After rotation
2 3 4 13
1 12 11 96
10 99 98 97
Matrix: After rotation
3 4 13 96
2 11 12 97
1 10 99 98
Matrix: Finished
3 4 13 96
2 11 12 97
1 10 99 98
$
Whether the output is what you intended is a wholly separate discussion. This is simply not abusing the memory.

Allocate dynamically and initialize multidimensional arrays without indexes

If I allocated a multidimensional array dynamically and without using indexes ( [ i ] [ j ] ), how can I initialize it?
#include <stdio.h>
#include <stdlib.h>
#define ROWS 3
#define COLUMNS 4
int main(void)
{
int i,j;
char **v;
v = malloc(ROWS * sizeof(char*));
for (i = 0 ; i < ROWS ; i++)
*(v + i * sizeof(char*)) = malloc(COLUMNS * sizeof(char));
for (i = 0 ; i < ROWS ; i++)
for (j = 0 ; j < COLUMNS ; j++)
??? = 'a' + i * COLUMNS + j;
return 0;
}
Instead of ??? what do I have to put? Addresses aren't contiguous so I think this expression:
**(v+(i*COLUMNS+j)*sizeof(char))
isn't correct...
Thanks.
Do not multiply by the size of the type, pointer arithmetics is done in multiples of the base type.
You need to dereference like you do above, and then dereference again, like this
int i, j;
char **v;
v = malloc(ROWS * sizeof(char *));
if (v == NULL)
return -1;
for (i = 0 ; i < ROWS ; i++)
{
*(v + i) = malloc(COLUMNS * sizeof(char));
if (*(v + i) == NULL)
return -1;
for (j = 0 ; j < COLUMNS ; j++)
{
*(*(v + i) + j) = 'a' + i * COLUMNS + j;
}
}
return 0;
and don't forget to free().
So basically x[i] is equivalent to *(x + i) and you can apply it to the resulting pointer too.
NOTE: These are not strings, they need to be nul terminated to become strings.
If you insist on using sizeof this is how
int i, j;
char **v;
v = malloc(ROWS * sizeof(char *));
if (v == NULL)
return -1;
for (i = 0 ; i < ROWS ; i++)
{
*((unsigned char *) v + i * sizeof(char *)) = malloc(COLUMNS * sizeof(char));
if (*(v + i) == NULL)
return -1;
for (j = 0 ; j < COLUMNS ; j++)
{
*(*((unsigned char *) v + i * sizeof(char *)) + j) = 'a' + i * COLUMNS + j;
}
}
I will not use sizeof(char) as it's very redundant, the standard clearly states that sizeof(char) MUST be 1.
You are not creating a multi-dimensional array but an array of pointers. In your code, a possibility is to put *((*(v + i)) + j) in place of your ???.
Otherwise if you want the addresses to be contiguous like a multi-dimensional array you need to allocate all the memory in one malloc, assign it to v, and then use *(v + i*COLUMNS + j) to access it.

Heapsort working with strings but not ints

I'm trying to get a generic heapsort working. It works perfectly with strings but for some reason does not with integer types. Completely lost as to why this is. I am sure that the comparison function is correct. The last if statement in the heapsort function is to correct a bug that would sometimes cause the 0th and 1st indexes to be reversed.
#include "heapsort.h"
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
int heapsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *))
{
int i;
int j;
printf("\n");
/*build heap*/
for (j = 1; j < nel; j++) {
i = j;
while (compar(base + i * width, base + (i-1)/2 * width) > 0) {
swap(base + i * width, base + (i-1)/2 * width);
i = (i-1)/2;-
}
}
/*sort*/
for (i = 1; i < nel; i++) {
swap(base , base + (nel - i) * width);
j = 0;
while (((2 * j + 1) < nel - i) && ((2 * j + 2) < nel - i)){
if (compar(base + (j * 2 + 2) * width, base + (j * 2 + 1) * width) > 0
&& compar(base + j * width, base + (j * 2 + 2) * width) < 0)
{
swap(base + j * width, base + (2 * j + 2) * width);
j = 2 * j + 2;
}
else if (compar(base + (j * 2 + 2) * width, base + (j * 2 + 1) * width) <= 0
&& compar(base + j * width, base + (j * 2 + 1) * width) < 0)
{
swap(base + j * width, base + (2 * j + 1) * width);
j = 2 * j + 1;
}
else
break;
}
}
if (compar(base + 0 * width, base + 1 * width) > 0) {
swap(base + 0 * width, base + 1 * width);
}
return 0;
}
void swap(void *a, void *b)
{
void *temp;
printf("swapping %d and %d\n", *(int*)a, *(int*)b);
temp = *(void**)a;
*(void**)a = *(void**)b;
*(void**)b = temp;
}
int intcmp(const void * a, const void * b)
{
return *(int*)a - *(int*)b;
}
The swap function looks wrong. It is assuming the values referenced by a and b are pointers (which will work if the types are [const] char * strings) and is swapping sizeof(void *) bytes. It is likely that sizeof(int) != sizeof(void *) on your system.
You need to swap width bytes.

Resources