Notationally cleanest way of passing multidimensional array - c

I was working on these problems that I found online and one of the asks to rotate a two-dimensional NxN array in-place. My code for it is the following:
#include <stdio.h>
void rotate(int n, int *s)
{
int nx, ny, tmp;
int i, j;
if(n < 1) return;
/* Compute upper small square as basis for trajectories */
if(n % 2 == 0) {
nx = ny = n/2;
}
else {
ny = (n-1)/2;
nx = ny+1;
}
/* Move elements along their trajectories */
for(i = 0; i < nx; i++) {
for(j = 0; j < ny; j++) {
tmp = *(s + n*j + n-1-i);
*(s + n*j + n-1-i) = *(s + n*(n-1-i) + n-1-j);
*(s + n*(n-1-i) + n-1-j) = *(s + n*(n-1-j) + i);
*(s + n*(n-1-j) + i) = *(s + n*i + j);
*(s + n*i + j) = tmp;
}
}
}
int main(void)
{
int test[4][4] = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12},
{ 13, 14, 15, 16}};
int n = 4;
int i, j;
for(i = 0; i < n; i++) {
for(j = 0; j < n; j++) {
printf("%d ", test[i][j]);
}
printf("\n");
}
printf("\nRotating matrix in place...\n\n");
rotate(n, test);
for(i = 0; i < n; i++) {
for(j = 0; j < n; j++) {
printf("%d ", test[i][j]);
}
printf("\n");
}
return 0;
}
I know that the compiler will complain when I pass the two-dimensional array to rotate() in the main() function, because of the double pointer conversion from arrays to pointers. My issues are the following:
What is the correct way to declare the type of the rotate() function.
How can I do it in a way that I can use the s[i][j] notation within the function rotate() without having to resort to pointer arithmetic? I realize that the type must be able to somehow dynamically take into account the value of n, so is it possible?
I know I could circumvent the ugly notation by defining a pair of inline getter and setter functions, but that would require typing too much.

Pass additional parameters along with the pointer to an array:
void Func( size_t y , size_t x , int(*a)[x] ) {...
This is identical to
void Func( size_t y , size_t x , int a[][x] ) {...
or
void Func( size_t y , size_t x , int a[y][x] ) {...
Apart from the outermost one, all dimensions must be provided for a. In this case y is optional. But you still need it to determine the outer size of the array in the function.
The notation is then identical as with the array:
a[y-1][x-1] = 1234 ;

Related

dealing with dups in end of the array

This is the task I have got:
I need to write a function (not recursive) which has two parameters.
An array of integers.
An integer representing the size of the array.
The function will move the duplicates to an end of the array.
And will give the size of the different digits.
Example:
5 , 2 , 4 , 5 , 6 , 7 , 2, n = 7
we will get back 5 , 2 , 4 , 6 , 7 , 5 , 2 and 5
We must keep the original sort as it is (which means like in example 5 must)
It does not matter how we sort the duplicates ones but just keep the sort for the original array as it is)
The function has to print the number of different digits (like in example 5)
The the input range of numbers in array [-n,n]
I can only use 1 additional array for help.
It has to be O(n)
I tried it so many times and feel like am missing something. Would appreciate any advice/suggestions.
int moveDup(int* arr, int n)
{
int* C = (int*)calloc(n * 2 + 1, sizeof(int));
assert(C);
/*int* count = C + n;*/
int *D = arr[0];
int value = 0, count = 0;
for (int i = 0; i < n; i++)
{
value = arr[i];
if (C[value + n] == 0)
{
*D = arr[i];
D++;
count++;
}
C[value + n] = C[value + n] + 1;
}
while (1 < C[value + n])
{
*D = i;
D++;
C[value + n]--;
}
free(C);
return count;
}
This algorithm will produce the required results in O(n) arithmetic complexity:
Input is an array A with n elements indexed from A0 to An−1 inclusive. For each Ai, −n ≤ Ai ≤ n.
Create an array C that can be indexed from C−n to C+n, inclusive. Initialize C to all zeros.
Define a pointer D. Initialize D to point to A0.
For 0 ≤ i < n:
If CAi=0, copy Ai to where D points and advance D one element.
Increment CAi.
Set r to the number of elements D has been advanced from A0.
For −n ≤ i ≤ +n:
While 1 < CAi:
Copy i to where D points and advance D one element.
Decrement CAi.
Release C.
Return r. A contains the required values.
A sample implementation is:
#include <stdio.h>
#include <stdlib.h>
#define NumberOf(a) (sizeof (a) / sizeof *(a))
int moveDuplicates(int Array[], int n)
{
int *memory = calloc(2*n+1, sizeof *Array);
if (!memory)
{
fprintf(stderr, "Error, unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
int *count = memory + n;
int *destination = Array;
for (int i = 0; i < n; ++i)
// Count each element. If it is unique, move it to the front.
if (!count[Array[i]]++)
*destination++ = Array[i];
// Record how many unique elements were found.
int result = destination - Array;
// Append duplicates to back.
for (int i = -n; i <= n; ++i)
while (0 < --count[i])
*destination++ = i;
free(memory);
return result;
}
int main(void)
{
int Array[] = { 5, 2, 4, 5, 6, 7, 2 };
printf("There are %d different numbers.\n",
moveDuplicates(Array, NumberOf(Array)));
for (int i = 0; i < NumberOf(Array); ++i)
printf(" %d", Array[i]);
printf("\n");
}
here is the right answer, figured it out by myself.
int moveDup(int* arr, int n)
{
int* seen_before = (int*)calloc(n * 2 + 1, sizeof(int));
assert(seen_before);
int val = 0, count = 0, flag = 1;
int j = 0;
for (int i = 0; i < n; i++)
{
val = arr[i];
if (seen_before[arr[i] + n] == 0)
{
seen_before[arr[i] + n]++;
count++;
continue;
}
else if (flag)
{
j = i + 1;
flag = 0;
}
while (j < n)
{
if (seen_before[arr[j] + n] == 0)
{
count++;
seen_before[arr[j] + n]++;
swap(&arr[i], &arr[j]);
j++;
if (j == n)
{
free(seen_before);
return count;
}
break;
}
/*break;*/
j++;
if (j == n)
{
free(seen_before);
return count;
}
}
}
}
second right answer
int* mem = (int*)calloc(2 * n + 1, sizeof * arr);
assert(mem);
int* count = mem + n;
int* dest = arr;
for (i = 0; i < n; ++i)
{
if (count[arr[i]]++ == 0)
{
*dest = arr[i];
*dest++;
}
}
res = dest - arr;
for (i = -n; i <= n; ++i)
{
while (0 < --count[i])
{
*dest++ = i;
}
}
free(mem);
return res;

Can't figure out what's wrong with my code for a HackerRank problem in C

I'm sorry to ask help for a HackerRank problem here, I know it's not really the right place but nobody is answering me on HackerRank. Also, I'm new in C, so don't be to rude please.
Problem's description:
You are given n triangles, specifically, their sides a, b and c. Print them in the same style but sorted by their areas from the smallest one to the largest one. It is guaranteed that all the areas are different.
Link to the problem : https://www.hackerrank.com/challenges/small-triangles-large-triangles/problem
We can only edit the sort_by_area function.
First of all, I didn't calculate the triangles' area, I've just calculated the perimeter of each triangle, because the formula is simpler to read and to execute. Normally, that doesn't change anything for the result since a bigger perimeter means a bigger area. Tell me if I'm wrong.
The problem is that I have unexpected results: there's numbers on a line from my output that I really don't know from where they come. See:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct {
int a;
int b;
int c;
} triangle;
void sort_by_area(triangle *tr, int n) {
// Array for storing the perimeter.
int *size = malloc(100 * sizeof(*size));
// Adding perimeters in size array.
for (int i = 0; i < n; i++) {
size[i] = tr[i].a + tr[i].b + tr[i].c;
}
// Sort.
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (size[j] > size[j + 1]) {
// Sort in size array.
int temp = size[j];
size[j] = size[j + 1];
size[j + 1] = temp;
// Sort in tr array.
temp = tr[j].a;
tr[j].a = tr[j + 1].a;
tr[j + 1].a = temp;
temp = tr[j].b;
tr[j].b = tr[j + 1].b;
tr[j + 1].b = temp;
temp = tr[j].c;
tr[j].c = tr[j + 1].c;
tr[j + 1].c = temp;
}
}
}
}
int main() {
int n;
scanf("%d", &n);
triangle *tr = malloc(n * sizeof(triangle));
for (int i = 0; i < n; i++) {
scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
}
sort_by_area(tr, n);
for (int i = 0; i < n; i++) {
printf("%d %d %d\n", tr[i].a, tr[i].b, tr[i].c);
}
return 0;
}
Input:
3
7 24 25
5 12 13
3 4 5
Output:
0 417 0 // Unexpected results on this line.
3 4 5
5 12 13
Expected output:
3 4 5
5 12 13
7 24 25
It seems that an error occurs from the 7 24 25 triangle, but for me, my code seems to be good.... Can you help to find out what's wrong ? I really want to understand before going to another problem.
The assumption that a greater parameter implies a greater area is incorrect. Why? Imagine an isosceles triangle with a base of 1000 units and a height of 1e-9 units. The area is minuscule, compared to an equilateral triangle with unit length whereas the former has a huge perimeter (~2000 units) compared to the latter (3 units). That's just an (extreme) example to convey the flaw in your assumption.
I'd suggest you roll up your own area function. It's even mentioned on the problem page to use Heron's formula. Since it's just to be used in the comparison, then we don't need the exact area but an indicative area. So something like
double area(triangle const* tr) {
if(tr) {
double semiPerimeter = (tr->a + tr->b + tr->c)/2.0;
return semiPerimeter* (semiPerimeter - tr->a) * (semiPerimeter - tr->b) * (semiPerimeter - tr->c);
} else {
return 0;
}
}
Where we don't really need to calculate the square root since we just need to compare the areas across triangles and comparing the square of areas across triangles should be fine.
After this, it's just a matter of plugging this into whatever you did, after correcting the inner j loop to run only till n-1 (as the other answer has also explained)
void sort_by_area(triangle* tr, int n) {
/**
* Sort an array a of the length n
*/
double areaArr[n];
for(size_t i = 0; i < n; ++i) {
areaArr[i] = area(&tr[i]);
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n - 1; j++) {
if (areaArr[j] > areaArr[j + 1]) {
// Sort in area array.
int temp = areaArr[j];
areaArr[j] = areaArr[j + 1];
areaArr[j + 1] = temp;
// Sort in tr array.
triangle tmp = tr[j];
tr[j] = tr[j + 1];
tr[j + 1] = tmp;
}
}
}
}
You could directly use qsort too here since the problem doesn't prohibit using standard functions, something like:
int qsortCompare(void const* a, void const* b) {
triangle const* trA = a;
triangle const* trB = b;
if(trA && trB) {
double areaA = area(trA);
double areaB = area(trB);
return (areaA < areaB) ? -1 :
((areaA > areaB)? 1: 0);
}
return 0;
}
void sort_by_area(triangle* tr, int n) {
qsort(tr, n, sizeof(triangle), &qsortCompare);
}
Also, don't be restricted to add functions in the problem solution. The actual driver code only calls sort_by_area() but you can write other functions in the solution and call them from sort_by_area().
The inner loop does not need to run till n, only till n-1
for (int j = 0; j < n - 1; j++)
Because when j == n, then you are comparing with random junk outside of your respective arrays by accessing size[j+1] and tr[j+1].
Also, when swapping, you don't need to copy the structure members one-by-one. You can simply do:
// Sort in tr array.
triangle tmp = tr[j];
tr[j] = tr[j + 1];
tr[j + 1] = tmp;
Edit: As #CiaPan pointed out:
You have a memory leak. You need to call free() after you are done with using the malloc'd memory.
You are not allocating the right amount of memory. If you are passed more than 100 triangles, your code might behave weirdly or randomly crash.
int *size = malloc(n* sizeof(*size));
Full code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct {
int a;
int b;
int c;
} triangle;
void sort_by_area(triangle *tr, int n) {
// Array for storing the perimeter.
int *size = malloc(n* sizeof(*size));
// Adding perimeters in size array.
for (int i = 0; i < n; i++) {
size[i] = tr[i].a + tr[i].b + tr[i].c;
}
// Sort.
for (int i = 0; i < n; i++) {
for (int j = 0; j < n - 1; j++) {
if (size[j] > size[j + 1]) {
// Sort in size array.
int temp = size[j];
size[j] = size[j + 1];
size[j + 1] = temp;
// Sort in tr array.
triangle tmp = tr[j];
tr[j] = tr[j + 1];
tr[j + 1] = tmp;
}
}
}
}
int main() {
int n;
scanf("%d", &n);
triangle *tr = malloc(n * sizeof(triangle));
for (int i = 0; i < n; i++) {
scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
}
sort_by_area(tr, n);
for (int i = 0; i < n; i++) {
printf("%d %d %d\n", tr[i].a, tr[i].b, tr[i].c);
}
return 0;
}

Remove values from an array of int

I've written this small C function to remove integers from an array.
/* remove `count` integers from `arr`, starting at index `idx` */
void remove_int(int (*arr)[100], int idx, int count)
{
int i, j;
for (i = 0; i < count; i++)
for (j = idx; *arr[j]; j++)
*arr[j] = *arr[j+1];
}
Say I run it like this:
int arr[100] = {25, 4, 4, 1, 2, 1, 2};
remove_int(&arr, 7, 2);
I get a Segmentation Fault. Why?
EDIT Comment by BLUEPIXY solved it, answer by chqrlie explained it. Thanks guys!
Your code does not do what you think it does:
arr is defined as a pointer to an array of 100 int elements.
arr[j] does not point to the element at offset j, but rather to the jth array in the array pointed to by arr.
*arr[j] dereferences the integer at location arr[j][0], much beyond the end of the arr array from the calling function.
If you keep the same API, you should write the code this way:
/* remove `count` integers from `arr`, starting at index `idx` */
void remove_int(int (*arr)[100], int idx, int count) {
int i, j;
for (i = idx + count; i < 100 && (*arr)[i]; i++)
(*arr)[i - count] = (*arr)[i];
for (j = 0; j < count && i - count + j < 100; j++) {
(*arr)[i - count + j] = 0;
}
It is not idiomatic in C to handle pointers to arrays, it is more common to just pass arrays directly, and the called function receives a pointer to the first element of the array.
The function would then be called this way:
int arr[100] = {25, 4, 4, 1, 2, 1, 2};
remove_int(arr, 7, 2);
And the function would be written this way:
/* remove `count` integers from `arr`, starting at index `idx` */
void remove_int(int arr[100], int idx, int count) {
int i, j;
for (i = idx + count; i < 100 && arr[i]; i++)
arr[i - count] = arr[i];
for (j = 0; j < count && i - count + j < 100; j++) {
arr[i - count + j] = 0;
}
In this case, the [100] array size is ignored and the function behaves exactly the same as if it was defined as void remove_int(int *arr, int idx, int count)

Reversing int array using recursion in C

I have learnt C language at school but I'm not good at it... And when I was trying to implement this algorithm using C language:
ReverseArray(int A[], int i, int j) {
Input: Array A, nonnegative integer indices i and j
Output: The reversal of the elements in A starting at index i and ending at j
if i < j then
swap A[i] and A[j]
ReverseArray(A, i+1, j-1)
}
I managed to code this:
int *reverseArray(int A[], int i, int j) {
int *R = NULL;
if(i < j) {
int temp = A[j];
A[j] = A[i];
A[i] = temp;
R = reverseArray(A, i+1, j-1);
return R;
} else {
return R;
}
}
But when I tried to print the original and reversed array in the main:
int main(void) {
int A[] = {1, 3, 5, 6, 8, 3, 4, 2};
int *r = reverseArray(A, 0, 7);
//This prints out the reversed array, when I intended to print the original
for (size_t i = 0; i < 8; i++) {
printf("%d ", A[i]);
}
printf("\n");
/* This was intended to print the reversed array but doesn't work
for (size_t i = 0; i < 8; i++) {
printf("%d ", r[i]);
}
*/
return 0;
}
Could anyone please explain why the commented out for loop doesn't work? And why the first for loop prints out the reversed array...
Is there any other way to get the result of reverseArray() without using *r?
I tried to malloc *r just in case that was the problem, but it still didn't work.
Thank you.
Just don't return anything. You make a reversion in place, so the resulting array is the same as the array to be reversed, and the caller knows it already.
You need to print the contents of A before you call reverseArray, not after. The reason is that you are reversing the bytes in place so the array A itself is changed by calling reverseArray.
A try from your code base and the problem description
If allowed to rewrite the Array in place, then it will work
#include<stdio.h>
void reverseArray(int A[], int i, int j) {
//int *R = NULL;
if(i < j) {
int temp = A[j];
A[j] = A[i];
A[i] = temp;
reverseArray(A, i+1, j-1);
}
}
int main(void) {
int A[] = {1, 3, 5, 6, 8, 3, 4, 2};
//This prints out original array
for (size_t i = 0; i < 8; i++) {
printf("%d ", A[i]);
}
printf("\n");
reverseArray(A, 0, 7);
// print the reversed array
for (size_t i = 0; i < 8; i++) {
printf("%d ", A[i]);
}
return 0;
}
It will Output:
1 3 5 6 8 3 4 2
2 4 3 8 6 5 3 1
R is always assigned to NULL, and A is not a pointer, then you are editing the real data of the array.
if you want to reverse and create a new array, you must do something like that :
int *reverseArray(int array[], int arraySize) {
int *reversedArray = malloc(sizeof(int) * arraySize);
for ( int i = 0 ; i < arraySize ; ++i ) {
reversedArray[i] = array[arraySize - i - 1];
}
return reversedArray;
}
You can also do it in recursive way :
int *reverseArray(int inputArray[], int arrayLength ) {
int *_reverseArray (int inputArray[], int arrayLength, int *outputArray, int actual) {
if (outputArray == NULL) {
outputArray = malloc(sizeof(int) * arrayLength);
}
if (actual < arrayLength) {
outputArray[actual] = inputArray[arrayLength - actual - 1];
return _reverseArray(inputArray, arrayLength, outputArray, ++actual);
}
return outputArray;
}
return _reverseArray(inputArray, arrayLength, NULL, 0);
}
If you want to edit the original array :
void reverseArray(int array[], int arraySize)
{
for ( int i = 0 ; i < arraySize / 2 ; ++i ) {
array[i] ^= array[arraySize - i - 1];
array[arraySize - i - 1] ^= array[i];
array[i] ^= array[arraySize - i - 1];
}
}

I need help creating a k-combinations algorithm non-recursively

I've looked around online for an non-recursive k-combinations algorithm, but have had trouble understanding all of the reindexing involved; The code I've found online is not commented well, or crashes.
For example, if I have the collection, {'a', 'b', 'c', 'd', 'e'} and I want to find a 3 combinations; ie,
abc
abd
abe
acd
ace
ade
bcd
bce
bde
cde
How can I implement an algorithm to do this? When I write down the general procedure, this it is clear. That is; I increment the last element in a pointer until it points to 'e', increment the second to last element and set the last element to the second to last element + 1, then increment the last element again until it reaches 'e' again, and so on and so forth, as illustrated by how I printed the combinations. I looked at Algorithm to return all combinations of k elements from n for inspiration, but my code only prints 'abc'. Here is a copy of it:
#include <stdio.h>
#include <stdlib.h>
static void
comb(char *buf, int n, int m)
{
// Initialize a pointer representing the combinations
char *ptr = malloc(sizeof(char) * m);
int i, j, k;
for (i = 0; i < m; i++) ptr[i] = buf[i];
while (1) {
printf("%s\n", ptr);
j = m - 1;
i = 1;
// flag used to denote that the end substring is at it's max and
// the j-th indice must be incremented and all indices above it must
// be reset.
int iter_down = 0;
while((j >= 0) && !iter_down) {
//
if (ptr[j] < (n - i) ) {
iter_down = 1;
ptr[j]++;
for (k = j + 1; k < m; k++) {
ptr[k] = ptr[j] + (k - j);
}
}
else {
j--;
i++;
}
}
if (!iter_down) break;
}
}
int
main(void)
{
char *buf = "abcde";
comb(buf, 5, 3);
return 1;
}
The very big problem with your code is mixing up indices and values. You have an array of chars, but then you try to increment the chars as if they were indices into the buffer. What you really need is an array of indices. The array of chars can be discarded, since the indices provide all you need, or you can keep the array of chars separately.
I found a psuedocode description here, http://www4.uwsp.edu/math/nwodarz/Math209Files/209-0809F-L10-Section06_03-AlgorithmsForGeneratingPermutationsAndCombinations-Notes.pdf
and implemented it in C by
#include <stdlib.h>
#include <stdio.h>
// Prints an array of integers
static void
print_comb(int *val, int len) {
int i;
for (i = 0; i < len; i++) {
printf("%d ", val[i]);
}
printf("\n");
}
// Calculates n choose k
static int
choose(int n, int k)
{
double i, l = 1.0;
double val = 1.0;
for (i = 1.0; i <= k; i++) {
l = ((double)n + 1 - i) / i;
val *= l;
}
return (int) val;
}
static void
comb(int n, int r)
{
int i, j, m, max_val;
int s[r];
// Initialize combinations
for (i = 0; i < r; i++) {
s[i] = i;
}
print_comb(s, r);
// Iterate over the remaining space
for (i = 1; i < choose(n, r); i++) {
// use for indexing the rightmost element which is not at maximum value
m = r - 1;
// use as the maximum value at an index, specified by m
max_val = n - 1; // use for
while(s[m] == max_val) {
m--;
max_val--;
}
// increment the index which is not at it's maximum value
s[m]++;
// iterate over the elements after m increasing their value recursively
// ie if the m-th element is incremented, all elements afterwards are
// incremented by one plus it's offset from m
// For example, this is responsible for switching 0 3 4 to 1 2 3 in
// comb(5, 3) since 3 and 4 in the first combination are at their maximum
// value
for (j = m; j < r - 1; j++) {
s[j + 1] = s[j] + 1;
}
print_comb(s, r);
}
}
int
main(void)
{
comb(5, 3);
return 1;
}

Resources