It seems to be a simply exercise, but something doesn't work with the following qsort algorithmus. The struct abcSort correctly shows all assigned values. Unfortunately, the qsort is not sorting anything.
typedef int(*compfn)(const void*, const void*);
struct ABCSort
{
int svSort[10];
string itemSort[10];
};
struct ABCSort abcSort;
int compare(struct ABCSort*, struct ABCSort*);
void mainSort()
{
for (int i = 0; i < 10; i++)
{
abcSort.svSort[i] = 100 - i;
abcSort.itemSort[i] = arrayREAD[i][2];
}
qsort( (void*)&abcSort, 10, sizeof(struct ABCSort), (compfn)compare );
}
int compare(struct ABCSort *elem1, struct ABCSort *elem2)
{
if (elem1->svSort< elem2->svSort)
return -1;
else if (elem1->svSort > elem2->svSort)
return 1;
else
return 0;
}
You have build two arrays of integer and strings and you want to sort them by the numbers, keeping the initial pairing. That's the first problem, you should have created one array of structs, each struct containg a number and a string and a function that compares the integer member of that struct to obtain the sort order.
You also tagged this question as C++ but you are using qsort, arrays and function pointers like C, so I'll present two complete C programs that solve your problem.
Let's see, using an array of structs, what your code could be like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 6
#define CMAX 15
typedef int(*cmp_fn)(const void*, const void*);
typedef struct {
int num;
char str[CMAX];
} numABC;
int comp_struct(const numABC *lhs, const numABC *rhs ) {
if ( lhs->num < rhs->num )
return -1;
if ( lhs->num > rhs->num )
return 1;
return 0;
}
int main(void) {
numABC myArray[MAX] = { {6, "cat"}, {4, "dog"}, {8, "panter"},
{2, "red fish"}, {1, "hawk"}, {6, "snake"} };
int i;
// sort the array of structs by int member
qsort(myArray, MAX, sizeof(numABC), (cmp_fn)comp_struct);
// print out the sorted array
printf("\nSort by numbers:\n");
for ( i = 0; i < MAX; ++i ) {
printf("%d %s\n",myArray[i].num,myArray[i].str);
}
return 0;
}
If you want to use this code, but you have a couple of arrays instead, one option is to convert those arrays:
int nums[MAX] = {6,4,8,2,1,3};
char str[MAX][CMAX] = {"cat","dog","panter","red fish","hawk","snake"};
int i;
// create the array of structs from the two arrays
numABC myArray[MAX];
for ( i = 0; i < MAX; ++i ) {
myArray[i].num = nums[i];
strcpy(myArray[i].str, str[i]);
}
Another option to sort two different arrays (mantaining the pairing or alignment between the two) is to use a more complicated method which consists in sorting an array of indeces instead. to keep the relationships between the two original arrays I'll have to use global variables which can be accessed inside the compare function(s). Once the indeces are sorted, the original arrays are changed accordingly.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 6
#define CMAX 15
const size_t I_DIM = MAX * sizeof(int);
const size_t SS_DIM = MAX * sizeof(char*);
const size_t S_DIM = MAX * CMAX;
// global variables needed to perform comparisons
int *pg_int;
char **pg_str;
typedef int(*cmp_fn)(const void*, const void*);
int comp_num(const int *lhs, const int *rhs ) {
if (pg_int[*lhs] < pg_int[*rhs])
return -1;
if (pg_int[*lhs] > pg_int[*rhs])
return 1;
return 0;
}
int comp_str(const int *lhs, const int *rhs ) {
return strcmp(pg_str[*lhs],pg_str[*rhs]);
}
int main(void) {
int nums[MAX] = {6,4,8,2,1,3};
char str[MAX][CMAX] = {"cat","dog","panter","red fish","hawk","snake"};
int i;
// create an array of indeces
int index[MAX];
for ( i = 0; i < MAX; ++i ) {
index[i] = i;
}
// set global copies
pg_int = malloc(I_DIM);
memcpy(pg_int,nums,I_DIM);
pg_str = malloc(SS_DIM);
pg_str[0] = malloc(S_DIM);
memcpy(pg_str[0],str[0],S_DIM);
for ( i = 1; i < MAX; i++ ) {
pg_str[i] = pg_str[0] + i * CMAX;
}
// sort the indeces ordering by ints
qsort(index, MAX, sizeof(int), (cmp_fn)comp_num);
//update the two arrays
for ( i = 0; i < MAX; ++i ) {
nums[i] = pg_int[index[i]];
strcpy(str[i],pg_str[index[i]]);
}
// print out sorted couples
printf("Sort by numbers:\n");
for ( i = 0; i < MAX; ++i ) {
printf("%d %s\n",nums[i],str[i]);
}
// sort the indeces ordering by strings
qsort(index, MAX, sizeof(int), (cmp_fn)comp_str);
//update the two arrays
for ( i = 0; i < MAX; ++i ) {
nums[i] = pg_int[index[i]];
strcpy(str[i],pg_str[index[i]]);
}
// print out sorted couples
printf("\nSort by strings:\n");
for ( i = 0; i < MAX; ++i ) {
printf("%d %s\n",nums[i],str[i]);
}
free(pg_int);
free(pg_str[0]);
free(pg_str);
return 0;
}
The output (sorry for the silly example) is:
Sort by numbers:
1 hawk
2 red fish
3 snake
4 dog
6 cat
8 panter
Sort by strings:
6 cat
4 dog
1 hawk
8 panter
2 red fish
3 snake
If you want to accomplish the same task in C++ you should take advantage of the Standard Library and use std::vector as a container and std::sort as algorithm:
#include <iostream>
#include <vector>
#include <algorithm>
using std::vector;
using std::string;
using std::cout;
struct numABC {
double num;
string str;
// instead of a compare function I can overload operator <
friend bool operator<( const numABC &lhs, const numABC &rhs ) {
return lhs.num < rhs.num;
}
};
// or use a lambda
auto cmp_str = []( const numABC &lhs, const numABC &rhs ) -> bool {
return lhs.str < rhs.str;
};
int main() {
vector<numABC> my_data = { {3.6, "cat"}, {5.7, "dog"}, {7.1, "panter"},
{0.2, "red fish"}, {1.8, "hawk"}, {1.1, "snake"}};
std::sort(my_data.begin(), my_data.end());
std::cout << "Sort by numbers:\n";
for ( auto & s : my_data ) {
std::cout << s.num << ' ' << s.str << '\n';
}
std::sort(my_data.begin(), my_data.end(), cmp_str);
// passing a lambda to specify how to compare ^^
std::cout << "Sort by strings:\n";
// if you don't like c++11 range for:
for ( int i = 0; i < my_data.size(); ++i ) {
std::cout << my_data[i].num << ' ' << my_data[i].str << '\n';
}
return 0;
}
Note that I have initialized my_data as a vector of objects of type numABC. If you have to start from two arrays, you can create the vector like this:
vector<double> nums = {3.6, 5.7, 7.1, 0.2, 1.8, 1.1};
vector<string> str = {"cat", "dog", "panter", "red fish", "hawk", "snake"};
vector<numABC> my_data;
for ( int i = 0; i < nums.size(); ++i ) {
my_data.push_back(numABC{nums[i],str[i]});
}
After sorting, if you have to extract the two vectors again (instead of simply looping through my_data) you can do something like this:
for ( int i = 0; i < my_data.size(); ++i ) {
nums[i] = my_data[i].num;
str[i] = my_data[i].str;
}
Alternatively you could implement an algorithm similar to the one I used before and sort the two vectors nums and srt using an auxiliary vector of indeces:
vector<double> nums = {3.6, 5.7, 7.1, 0.2, 1.8, 1.1};
vector<string> str = {"cat", "dog", "panter", "red fish", "hawk", "snake"};
// create the vector of indeces
vector<int> idx(nums.size());
std::iota(idx.begin(),idx.end(),0); // fill the vector, require #include <numeric>
// thanks to the lambda variable capture you don't need globals
auto cmp_ind = [ &nums ]
( const int &lhs, const int &rhs ) -> bool {
return nums[lhs] < nums[rhs];
};
// sort indeces
std::sort(idx.begin(), idx.end(),cmp_ind);
// create sorted arrays. It could be done in place but it's more difficult
vector<double> sorted_nums(nums.size());
vector<string> sorted_str(str.size());
for ( int i = 0; i < nums.size(); ++i ) {
sorted_nums[i] = nums[idx[i]];
sorted_str[i] = str[idx[i]];
}
std::cout << "Sort by numbers:\n";
for ( int i = 0; i < nums.size(); ++i ) {
std::cout << sorted_nums[i] << ' ' << sorted_str[i] << '\n';
}
You seem to intend to sort an array of integers (your compare function looks like that). But what you are actually handing over to qsort for sorting is a pointer to a structure that holds, among other stuff, an array.
So what you are actually trying to sort is one single struct ABCSort which is initialized and 9 other, uninitialized structures. This must fail.
Your qsort line should look like so:
qsort ((void*)&(abcsort.svsort), 10, sizeof (int), (compfn)compare);
Also, you should change the compare function so that it takes and works on two pointers to integers:
int compare (int * e1, int * e2) {
return *e1 - *e2;
}
EDIT:
After you have explained a bit better what you want, have a look at the following:
typedef int(compfn)(const void, const void*);
#define MAXCARS 5
struct car {
int sortKey;
double displacement;
char name[15]; /* Note I have decided this should be C */
};
/* This time we have an array of structs */
struct car cars [MAXCARS] = {
{ 0, 1.9, "BMW" },
{ 0, 6.3, "Audi" },
{ 0, 0.5, "Fiat" },
{ 0, 25.0, "Humvee" },
{ 0, 0.05, "Minibike" }
};
int compare(struct car*, struct car*);
void main(int argc, char *argv []) {
int i;
for (i = 0; i < MAXCARS; i++)
cars[i].sortKey = 100 - i;
qsort((void *)&cars, MAXCARS, sizeof(struct car), (compfn)compare);
}
/* Note we are comparing struct car-s in here, based on their displacement */
int compare(struct car *elem1, struct car *elem2) {
return elem1->sortKey - elem2->sortKey;
}
Related
I have an array of integers with a bunch of numbers from 1-10
Then I have an array of names(strings) which belong with the numbers a.e.
Numbers[0] = 5, Numbers[1] = 2
Names[0] = "Jeremy", Names [1] = "Samantha".
I can easily order the numbers with:
int n = sizeof(Numbers) / sizeof(Numbers[0]);
sort(Numbers, Numbers + n, greater<int>());
But then the names and numbers don't match at all.
How do I fix this?
A very common approach is to create an array of indices and sort that:
std::vector<int> indices(Numbers.size());
std::iota(indices.begin(), indices.end(), 0);
std::sort(indices.begin(), indices.end(),
[&](int A, int B) -> bool {
return Numbers[A] < Numbers[B];
});
The original arrays are not altered, but now indices can be used to access both arrays in the desired order.
If we want to reorder Numbers or Names in place, then we can
create a set of "back indices" that record where to find the element i in the sorted array:
std::vector<int> back_indices(indices.size());
for (size_t i = 0; i < indices.size(); i++)
back_indices[indices[i]] = i;
Now we can reorder, for example, Names in place in the desired order:
int index = 0;
std::string name = Names[index];
for (int i = 0; i < back_indices.size(); i++) {
index = back_indices[index];
std::swap(name,Names[index]);
}
I've tested this code which should give you the required behavior:
struct numberName {
int num;
string name;
};
bool compare(numberName a, numberName b){
return a.num < b.num; // if equal, no need to sort.
}
int main() {
numberName list[2];
list[0].num = 5, list[1].num = 2;
list[0].name = "Jeremy", list[1].name = "Samantha";
sort(list, list+2, compare);
}
Like HAL9000 said, you want to use a struct since this keeps variables that belong to each other together. Alternatively you could use a pair, but I don't know if a pair would be good practice for your situation or not.
This is a great example of the complexities introduced by using parallel arrays.
If you insist on keeping them as parallel arrays, here is a possible approach. Create a vector of integer indexes, initialised to { 0, 1, 2, 3, etc }. Each integer represents one position in your array. Sort your vector of indexes using a custom comparision function that uses the indexes to refer to array1 (Numbers). When finished you can use the sorted indexes to reorder array1 and array2 (Names).
One could also write their own sort algorithm that performs swaps on the extra array at the same time.
Or one could trick std::sort into sorting both arrays simultaneously by using a cleverly designed proxy. I will demonstrate that such a thing is possible, although the code below may be considered a simple hackish proof of concept.
Tricking std::sort with a cleverly-designed proxy
#include <iostream>
#include <algorithm>
constexpr size_t SZ = 2;
int Numbers[SZ] = {5, 2};
std::string Names[SZ] = {"Jeremy", "Samantha"};
int tempNumber;
std::string tempName;
class aproxy {
public:
const size_t index = 0;
const bool isTemp = false;
aproxy(size_t i) : index(i) {}
aproxy() = delete;
aproxy(const aproxy& b) : isTemp(true)
{
tempName = Names[b.index];
tempNumber = Numbers[b.index];
}
void operator=(const aproxy& b) {
if(b.isTemp) {
Names[index] = tempName;
Numbers[index] = tempNumber;
} else {
Names[index] = Names[b.index];
Numbers[index] = Numbers[b.index];
}
}
bool operator<(const aproxy& other) {
return Numbers[index] < Numbers[other.index];
}
};
int main() {
aproxy toSort[SZ] = {0, 1};
std::sort(toSort, toSort+SZ);
for(int i=0; i<SZ; ++i) {
std::cout << "Numbers[" << i << "]=" << Numbers[i] << std::endl;
std::cout << "Names[" << i << "]=" << Names[i] << std::endl;
}
return 0;
}
...and an even more cleverly-designed proxy could avoid entirely the need to allocate SZ "aproxy" elements.
Tricking std::sort with an "even more cleverly-designed" proxy
#include <iostream>
#include <algorithm>
class aproxy;
constexpr size_t SZ = 2;
int Numbers[SZ] = {5, 2};
std::string Names[SZ] = {"Jeremy", "Samantha"};
aproxy *tempProxyPtr = nullptr;
int tempNumber;
std::string tempName;
class aproxy {
public:
size_t index() const
{
return (this - reinterpret_cast<aproxy*>(Numbers));
}
bool isTemp() const
{
return (this == tempProxyPtr);
}
~aproxy()
{
if(isTemp()) tempProxyPtr = nullptr;
}
aproxy() {}
aproxy(const aproxy& b)
{
tempProxyPtr = this;
tempName = Names[b.index()];
tempNumber = Numbers[b.index()];
}
void operator=(const aproxy& b) {
if(b.isTemp()) {
Names[index()] = tempName;
Numbers[index()] = tempNumber;
} else {
Names[index()] = Names[b.index()];
Numbers[index()] = Numbers[b.index()];
}
}
bool operator<(const aproxy& other) {
return Numbers[index()] < Numbers[other.index()];
}
};
int main() {
aproxy* toSort = reinterpret_cast<aproxy*>(Numbers);
std::sort(toSort, toSort+SZ);
for(int i=0; i<SZ; ++i) {
std::cout << "Numbers[" << i << "]=" << Numbers[i] << std::endl;
std::cout << "Names[" << i << "]=" << Names[i] << std::endl;
}
return 0;
}
Disclaimer: although my final example above may technically be in violation of the strict-aliasing rule (due to accessing the same space in memory as two different types), the underlying memory is only used for addressing space-- not modified-- and it does seems to work fine when I tested it. Also it relies entirely on std::sort being written in a certain way: using a single temp variable initialized via copy construction, single-threaded, etc. Putting together all these assumptions it may be a convenient trick but not very portable so use at your own risk.
I have two arrays of data type double - called array1[10] and array2[8]. I am required to search for array2 inside array1 at each element using a linear search function. The function declaration is
string linSearch (double array1[10], double array2[8]);
If array2 is found inside array1 then I need to print out the index of where it is found in array1. If its not found I need the output to be "NA". This output must be a delimited-comma- string.
eg.
//given the two arrays:
array1={1.1,1.2,6,7,3.5,2,7,8.8,9,23.4}
array2={6,45,2,7,1.1,5,4,8.8}
//after the linear search completes, the output must be the index in which //array2 is found in array1. if its not found, then it must be NA:
2,NA,5,6,0,NA,NA,7
So far I have the code that follows. Its my first time working with arrays and I am still having difficulties grasping the concept- like once I define the function how do I even call it in the main program?! anyway..the function definition I have (excluding the main program) is:
string linSearch (double array1[10], double array2[8])
{
int index1 = 0;
int index2 =0;
int position =-1;
bool found = false;
while (index1<10 && !found && index2<8)
{
if array1[index1] == array2[index2])
{
found = true;
position = index1;
}
index1++;
index2++;
}
return position;
}
I am EXTREMELY confused about searching for one array in the other and how to output the delimited list as well as how to connect it to my main program. Any help would be GREATLY appreciated. Thanks!
#include <iostream>
using namespace std;
string linSearch(double array1[10], double array2[8])
{
string result = "";
bool found;
for (int j = 0; j < 8; j++)
{
if(j > 0)
result.append(", ");
found = false;
for (int i = 0; i < 10; i++){
if (array1[i] == array2[j]) {
result.append(to_string(i));
found = true;
}
}
if(!found)
result.append("NA");
}
return result;
}
int main(){
double a1[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
double a2[8] = {11, 25, 3, 41, 5, 6, 7, 8};
cout << linSearch(a1, a2) << endl;
return 0;
}
You are not searching one array inside the other. You are searching for elements from one array in a second array. If you are using a linear search and if you do not want to sort the array, you need 2 nested loops to do that. One for each element in the second array, and one to find that element in the first array.
Keep things simple and start with finding the position of a single element in one array. Because you are comparing doubles, you should not compare them with ==. Next you just need a function that calls the first for each element in the second array:
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
void index_to_string(const std::vector<double>& v,double e,std::ostream& out){
auto it = std::find_if(v.begin(),
v.end(),
[e](const double& x) {
return std::abs(e-x) < 1e-8;
}
);
if (it == v.end()) {
out << "NA";
} else {
out << (it - v.begin());
}
}
void all_indices_to_string(const std::vector<double>& v1,const std::vector<double>& v2,std::ostream& out){
if (v1.size() == 0 || v2.size()==0) return;
index_to_string(v1,v2[0],out);
for (size_t i=1;i<v2.size();++i){
out << ",";
index_to_string(v1,v2[i],out);
}
}
int main() {
double array1[] ={1.1,1.2,6,7,3.5,2,7,8.8,9,23.4};
double array2[] ={6,45,2,7,1.1,5,4,8.8};
all_indices_to_string(
std::vector<double>(std::begin(array1),std::end(array1)),
std::vector<double>(std::begin(array2),std::end(array2)),
std::cout
);
}
Output:
2,NA,5,3,0,NA,NA,7
In your example of arrays and the expected output
//given the two arrays:
array1={1.1,1.2,6,7,3.5,2,7,8.8,9,23.4}
array2={6,45,2,7,1.1,5,4,8.8}
and
2,NA,5,6,0,NA,NA,7
^
there is a typo. The output should be
2,NA,5,3,0,NA,NA,7
^
because the number 7 is found in the third position of the array array1.
Here you are.
#include <iostream>
#include <string>
#include <sstream>
std::string linearSearch( const double a1[], size_t n1, const double a2[], size_t n2 )
{
std::ostringstream os;
for ( size_t i = 0; i < n2; i++ )
{
if ( i != 0 ) os << ',';
size_t j = 0;
while ( j < n1 && a2[i] != a1[j] ) ++j;
if ( j == n1 ) os << "NA";
else os << j;
}
return os.str();
}
int main()
{
double a1[] = { 1.1, 1.2, 6, 7, 3.5, 2, 7, 8.8, 9, 23.4 };
const size_t N1 = sizeof( a1 ) / sizeof( *a1 );
double a2[] = { 6, 45, 2, 7, 1.1, 5, 4, 8.8 };
const size_t N2 = sizeof( a2 ) / sizeof( *a2 );
std::cout << linearSearch( a1, N1, a2, N2 ) << '\n';
return 0;
}
The program output is
2,NA,5,3,0,NA,NA,7
I had a quick question with regard to arrays in c++.
Let's say that for the program I wanted to store a specific value for each of the individual subscript components of the array. I wanted to create a function to do it and the problem here is I want a way of storing the individual values and remembering it. Since a local variable in a function will get its memory erased, I know we need to employ a static variable but I don't know how to do it.
Thanks
Varun G.
Let's say I have the function
int calculate(int array[], int size)
{
int i;
for(i=0; i<10; i++)
{
array[i]=0;
}
if(size >= 0 && size <=9)
{
array[size] = array[size]+1;
}
}
Here I want to basically create the array with the 10 numbers all being 0 and then if it falls in the range between 0 and 9 I want to add 1 to the specific position I want to also remember the position and the value so I can repeat it next time
For example if I enter 9 2 times I will get the array[size] to be 1 when I want it to be 2
Do you mean like this?
#include <iostream>
int f(int i) {
static const int data[8] = { 1, 1, 2, 3, 5, 8, 13, 21 };
return data[i];
}
int main() {
std::cout << f(4) << std::endl;
return 0;
}
#include <iostream>
#include <cstdlib>
#include <ctime>
void init( int a[], size_t n )
{
std::srand( ( unsigned int )std::time( 0 ) );
for ( size_t i = 0; i < n; i++ ) a[i] = std::rand() % n;
}
int main()
{
const size_t N = 10;
int a[N];
init( a, N );
for ( int x : a ) std::cout << x << ' ';
std::cout << std::endl;
}
Another way
#include <iostream>
#include <array>
void init( std::array<int, 10> &a )
{
a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
}
int main()
{
std::array<int, 10> a;
init( a );
for ( int x : a ) std::cout << x << ' ';
std::cout << std::endl;
}
If the size of the array has to be changed inside the function then it is better to use class std::vector instead of the array
I think you are looking for something along these lines:
int calculate( int size )
{
static int a[10] = { 0 };
if ( size >= 0 && size < 10 )
{
++a[size];
return a[size];
}
return -1;
}
The array will only be initialized once and will preserve its values between calls.
I have a matrix of values (stored as an array of values) and a vector with the matrix dimensions( dims[d0, d1, d2]).
I need to build a string like that:
"matA(j, k, l) = x;"
where j, k, l are the indices of the matrix and x the value of the element. I need to write this for each value of the matrix and for matrices with 2 to n dimensions.
I have a problem isolating the base case and replicating it in a useful way. I did a version in a switch case with a case for each dimension and a number of for cycles equal to the number of dimensions:
for (unsigned int k=1; k<=(dims[2]); k++)
{
for (unsigned int j=1; j<=(dims[1]); j++)
{
for (unsigned int i=1; i<=(dims[0]); i++)
{
strs << matName << "(" << i << "," << j << ","<< k << ")="<< tmp[t]<< "; ";
....
but is not what I wanted.. Any idea for a more general case with a variable number of dimensions?
You need a separate worker function to recursively generate the series of indices and main function which operates on it.
For example something like
void worker(stringstream& strs, int[] dims, int dims_size, int step) {
if (step < dims_size) {
... // Add dims[step] to stringstream. Another if may be necessary for
... // whether include `,` or not
worker(strs, dims, dims_size, step + 1);
} else {
... // Add cell value to stringstream.
}
}
string create_matrix_string(int[] dims, int dims_size, int* matrix) {
... // Create stringstream, etc.
strs << ... // Add matrix name etc.
worker(strs, dims, dims_size, 0);
strs << ... // Add ending `;` etc.
}
The main problem here is the value, since the dimension is not known during compilation. You can avoid that by encoding matrix in single-dimensional table (well, that's what C++ is doing anyway for static multidimensional tables) and call it using manually computed index, eg. i + i * j (for two-dimensional table). You can do it, again, by passing an accumulated value recursively and using it in final step (which I omitted in example above). And you probably have to pass two of them (running sum of polynomial components, and the i * j * k * ... * x product for indices from steps done so far.
So, the code above is far from completion (and cleanliness), but I hope the idea is clear.
You can solve this, by doing i, j and k in a container of the size of dim[] - sample:
#include <iostream>
#include <vector>
template< typename Itr >
bool increment( std::vector< int >& ijk, Itr idim, int start )
{
for( auto i = begin(ijk); i != end(ijk); ++i, ++idim )
{
if( ++*i <= *idim )
return true;
*i = start;
}
return false;
}
int main()
{
using namespace std;
int dim[] = { 5, 7, 2, 3 };
const int start = 1;
vector< int > ijk( sizeof(dim)/sizeof(*dim), start );
for( bool inc_done = true; inc_done
; inc_done = increment( ijk, begin(dim), start ) )
{
// .. here make what you want to make with ijk
cout << "(";
bool first = true;
for( auto j = begin(ijk); j != end(ijk); ++j )
{
if( !first )
cout << ",";
else
first = false;
cout << *j;
}
cout << ")= tmp[t] " << endl;
}
return 0;
}
I have a program that looks like the following:
double[4][4] startMatrix;
double[4][4] inverseMatrix;
initialize(startMatrix) //this puts the information I want in startMatrix
I now want to calculate the inverse of startMatrix and put it into inverseMatrix. I have a library function for this purpose whose prototype is the following:
void MatrixInversion(double** A, int order, double** B)
that takes the inverse of A and puts it in B. The problem is that I need to know how to convert the double[4][4] into a double** to give to the function. I've tried just doing it the "obvious way":
MatrixInversion((double**)startMatrix, 4, (double**)inverseMatrix))
but that doesn't seem to work. Is that actually the right way to do it?
No, there's no right way to do specifically that. A double[4][4] array is not convertible to a double ** pointer. These are two alternative, incompatible ways to implement a 2D array. Something needs to be changed: either the function's interface, or the structure of the array passed as an argument.
The simplest way to do the latter, i.e. to make your existing double[4][4] array compatible with the function, is to create temporary "index" arrays of type double *[4] pointing to the beginnings of each row in each matrix
double *startRows[4] = { startMatrix[0], startMatrix[1], startMatrix[2] , startMatrix[3] };
double *inverseRows[4] = { /* same thing here */ };
and pass these "index" arrays instead
MatrixInversion(startRows, 4, inverseRows);
Once the function finished working, you can forget about the startRows and inverseRows arrays, since the result will be placed into your original inverseMatrix array correctly.
For given reason that two-dimensional array (one contiguous block of memory) and an array of pointers (not contiguous) are very different things, you can't pass a two-dimensional array to a function working with pointer-to-pointer.
One thing you could do: templates. Make the size of the second dimension a template parameter.
#include <iostream>
template <unsigned N>
void print(double a[][N], unsigned order)
{
for (unsigned y = 0; y < order; ++y) {
for (unsigned x = 0; x < N; ++x) {
std::cout << a[y][x] << ' ';
}
std::cout << '\n';
}
}
int main()
{
double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}};
print(arr, 3);
}
Another, a bit clumsier way might be to make the function accept a pointer to a single-dimensional array, and both width and height given as arguments, and calculate the indexes into a two-dimensional representation yourself.
#include <iostream>
void print(double *a, unsigned height, unsigned width)
{
for (unsigned y = 0; y < height; ++y) {
for (unsigned x = 0; x < width; ++x) {
std::cout << a[y * width + x] << ' ';
}
std::cout << '\n';
}
}
int main()
{
double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}};
print(&arr[0][0], 3, 3);
}
Naturally, a matrix is something that deserves a class of its own (but the above might still be relevant, if you need to write helper functions).
Since you are using C++, the proper way to do something like this would be with a custom class and some templates. The following example is rather rough, but it gets the basic point across.
#include <iostream>
using namespace std;
template <int matrix_size>
class SquareMatrix
{
public:
int size(void) { return matrix_size; }
double array[matrix_size][matrix_size];
void copyInverse(const SquareMatrix<matrix_size> & src);
void print(void);
};
template <int matrix_size>
void SquareMatrix<matrix_size>::copyInverse(const SquareMatrix<matrix_size> & src)
{
int inv_x;
int inv_y;
for (int x = 0; x < matrix_size; x++)
{
inv_x = matrix_size - 1 - x;
for (int y = 0; y < matrix_size; y++)
{
inv_y = matrix_size - 1 - y;
array[x][y] = src.array[inv_x][inv_y];
}
}
}
template <int matrix_size>
void SquareMatrix<matrix_size>::print(void)
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
cout << array[x][y] << " ";
}
cout << endl;
}
}
template <int matrix_size>
void Initialize(SquareMatrix<matrix_size> & matrix);
int main(int argc, char * argList[])
{
SquareMatrix<4> startMatrix;
SquareMatrix<4> inverseMatrix;
Initialize(startMatrix);
inverseMatrix.copyInverse(startMatrix);
cout << "Start:" << endl;
startMatrix.print();
cout << "Inverse:" << endl;
inverseMatrix.print();
return 0;
}
template <int matrix_size>
void Initialize(SquareMatrix<matrix_size> & matrix)
{
for (int x = 0; x < matrix_size; x++)
{
for (int y = 0; y < matrix_size; y++)
{
matrix.array[x][y] = (x+1)*10+(y+1);
}
}
}
Two dimensional array is not a pointer to pointer or something similar. The correct type for you startMatrix is double (*)[4]. For your function, the signature should be like:
MatrixInversion( double (*A)[4], int order, double (*B)[4] );
There is a solution using the pointer to point by bobobobo
William Sherif (bobobobo) used the C version and I just want to show C++ version of bobobobo's answer.
int numRows = 16 ;
int numCols = 5 ;
int **a ;
a = new int*[ numRows* sizeof(int*) ];
for( int row = 0 ; row < numRows ; row++ )
{
a[row] = new int[ numCols*sizeof(int) ];
}
The rest of code is the same with bobobobo's.
You can definitely do something like the code below, if you want.
template <typename T, int n>
class MatrixP
{
public:
MatrixP operator()(T array[][n])
{
for (auto i = 0; i < n; ++i) {
v_[i] = &array[i][0];
}
return *this;
}
operator T**()
{
return v_;
}
private:
T* v_[n] = {};
};
void foo(int** pp, int m, int n)
{
for (auto i = 0; i < m; ++i) {
for (auto j = 0; j < n; ++j) {
std::cout << pp[i][j] << std::endl;
}
}
}
int main(int argc, char** argv)
{
int array[2][2] = { { 1, 2 }, { 3, 4 } };
auto pa = MatrixP<int, 2>()(array);
foo(pa, 2, 2);
}
The problem is that a two-dimensional array is not the same as an array of pointers. A two-dimensional array stores the elements one row after another — so, when you pass such an array around, only a pointer to the start is given. The receiving function can work out how to find any element of the array, but only if it knows the length of each row.
So, your receiving function should be declared as void MatrixInversion(double A[4][], int order, double B[4][]).
by nice coding if c++:
struct matrix {
double m[4][4];
};
matrix startMatrix;
matrix inverseMatrix;
so the interface would be
void MatrixInversion(matrix &A, int order, matrix &B);
and use it
MatrixInversion(startMatrix, 4, inverseMatrix);
The benefit
the interface is very simple and clear.
once need to modify "m" of matrix internally, you don't need to update the interface.
Or this way
struct matrix {
void Inversion(matrix &inv, int order) {...}
protected:
double m[4][4];
};
matrix startMatrix;
matrix inverseMatrix;
...
An ugly way in c
void MatrixInversion(void *A, int order, void *B);
MatrixInversion((void*)startMatrix, 4, (void*)inverseMatrix);
EDIT: reference code for MatrixInversion which will not crash:
void MatrixInversion(void *A, int order, void *B)
{
double _a[4][4];
double _b[4][4];
memcpy(_a, A, sizeof _a);
memcpy(_b, B, sizeof _b);
// processing data here
// copy back after done
memcpy(B, _b, sizeof _b);
}