The concrete purpose is transferring a string array to a matrix of coefficients and the solving it as a linear system of equations.
I have a bit of trouble with two-dimensional arrays in C. I want to pass such an array to a function accepting a pointer to pointers. I figured no way of really passing the array itself. Furthermore, I am not very sure if my solution is perfect practice because it is very circuitous and long. Especially because this should be a library documentation, I want to have the best way of doing it possible. To the code:
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX_STRING 256
#define ALPHABET_LENGTH 26
#define MAX_ASCII 128
#define MAX_TEMP 256
void lsoeSolveRecursive(double**, double[], int, int);
void lsoePartition(double**, int);
void lsoeElimination(double**, int, int);
void lsoeSwap(double**, int, int);
void lsoeExpand(double**, int);
void lsoeShrink(double**, int);
int getDecimalPlaces(double);
int lcm(int, int);
int gcd(int, int);
void seSearch(char[], char[], char[], int, int, double**);
bool seIsDigit(char);
const char possibleVarNames[] = "xyzabcdefghijklmnopqrstuvwxyz";
int power;
void lsoeSolve(double **matrix, double matrixr[], int matrixc)
{
lsoePartition(matrix, matrixc);
lsoeSolveRecursive(matrix, matrixr, matrixc, 1);
}
void lsoeSolveRecursive(double **matrix, double matrixr[], int matrixc, int i)
{
double res = matrix[matrixc - i][matrixc];
for (int j = 0; j < i; j++)
res -= matrixr[matrixc - j] * matrix[matrixc - i][matrixc - j];
matrixr[matrixc - i] = res / matrix[matrixc - i][matrixc - i];
if (i != matrixc)
lsoeSolveRecursive(matrix, matrixr, matrixc, i + 1);
}
void lsoePartition(double **matrix, int matrixc)
{
double part[2][matrixc + 1];
for (int a1 = 0; a1 < matrixc - 1; a1++)
for (int a2 = a1 + 1; a2 < matrixc; a2++)
{
for (int j = a1; j < matrixc + 1; j++)
{
part[0][j] = matrix[a1][j];
part[1][j] = matrix[a2][j];
}
if (part[0][a1] == 0 || part[1][a1] == 0)
{
if (part[0][a1] == 0)
lsoeSwap(matrix, a1, a2);
break;
}
double *arg[2];
for (int i = 0; i < 2; i++)
arg[i] = part[i];
lsoeElimination(arg, matrixc, a1);
for (int j = a1; j < matrixc + 1; j++)
{
matrix[a1][j] = part[0][j];
matrix[a2][j] = part[1][j];
}
}
}
void lsoeElimination(double **part, int matrixc, int index)
{
lsoeExpand(part, matrixc);
int leastCommonMultiply = abs(lcm(part[0][index], part[1][index]));
double factor = leastCommonMultiply / fabs(part[0][index]);
if (part[0][index] > 0)
for (int i = index; i < matrixc + 1; i++)
part[0][i] *= -(factor);
else
for (int i = index; i < matrixc + 1; i++)
part[0][i] *= factor;
factor = leastCommonMultiply / fabs(part[1][index]);
if (part[1][index] < 0)
for (int i = index; i < matrixc + 1; i++)
part[1][i] *= -(factor);
else
for (int i = index; i < matrixc + 1; i++)
part[1][i] *= factor;
for (int i = 0; i < matrixc + 1; i++)
part[1][i] += part[0][i];
lsoeShrink(part, matrixc);
}
void lsoeSwap(double **array, int a, int b)
{
double *temp = array[a];
array[a] = array[b];
array[b] = temp;
}
void lsoeExpand(double **part, int matrixc)
{
for (int i = 0; i < 2; i++)
for (int j = 0; j < matrixc + 1; j++)
{
int decimalPlaces;
decimalPlaces = getDecimalPlaces(part[i][j]);
if (decimalPlaces > power)
power = decimalPlaces;
}
for (int i = 0; i < 2; i++)
for (int j = 0; j < matrixc + 1; j++)
part[i][j] = part[i][j] * pow(10, power);
}
void lsoeShrink(double **part, int matrixc)
{
for (int i = 0; i < 2; i++)
for (int j = 0; j < matrixc + 1; j++)
part[i][j] = part[i][j] * pow(10, -power);
}
int getDecimalPlaces(double n)
{
char string[MAX_STRING];
int numberOfDecimalPlaces = 0;
int i = sprintf(string, "%f", n);
bool countZero = false;
for (int j = i - 1; j > 0; j--)
{
if (string[j] == '.')
break;
if (!countZero && string[j] != 48)
countZero = true;
if (countZero)
numberOfDecimalPlaces++;
}
return numberOfDecimalPlaces;
}
int gcd(int a, int b)
{
if (a == 0)
return b;
return gcd(b % a, a);
}
int lcm(int a, int b)
{
return a / gcd(a, b) * b;
}
void seEvaluate(char **line, int linec, double **matrix) // linec: Anzahl Zeilen
{
bool ascii[MAX_ASCII], v[ALPHABET_LENGTH];
for (int i = 0; i < MAX_ASCII; i++)
{
ascii[i] = false;
v[i % ALPHABET_LENGTH] = false;
}
for (int i = 0; i < linec; i++)
for (int j = 0; j < strlen(line[i]); j++)
ascii[(int) line[i][j]] = true;
for (int i = 0; i < ALPHABET_LENGTH; i++)
{
if (i < 23)
{
if (ascii[i + 97])
v[i + 3] = true;
}
else
{
if (ascii[i + 97])
v[i - 23] = true;
}
}
char vars[ALPHABET_LENGTH] = "";
for (int i = 0; i < ALPHABET_LENGTH; i++)
if (v[i])
{
char str[2] = "\0";
str[0] = possibleVarNames[i];
strcat(vars, str);
}
3
char temp[MAX_TEMP];
for (int i = 0; i < strlen(vars); i++)
{
for (int i = 0; i < MAX_TEMP; i++)
temp[i] = 0;
seSearch(line[i], vars, temp, 0, i, matrix);
}
}
void seSearch(char equation[], char vars[], char temp[], int index, int row,
double **matrix)
{
if (seIsDigit(equation[index]) || equation[index] == '-')
{
char str[2] = "\0";
str[0] = equation[index];
strcat(temp, str);
}
else if (equation[index] == '.' || equation[index] == ',')
strcat(temp, ".");
else
{
for (int i = 0; i < strlen(vars); i++)
{
if (equation[index] == vars[i])
{
if (strcmp(temp, "") == 0 || strcmp(temp, "\0") == 0
|| strcmp(temp, "-") == 0)
strcat(temp, "1");
matrix[row][i] = strtod(temp, NULL);
memset(temp, 0, MAX_TEMP);
break;
}
}
}
if (index + 1 < strlen(equation))
seSearch(equation, vars, temp, index + 1, row, matrix);
else
matrix[row][strlen(vars)] = strtod(temp, NULL);
}
bool seIsDigit(char c)
{
if (c > 47 && c < 58)
return true;
return false;
}
// Number of results equal to the rows of the linear system of equations.
#define NUMBER_OF_RESULTS 4
int main(void)
{
// Example matrix entered as 4 strings.
char stringMatrix[NUMBER_OF_RESULTS][256] =
{ "3x + 4y -5z + 6a = 39",
"6x + 5y - 6z + 5a = 43",
"9x - 4y + 2z + 3a = 6",
"2y - 3z + a = 13" };
// Array for storing the results.
double matrixr[NUMBER_OF_RESULTS];
// Turning the matrix to pointer array suitable for functions.
char *pMatrix[NUMBER_OF_RESULTS];
for (int i = 0; i < NUMBER_OF_RESULTS; i++)
pMatrix[i] = stringMatrix[i];
// Array for storing the result of string evaluation.
static double resMatrix[NUMBER_OF_RESULTS][NUMBER_OF_RESULTS+1];
// Turning the coefficient matrix suitable for functions.
double *pRetMatrix[NUMBER_OF_RESULTS];
for (int i = 0; i < NUMBER_OF_RESULTS; i++)
pRetMatrix[i] = resMatrix[i];
// Evaluating the string matrix.
seEvaluate(pMatrix, NUMBER_OF_RESULTS, pRetMatrix);
// Solving the coefficient matrix.
lsoeSolve(pRetMatrix, matrixr, NUMBER_OF_RESULTS);
// Printing out the results.
printf("Linear System Of Equations:\n");
for (int i = 0; i < 4; i++)
printf("%s\n", stringMatrix[i]);
printf("--> ");
printf("x = %.2f, y = %.2f, z = %.2f, a = %.2f", matrixr[0], matrixr[1],
matrixr[2], matrixr[3]);
printf("\n\n");
return 0;
}
If you know a better way for doing so, I would be very pleased with an answer. Thanks in advance!
Edit: I want to use two-dimensional arrays in functions furthermore, but can't find a way of doing without converting them to pointers the messy way described.
Edit 2: I appended the full source code as a working one working file now. I hope it helps you.
know a better way for doing soThere may be ways to achieve same better in some intuitive way. For doing so, I lack an intuition for good/better. stackoverflow is a better fit for "how-to" questions. \$\endgroup\$double part[2][matrixc + 1];and use inintfunctions likeabs(part[0][index])? \$\endgroup\$struct inputthat has the strings andstruct lsoethat has all of the matrix and the dimensions that you extracted would probably help. \$\endgroup\$abs()tofabs()in these cases now. \$\endgroup\$