views:

288

answers:

7

this is a magic square generator, but do not know C++, I have some difficulties to convert this code:

#include <vector>
#include <iostream>
using namespace std;
//There two series will be on even in case of magic square
// One of even order will be for multiple of 4
void BuildDoublyEvenMagicSquare(vector<vector<int> > &mat, int Order);
//Other of even order will be for multiple of 2
void SinglyEvenMagicSquare(vector<vector<int> > &mat, int order);
// For odd order
void BuildOddMagicSquare(vector<vector<int> > &mat, int Order);

// For odd order
void BuildOddMagicSquare(vector<vector<int> > &mat, int Order)
{
  int SqrOfOrder = Order * Order;
  int start=0, mid=Order/2;     // start position
  for (int loop=1; loop<=SqrOfOrder; ++loop)
  {
    mat[start--][mid++] = loop;
    if (loop % Order == 0)
    {
      start += 2;
      --mid;
    }
    else
    {
      if (mid==Order)
        mid -= Order;
      else if (start<0)
        start += Order;
    }
  }
}

void BuildDoublyEvenMagicSquare(vector<vector<int> > &mat, int Order)
{
  vector<vector<int> > A(Order, vector<int> (Order, 0));
  vector<vector<int> > B(Order, vector<int> (Order, 0));
  int i, j;
  //Building of matrixes I and  J
  int index=1;
  for (i=0; i<Order; i++)
    for (j=0; j<Order; j++)
    {
      A[i][j]=((i+1)%4)/2;
      B[j][i]=((i+1)%4)/2;
      mat[i][j]=index;
      index++;
    }
  for (i=0; i<Order; i++)
    for (j=0; j<Order; j++)
    {
      if (A[i][j]==B[i][j])
        mat[i][j]=Order*Order+1-mat[i][j];
    }
}

void BuildSinglyEvenMagicSquare(vector<vector<int> > &mat, int order)
{
  int ho=order/2;

  vector<vector<int> > C(ho, vector<int> (ho, 0));

   // For Order is Odd
    if (order%2==1)
      BuildOddMagicSquare(C, order);

   // For Order is Even
   else
   {
    //For Order is Doubly Even Order
    if (order % 4==0)
      BuildDoublyEvenMagicSquare(C, order);
     //For Order is Singly Even Order
    else
      BuildSinglyEvenMagicSquare(C, order);
   }
  int i, j, k;
  for (i=0; i<ho; i++)
    for (j=0; j<ho; j++)
    {
      mat[i][j]=C[i][j];
      mat[i+ho][j]=C[i][j]+3*ho*ho;
      mat[i][j+ho]=C[i][j]+2*ho*ho;
      mat[i+ho][j+ho]=C[i][j]+ho*ho;
    }
  if (order==2)
    return;

  vector<int> A(ho, 0);
  vector<int> B;

  for (i=0; i<ho; i++)
    A[i]=i+1;

  k=(order-2)/4;
  for (i=1; i<=k; i++)
    B.push_back(i);

  for (i=order-k+2; i<=order; i++)
    B.push_back(i);

  int temp;
  for (i=1; i<=ho; i++)
    for (j=1; j<=B.size(); j++)
    {
      temp=mat[i-1][B[j-1]-1];
      mat[i-1][B[j-1]-1]=mat[i+ho-1][B[j-1]-1];
      mat[i+ho-1][B[j-1]-1]=temp;
    }
  i=k;
  j=0;
  temp=mat[i][j]; mat[i][j]=mat[i+ho][j]; mat[i+ho][j]=temp;
  j=i;
  temp=mat[i+ho][j]; mat[i+ho][j]=mat[i][j]; mat[i][j]=temp;
}

int main()
{
  int Order;
  cout<<"Enter the order of square which you wanna: ";
  cin>>Order;
  vector<vector<int> > mat(Order, vector<int> (Order, 0));

  // For order less than 3 is meaningless so printing error
  if (Order<3)
  {
    cout<<" Order Of Square must be greater than 2";
    return -1;
  }

   // For Order is Odd
    if (Order%2==1)
      BuildOddMagicSquare(mat, Order);

   // For Order is Even
   else
   {
    //For Order is Doubly Even Order
    if (Order % 4==0)
      BuildDoublyEvenMagicSquare(mat, Order);
     //For Order is Singly Even Order
    else
      BuildSinglyEvenMagicSquare(mat, Order);
   }


  // Display Results

  for (int i=0; i<Order; i++)
  {
    for (int j=0; j<Order; j++)
    {
      cout<< mat[i][j]<<"  " ;
    }
    cout<<endl;
  }
  return 0;
}

for example, how can I write this function call in C?

void BuildDoublyEvenMagicSquare(vector<vector<int> > &mat, int Order);

and what vector<vector<int> > &mat means?

@Omnifarious

can i use something like this?

 int **mat:
*mat = (int **)malloc(sizeof(int*)*Order);
for (int i=0;i<Order;i++)
mat[i] = (int *)malloc(sizeof(int)*Order);
+2  A: 

I'll just answer the last part of the question.

vector is a container in the C++ standard library. It's like an array that can automatically resize itself when it gets full.

A vector<vector<int> > is a vector containing vector objects, and the latter holds int.

A vector<vector<int> >& is a reference to same. A reference is like a pointer, except that you do not use * to access the actual contents. So you treat mat "as if" it's a vector object directly, except that it's really aliased to another instance, so any changes you make to it will "reflect back" and affect what the caller can see.

Simple example of references:

void add1(int& n) {
    ++n;
}

int main() {
    int num = 5;
    add1(num);
    // num is 6 here
}
Chris Jester-Young
A: 

A C++ vector is like a C array. It adds some nice features, like optional bounds checking, automatic reallocation when it needs its size increased, and so on.

A vector<int> is roughly analogous to an int[].

A vector<vector<int> > is like an int*[], where each int* points to an array. It's not like a two-dimensional array - each of the inner vectors can have different sizes.

Prefixing a variable with an & makes that variable a reference. A reference is like a pointer that you don't have to explicitly dereference. Passing parameters by reference is a common C++ idiom, which is used in many of the same situations as passing by pointer in C.

Daniel Yankowsky
A: 

vector is an array which is resized automatically. So vector<vector<int>> would be an array of int-arrays, equivalent to the C int*[]. &mat is a reference to a mat, similiar to pointers (in fact I think C99 supports references). However, in this case since the value being passed in is already a pointer, it is not really needed.

So the equivalent in C would be

void BuildDoublyEvenMagicSquare(int*[] mat, int Order); 
BlueRaja - Danny Pflughoeft
In C++98, you have to write a space between the `>>`, or else there's a parse error. In C++0x, the space is optional.
Chris Jester-Young
+2  A: 

For the last part of the question, in C that function prototype would look like this if you follow the rest of my advice:

void BuildDoublyEvenMagicSquare(int *mat, int Order);

There are actually several ways you could do it. There are some things being done here that simply can't be done in C, so you'll have to sort of go for a slightly different approach. The biggest thing is the C++ vector's. A C++ vector is like a C array, but it does all the memory management for you. This means, for example, that it's fairly convenient to have an array of arrays where in C it would just add to your resource management headache.

The C++ declaration:

vector<int> varname(5);

is roughly equivalent to the C declaration:

int varname[5];

But in C++ you can do this:

int randominteger = 7;
vector<int> varname(randominteger);

and in C this is illegal unless you have a C99 compliant compiler (-std=c99 in gcc):

int randominteger = 7;
int varname[randominteger];

You can't have arrays with variable numbers of elements in C, so you have to resort to calloc or malloc and do your own memory management, like this:

/* Not that this is not necessary and shouldn't be done (as it's *
 * prone to memory leaks) if you have a C99 compliant compiler.  */

int randominteger = 7;
int *varname = calloc(randominteger, sizeof(int));
if (varname == NULL) {
   /* Die horribly of running out of memory. */
}

In this case, I'm assuming that you're going to unfold your array of arrays into a single long C array of integers large enough to hold the answer so you can reduce the number of bits of memory you have to manage. To accomplish this, I would use a call like mat = calloc(order * order, sizeof(int)); in main, which also means you'll have to call free(mat) when you're finished with it at the end of main.

I'm also assuming that you're unfolding the array so that you no longer have an array of arrays. That means you'll have to be doing some math to turn a row,column index into a linear index into the array. Something like row * order + column.

You'll have to repeat the procedure I suggested for main in each of the functions that build a magic square because they each create temporary arrays to hold stuff in that go away at the end of the function.

Omnifarious
I thought C99 added support for arrays whose length is determined at run-time?
Bill
@Bill, you're right! That would save a LOT of headache right there. I don't know that the OP has a C99 compliant compiler, but if (s)he does...
Omnifarious
I mostly do C++, but is it that common to find a compiler that doesn't conform to a standard adopted in early 2000?
Bill
@Bill: I've never noticed that Microsoft has ever cared much. Their compiler is the one I worry about the most.
Omnifarious
A: 

You can get rid of the #includes and the 'using namespace std' line. The only difficult bit now is your vector. What's being passed here is a two dimensional array of ints which is easy enough in C. The difficult bit is resizing it if you don't know the bounds at the outset. That's why vector is so nice - you don't need to care.

For more general C++ to C connversion I'd suggest you get a book like "C++ for C programmers" and work from the index back. Even better, work from the beginning to the end and learn C++. You'll probably find that if the program is in any way complicated, there's going to be some things which are pretty tricky to do in C from C++. Good luck!!

Robin Welch
A: 

Vector is pretty much C++ for an array. There are ways to dynamicly resize vectors (without resorting to realloc()), but otherwise that is pretty much what you are looking at.

If you see & in a parameter list, it means "pass this parameter by reference". In C parameters inside a routine are a copy of what was passed in, so if you modify them that modificaion doesn't go outside the function. However, if you modify a C++ reference parameter, you are also modifying the variable the caller used for that parameter.

So to get the equivalent of <vector<vector<int>> & mat in C, you'd probably pass that parameter as something like int ** mat[], with the assumption that the user is passing in a pointer to an array of int arrays that they want you to work on. The difference is that inside the routine your C code would have to be doing a *mat to get at the array of int arrays, whereas in the C++ code they can just use mat directly.

T.E.D.
+3  A: 

Are you restricted to building the project as a C project? If you're writing good C code (and it isn't C99), you can probably compile it as C++ with no difficulty. If you can then build it as a C++ program, you can use the function as is.

In that case, all you really need to know is that you've got vector<vector<int> > mat, and when you call your function it's got your result. Then you can put the preprocessor directive #include <vector> in your files that use it, and follow it with using std::vector, and everything will just work. In particular, you can read off the values with mat[i][j], just as you would with an array of array of int in C.

One thing to watch is that you write vector<vector<int> > rather than vector<vector<int>>, since in the latter the >> will be treated as a right-shift operator rather than angle bracket delimiters. This will be fixed in C++0x, when it comes out (the x digit is now strictly hex), and may be fixed in particular compilers.

Alternatively, write a wrapper function that takes the vector and changes it into an array of array of int. For convenience, you can find the number of elements in a vector with mat.size() or mat[i].size().

David Thornley
The wrapper function approach might also work if he's bent on keeping the rest of his program in C.
Omnifarious
@Omnifarious: Sure, compile the function he wants and the wrapper (which will be declared `extern "C"`) into a little static library and link it in. That should work fine.
David Thornley