Using multi-dimensional array to print a magic square

F

Felipe Ribeiro

Hi everybody.

So, I'm reading KN King's book to learn C by myself and came across a
problem in the chapter about arrays that asks me to write a program
that prints a "size x size" magic square. The user specifies the value
of "size". The algorithm is the following:
Start placing the number 1 in the middle of row 0. Place each of the
remaing numbers 2, 3, ..., n2 by moving up one row and over one
column. In case a number attempts to go outside the array the program
should "wrap around" to the opposite side. If a number attempts to be
stored in an element already occupied, the number goes directly below
the previously stored number.

Here's what I wrote:
----------------------------------------------------------------------------------------------------------
#include <stdio.h>

#define true 1
#define false 0
#define ARRAY_SIZE 99

typedef int bool;

int main(void)
{
int i, j, size, n = 1, magic_sqr[ARRAY_SIZE][ARRAY_SIZE];
bool vacant[ARRAY_SIZE][ARRAY_SIZE];

printf("This program creates a magic square of a specified size.\n");
printf("The size must be an odd number between 1 and 99.\n");
printf("Enter size of magic square: ");
scanf("%d", &size);

for (i = 0; i < size; i++)
for (j = 0; j < size; j++)
vacant[j] = true;

for (i = 0, j = size / 2; n <= size * size; n++) {
magic_sqr[j] = n;
vacant[j] = false;
if ((i - 1 >= 0) && (j + 1 < size)) {
if (vacant[i - 1][j + 1]) {
i--;
j++;
} else {
i++;
}
} else {
if ((i - 1) == -1 && (j + 1) == size) {
if (vacant[size - 1][0]) {
i = size - 1;
j = 0;
} else {
i++;
}
} else {
if ((j + 1) == size) {
if (vacant[i - 1][0]) {
j = 0;
i--;
} else {
i++;
}
}
if ((i - 1) == -1) {
if (vacant[size - 1][j + 1]) {
i = size - 1;
j++;
} else {
i++;
}
}
}
}
}

for (i = 0; i < size; i++) {
for (j = 0; j < size; j++)
printf("%4d", magic_sqr[j]);
printf("\n");
}

return 0;
}
----------------------------------------------------------------------------------------------------------
When the user enters 5, the program should print
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
but it doesn't. It prints
0 23 1 8 15
22 5 7 14 16
4 6 13 19 21
10 12 18 20 3
11 17 24 2 9.

I've noticed that whenever the program has to go to element [0][0] it
fails. I've been looking into the code for some good time but coudn't
understand what's been happening. The condition that treats the 17th
number is the same that treats the 10th, for example, and it works
wonders for the latter.

If somebody could give me a hand I'd be really thankful. :)
 
M

mark.bluemel

Hi everybody.

So, I'm reading KN King's book to learn C by myself and came across a
problem in the chapter about arrays that asks me to write a program
that prints a "size x size" magic square. The user specifies the value
of "size". The algorithm is the following:
Start placing the number 1 in the middle of row 0. Place each of the
remaing numbers 2, 3, ..., n2 by moving up one row and over one
column. In case a number attempts to go outside the array the program
should "wrap around" to the opposite side. If a number attempts to be
stored in an element already occupied, the number goes directly below
the previously stored number.

Here's what I wrote:

----------------------------------------------------------------------------------------------------------
#include <stdio.h>

#define true 1
#define false 0
#define ARRAY_SIZE 99

typedef int bool;

int main(void)
{
        int i, j, size, n = 1, magic_sqr[ARRAY_SIZE][ARRAY_SIZE];
[snip]

I've noticed that whenever the program has to go to element [0][0] it
fails. I've been looking into the code for some good time but coudn't
understand what's been happening. The condition that treats the 17th
number is the same that treats the 10th, for example, and it works
wonders for the latter.

If somebody could give me a hand I'd be really thankful. :)

I haven't spent much time analysing your code, but I'd make a few
comments.

Solving this is probably easier if you think of two sets of
coordinates - the current cell and the next cell.

Don't use i and j as names, use something like "cur_row, cur_col" and
"new_row, new_col".

You can then simply follow the first rule to calculate your new_row
from your cur_row and your new_col from your cur_col (the "%" operator
probably helps).

If the cell at [new_row][new_col] is not vacant, then switch to the
second rule.

Finish up by updating cur_row and cur_col.

(Aside: In my quick solution, I didn't use a separate array of flags.
I thought it was simply to initialise my array to all zero and check
for zero in a cell).
 
F

Felipe Ribeiro

I know King doesn't advise about this, but when you issue a prompt
to the user that doesn't end in a newline character ('\n'), it's a
good idea to call fflush(stdout); This is because stdout in such
an interactive case may be line-buffered, meaning the output
may not appear until a newline character is encountered. A call
to fflush(stdout); will flush the stdout buffer before a newline
character is encountered. (The complete details aren't worth
bothering with at this stage.)

I hadn't heard about it. Thank you for the advice.
                              if ((j + 1) == size) {
                                       if (vacant[i - 1][0]) {
                                               j = 0;
                                               i--;
                                       } else {
                                               i++;
                                       }
                               }
                               if ((i - 1) == -1) {
                                       if (vacant[size - 1][j + 1]) {
                                               i = size - 1;
                                               j++;
                                       } else {
                                               i++;
                                       }
                               }

Place an `else' before the third `if', i.e.,

    else if ((i - 1) == -1) {

and you'll get the desired output.

How reckless of me! I wish I could've spotted this error. :)
What's happening is that the number 16 is getting written when
i == 1 and j == 4. Since (j + 1) == size, the first `if' is
true, the check on `vacant' succeeds, `j' gets set to 0,
and `i' gets set to 0. So at this point we have i == 0 and
j == 0, which is where you want 17 to be written. But then
in the third `if' the test (i - 1) == -1 succeeds, the fourth
`if' succeeds, and you end up with i == 4 and j == 1.

If any of this is unclear, let me know.

It couldn't be any clearer! Thanks a lot!
 
C

CBFalconer

Felipe said:
Han from China said:
I know King doesn't advise about this, but when you issue a prompt
to the user that doesn't end in a newline character ('\n'), it's a
good idea to call fflush(stdout); This is because stdout in such
an interactive case may be line-buffered, meaning the output
may not appear until a newline character is encountered. A call
to fflush(stdout); will flush the stdout buffer before a newline
character is encountered. (The complete details aren't worth
bothering with at this stage.)

I hadn't heard about it. Thank you for the advice.
if ((j + 1) == size) {
if (vacant[i - 1][0]) {
j = 0;
i--;
} else {
i++;
}
}
if ((i - 1) == -1) {
if (vacant[size - 1][j + 1]) {
i = size - 1;
j++;
} else {
i++;
}
}

Place an `else' before the third `if', i.e.,

else if ((i - 1) == -1) {

and you'll get the desired output.

How reckless of me! I wish I could've spotted this error. :)
....

Amazing. Han has actually given out accurate advice. If he keeps
this up he might get off some PLONK lists.
 
K

Keith Thompson

CBFalconer said:
Amazing. Han has actually given out accurate advice. If he keeps
this up he might get off some PLONK lists.

I think he actually gives accurate advice fairly often (though I
rarely read anything he writes, so I can't be sure). That's certainly
not enough to get him out of my killfile, but of course you can do as
you like.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top