Related
I have a graph code written a year ago which does not work now (AFAIR it worked). The graph is implemented with a square matrix which is symmetric respectively to the diagonal. I have omitted a lot of code to keep it as clear as possible, and this is still enough for the error to persist.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct
{
int **matrix;
unsigned size;
} graph;
void init(graph *gptr, int *matrix[], unsigned size)
{
gptr->size = size;
gptr->matrix = malloc(gptr->size * sizeof(*gptr->matrix));
for (unsigned i = 0; i < gptr->size; i++)
gptr->matrix[i] = malloc(gptr->size * sizeof(**gptr->matrix));
for (unsigned i = 0; i < gptr->size; i++)
for (unsigned j = 0; j <= i; j++)
gptr->matrix[i][j] = gptr->matrix[j][i] = matrix[i][j];
}
void add_vertex(graph *gptr, unsigned vertex)
{
for (unsigned i = 1; i < gptr->size; i++)
if (gptr->matrix[i][0] == vertex) return;
gptr->size++;
gptr->matrix = realloc(gptr->matrix, gptr->size * sizeof(*gptr->matrix));
for (unsigned i = 0; i < gptr->size; i++)
/* ERROR */
gptr->matrix[i] = realloc(gptr->matrix[i], gptr->size * sizeof(**gptr->matrix));
gptr->matrix[gptr->size - 1][0] = gptr->matrix[0][gptr->size - 1] = vertex;
for (unsigned i = 1; i < gptr->size; i++)
gptr->matrix[gptr->size - 1][i] = gptr->matrix[i][gptr->size - 1] = -1;
}
#define EDGES 7
#define RANDOM(min, max) min + rand() / ((RAND_MAX - 1) / (max - min))
#define MIN -1
#define MAX 9
int **getMatrix(unsigned size)
{
int **matrix = malloc(size * sizeof(*matrix));
for (unsigned i = 0; i < size; i++)
{
matrix[i] = malloc((i + 1) * sizeof(**matrix));
matrix[i][0] = i;
}
for (unsigned i = 1; i < size; i++)
{
for (unsigned j = 1; j < i; j++)
do
matrix[i][j] = RANDOM(MIN, MAX);
while (!matrix[i][j]);
matrix[i][i] = rand() % 2 - 1;
}
return matrix;
}
int main(void)
{
int **matrix = getMatrix(EDGES + 1);
graph x;
init(&x, matrix, EDGES + 1);
add_vertex(&x, EDGES + 1);
}
At gptr->matrix[i] = realloc(gptr->matrix[i], gptr->size * sizeof(**gptr->matrix)); the program gets paused by an exception Trace/breakpoint trap. I have googled for a while, and to me it's most likely there is something wrong with my reallocation, but I have no idea what's wrong. Besides, it works fine on clang and even on online gcc 7.4 whereas fails to succeed on my gcc 8.1. Can anyone see where I'm mistaken?
On the first entry to add_vertex, gptr->size == 8 and gptr->matrix points to an array of 8 pointers to malloc'ed memory.
gptr->size++;
Now gptr->size == 9.
gptr->matrix = realloc(gptr->matrix, gptr->size * sizeof(*gptr->matrix));
And now gptr->matrix points to an array of 9 pointers. gptr->matrix[0] .. gptr->matrix[7] are the valid malloc'ed pointers from before, and gptr->matrix[8] contains uninitialized garbage.
for (unsigned i = 0; i < gptr->size; i++)
/* ERROR */
gptr->matrix[i] = realloc(gptr->matrix[i], gptr->size * sizeof(**gptr->matrix));
Since gptr->size == 9, this iterates 9 times, and on the 9th iteration, the garbage pointer gptr->matrix[8] is passed to realloc. Not good.
You could iterate the loop gptr->size - 1 times instead, and initialize gptr->matrix[gptr->size - 1] = malloc(...) separately. Or to be a little lazy and avoid code duplication, you could initialize gptr->matrix[gptr->size - 1] = NULL before this loop, keep it iterating gptr->size times, and rely on the handy feature that realloc(NULL, sz) is equivalent to malloc(sz).
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;
}
I'm trying to make a simple console application in C which will calculate the determinant of a Matrix using the Gauss elimination. after a lot of tests I found out that my program is not working because of the core dumped error.After 2 days of editing and undoing, i could not find the problem.
Any help is more than welcomed.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int recherche_pivot(int k, int n, float *A)
{
int i, j;
if (A[((k - 1) * n + k) - 1] != 0)
{
return k;
}
else
{ //parcours du reste de la colonne
for (i = k + 1; i <= n; i++)
{
if (A[((k - 1) * n + i) - 1] != 0)
{
return i;
}
}
return -1;
}
}
void fois(int n, float p, int i, float * A, float *b, float * x)
{
int a;
for (a = 1; a <= n; a++)
{
x[a - 1] = A[((i - 1) * n + a) - 1] * p;
}
x[n] = b[i - 1] * p;
}
void afficher_system(int n, float * X, float *b)
{
int i, j;
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
printf("%f ", X[((i - 1) * n + j) - 1]);
printf(" | %f", b[i - 1]);
printf("nn");
}
printf("nnnn");
}
void saisirmatrice(int n, float *A)
{
int i, j;
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
scanf("%f", &A[((i - 1) * n + j) - 1]);
}
void affichermatrice(int n, float *A)
{
int i, j;
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
printf("A[%d][%d] = %fn", i, j, A[((i - 1) * n + j) - 1]);
}
void elemination(int n, int k, float *b, float *A)
{
int i, l, j;
float * L, piv;
L = (float *) malloc((n) * sizeof(float));
for (i = k + 1; i <= n; i++)
{
piv = -1 * (A[((i - 1) * n + k) - 1] / A[((k - 1) * n + k) - 1]);
fois(n, piv, k, A, b, L);
//afficher_vecteur(n,L);
for (j = 1; j <= n; j++)
{
A[((i - 1) * n + j) - 1] = A[((i - 1) * n + j) - 1] + L[j - 1];
}
b[i - 1] = b[i - 1] + L[n];
afficher_system(n, A, b);
}
}
void permutter(int n, float * A, int i, int j, float * b)
{
int a;
float t[n + 1];
for (a = 1; a <= n; a++)
{
t[a - 1] = A[((i - 1) * n + a) - 1];
A[((i - 1) * n + a) - 1] = A[((j - 1) * n + a) - 1];
A[((j - 1) * n + a) - 1] = t[a - 1];
}
t[n] = b[i - 1];
b[i - 1] = b[j - 1];
b[j - 1] = t[n];
}
void main()
{
float * A, det, *L, *R, *b, s;
int i, j, i0, n, k, stop = 0;
printf("Veuillez donner la taille de la matrice");
scanf("%d", &n);
A = (float *) malloc(sizeof(float) * (n * n));
L = (float*) malloc(n * sizeof(float));
R = (float*) malloc(n * sizeof(float));
b = (float*) malloc(n * sizeof(float));
printf("Veuillez remplir la matrice");
saisirmatrice(n, A);
det = 1;
stop = 0;
k = 1;
do
{
do
{
i0 = recherche_pivot(k, n, A);
if (i0 == k)
{
//Elémination
elemination(n, k, b, A);
k++;
}
else if (i0 == -1)
{
stop = 1;
}
else
{ //cas ou ligne pivot=i0 != k
//permutation
det = -det;
permutter(n, A, k, i0, b);
//elemination
elemination(n, k, b, A);
//afficher_matrice(n,A);
k++;
}
} while ((k <= n) && (stop == 0));
} while (stop == 1 || k == n);
for (i = 1; i < n; i++)
{
det = det * A[((i - 1) * n + i) - 1];
}
printf("Le determinant est :%f", det);
free(A);
free(L);
free(R);
free(b);
}
There are many problems in the above code. Since arrays are zero-indexed in C, you should count the rows and columns of your matrices starting from zero, instead of counting from 1 and then attempting to convert when array-indexing. There is no need to cast the result of malloc(), and it is better to use an identifier rather than an explicit type as the argument for the sizeof operator:
A = malloc(sizeof(*A) * n * n));
You allocate space for L and R in main(), and then never use these pointers until the end of the program when they are freed. Then you allocate for L within the elemination() function; but you never free this memory, so you have a memory leak. You also allocate space for b in main(), but you don't store any values in b before passing it to the elemination() function. This is bound to cause problems.
There is no need for dynamic allocation here in the first place; I suggest using a variable length array to store the elements of the matrix. These have been available since C99, and will allow you to avoid all of the allocation issues.
There is a problem in the recherche_pivot() function, where you compare:
if(A[((k - 1) * n + i) - 1] != 0) {}
This is a problem because the array element is a floating point value which is the result of arithmetic operations; this value should not be directly compared with 0. I suggest selecting an appropriate DELTA value to represent a zero range, and instead comparing:
#define DELTA 0.000001
...
if (fabs(A[((k - 1) * n + i) - 1]) < DELTA) {}
In the permutter() function you use an array, float t[n];, to hold temporary values. But an array is unnecessary here since you don't need to save these temporary values after the swap; instead just use float t;. Further, when you interchange the values in b[], you use t[n] to store the temporary value, but this is out of bounds.
The elemination() function should probably iterate over all of the rows (excepting the kth row), rather that starting from the kth row, or it should start at the k+1th row. As it is, the kth row is used to eliminate itself. Finally, the actual algorithm that you use to perform the Gaussian elimination in main() is broken. Among other things, the call permutter(n, A, k, i0, b); swaps the kth row with the i0th row, but i0 is the pivot column of the kth row. This makes no sense.
It actually looks like you want to do more than just calculate determinants with this code, since you have b, which is the constant vector of a linear system. This is not needed for the task alluded to in the title of your question. Also, it appears that your code gives a result of 1 for any 1X1 determinant. This is incorrect; it should be the value of the single number in this case.
The Gaussian elimination method for calculating the determinant requires that you keep track of how many row-interchanges are performed, and that you keep a running product of any factors by which individual rows are multiplied. Adding a multiple of one row to another row to replace that row does not change the value of the determinant, and this is the operation used in the reduce() function below. The final result is the product of the diagonal entries in the reduced matrix, multiplied by -1 once for every row-interchange operation, divided by the product of all of the factors used to scale individual rows. In this case, there are no such factors, so the result is simply the product of the diagonal elements of the reduced matrix, with the sign correction. This is the method used by the code posted in the original question.
There were so many issues here that I just wrote a fresh program that implements this algorithm. I think that it is close, at least in spirit, to what you were trying to accomplish. I did add some input validation for the size of the matrix, checking to be sure that the user inputs a positive number, and prompting for re-entry if the input is bad. The input loop that fills the matrix would benefit from similar input validation. Also note that the input size is stored in a signed int, to allow checks for negative input, and a successful input is cast and stored in a variable of type size_t, which is an unsigned integer type guaranteed to hold any array index. This is the correct type to use when indexing arrays, and you will note that size_t is used throughout the program.
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
#define DELTA 0.000001
void show_matrix(size_t mx_sz, double mx[mx_sz][mx_sz]);
void interchange(size_t r1, size_t r2, size_t mx_sz, double mx[mx_sz][mx_sz]);
void reduce(double factor, size_t r1, size_t r2,
size_t mx_sz, double mx[mx_sz][mx_sz]);
size_t get_pivot(size_t row, size_t mx_sz, double mx[mx_sz][mx_sz]);
double find_det(size_t mx_sz, double mx[mx_sz][mx_sz]);
int main(void)
{
size_t n;
int read_val, c;
printf("Enter size of matrix: ");
while (scanf("%d", &read_val) != 1 || read_val < 1) {
while ((c = getchar()) != '\n' && c != EOF) {
continue; // discard extra characters
}
printf("Enter size of matrix: ");
}
n = (size_t) read_val;
double matrix[n][n];
printf("Enter matrix elements:\n");
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < n; j++) {
scanf("%lf", &matrix[i][j]);
}
}
printf("You entered:\n");
show_matrix(n, matrix);
putchar('\n');
double result = find_det(n, matrix);
show_matrix(n, matrix);
putchar('\n');
printf("Determinant: %f\n", result);
return 0;
}
void show_matrix(size_t n, double mx[n][n])
{
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < n; j++) {
printf("%7.2f", mx[i][j]);
}
putchar('\n');
}
}
/* interchange rows r1 and r2 */
void interchange(size_t r1, size_t r2, size_t mx_sz, double mx[mx_sz][mx_sz])
{
double temp;
for (size_t j = 0; j < mx_sz; j++) {
temp = mx[r1][j];
mx[r1][j] = mx[r2][j];
mx[r2][j] = temp;
}
}
/* add factor * row r1 to row r2 to replace row r2 */
void reduce(double factor, size_t r1, size_t r2,
size_t mx_sz, double mx[mx_sz][mx_sz])
{
for (size_t j = 0; j < mx_sz; j++) {
mx[r2][j] += (factor * mx[r1][j]);
}
}
/* returns pivot column, or mx_sz if there is no pivot */
size_t get_pivot(size_t row, size_t mx_sz, double mx[mx_sz][mx_sz])
{
size_t j = 0;
while (j < mx_sz && fabs(mx[row][j]) < DELTA) {
++j;
}
return j;
}
double find_det(size_t mx_sz, double mx[mx_sz][mx_sz])
{
size_t pivot1, pivot2;
size_t row;
double factor;
bool finished = false;
double result = 1.0;
while (!finished) {
finished = true;
row = 1;
while (row < mx_sz) {
// determinant is zero if there is a zero row
if ((pivot1 = get_pivot(row - 1, mx_sz, mx)) == mx_sz ||
(pivot2 = get_pivot(row, mx_sz, mx)) == mx_sz) {
return 0.0;
}
if (pivot1 == pivot2) {
factor = -mx[row][pivot1] / mx[row - 1][pivot1];
reduce(factor, row - 1, row, mx_sz, mx);
finished = false;
} else if (pivot2 < pivot1) {
interchange(row - 1, row, mx_sz, mx);
result = -result;
finished = false;
}
++row;
}
}
for (size_t j = 0; j < mx_sz; j++) {
result *= mx[j][j];
}
return result;
}
Sample session:
Enter size of matrix: oops
Enter size of matrix: 0
Enter size of matrix: -1
Enter size of matrix: 3
Enter matrix elements:
0 1 3
1 2 0
0 3 4
You entered:
0.00 1.00 3.00
1.00 2.00 0.00
0.00 3.00 4.00
1.00 2.00 0.00
-0.00 -3.00 -9.00
0.00 0.00 -5.00
Determinant: 5.000000
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.
I am currently implementing an N x 2 matrix of floats on the heap as follows:
float **matrix = malloc(sizeof(float*) * n_cols);
for (int i = 0; i < n_cols; ++i) {
matrix[i] = malloc(sizeof(float) * 2);
}
The elements of matrix are not contiguous in memory, making this data structure cache unfriendly (as I understand it). I am trying to re-write the above to create a genuine 2D array on the heap. Based on some previous SO posts, I tried the following:
float (*matrix)[2] = malloc(sizeof(float) * n_cols * 2);
However, this lead to a segmentation fault when I ran my code.
If you want the whole array to be contiguous then you need to declare it as follows.
float *matrix = malloc(n1 * n2 * sizeof(float));
Does this help. Note the second way the matrix has been allocated.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
size_t r = 0;
size_t c = 0;
int rows = 82;
int columns = 30;
float *matrix = malloc(rows * columns * sizeof(float));
for(r = 0; r < rows; r++) {
printf("%zu - ", r);
for(c = 0; c < columns; c++) {
printf("%zu|", c);
matrix[r + r*c] = 1.0;
}
printf("\n");
}
float **matrix2 = malloc(rows * sizeof(float*));
for(r = 0; r < rows; r++) {
matrix2[r] = malloc(columns * sizeof(float));
}
for(r = 0; r < rows; r++) {
printf("%zu - ", r);
for(c = 0; c < columns; c++) {
printf("%zu|", c);
matrix2[r][c] = 1.0;
}
printf("\n");
}
free(matrix);
for(r = 0; r < rows; r++) {
free(matrix2[r]);
}
free(matrix2);
return 0;
}
You can find a benchmark with the code here...
https://github.com/harryjackson/doc/blob/master/c/cache_locality_2d_array_test.c
I think you want something like this.
float ** matrix = malloc(sizeof(float) * ((n_col * 2) + (n_col * sizeof(float*));
for(i = 0; i < n_col; i++)
{
matrix[i] = matrix + (n_col *sizeof(float*)) + ((i * 2) *sizeof(float));
}
The size of your matrix is 2* n_col, however the first index into your matrix is going to be a pointer to a column. You have to allocate additional space for these pointers. This is where the (n_col * sizeof(float *)) comes into play. Each row is of size (2 * sizeof(float)), so each of the first indexed in the matrix need to point to an array of memory (2 * sizeof(float)) bytes away from the last one.
It looks something like this.
m[0] m[1] m[2]
matrix matrix + 1 * (2 * sizeof(float)) matrix + 2 * (2 * sizeof(float))
The second index deference a location into the memory pointed to by m[x].