1

Final Edit

When debugging this code, I would see the first loop line execute n times, but the following lines would execute only once. Only later I would notice that the expected value changes, though, were in fact being made: it was just the loop line was being executed at once, as if the loop went through all iterations in one single step. From the second loop on, Pressing F10 (I use VSCode) would skip straight to the next loop, instead of skipping to the next iteration. That's how the compiler behaved (MinGW64).

Now, formatting the loops like this:

for( ; x<n; x++) {
            p[y][x] = h;
        } x--;
        for( ; y<n; y++) {
            p[y][x] = h;
        } y--;
        
etc...

did cause each iteration to be read separately: now from the second loop on, pressing F10 would just jump to the next iteration, not straight to the next loop.
Conclusion: both styles work the same, but debug differently.

Anyway, here's a version that's still pretty ugly, but now works as expected:

#include <stdio.h>
int main(){
    int n,size,sqrs,start=0,h,y,x; scanf("%i",&n);
    int p[n][n];
    size = n;
    if(n%2==0) sqrs = n/2;
    else sqrs = n/2+1;
    h = 1;
    y = start;
    x = start;
    for(int t=0; t<sqrs; t++){
        for( ; x<n; x++) p[y][x] = h; x--;
        for( ; y<n; y++) p[y][x] = h; y--;
        for( ; x>=start; x--) p[y][x] = h; x++; 
        for( ; y>=start; y--) p[y][x] = h; y++;
        y++; x++; h++; start++; n--;
    }  
    for(int i=0; i<size; i++){
        for(int j=0; j<size; j++){
            printf("%i ",p[i][j]);
        } printf("\n");
    }
}

Edit:

I'm trying to build a matrix where the numbers grow towards the center, i.e. a "pyramid". As of yet, I haven't had any problem with single-statemente one-liner for loops in C. Now, placing them consecutively is causing them, except for the first loop, to be skipped. As I see it, we have a `for` loop, then its single statement, and then a semicolon, which should (at least, I expected it to) terminate the line, then move on to the next piece of code, which just happens to be another `for` loop. The problem is the first `for` loop runs as expected, however, the following ones are just skipped, as they were at their ending condition.

I've stressed "not nested" because:

  • while searching for this issue, all I had found were about nesting loops and if statements regarding using or not braces;
  • each for loop/statement ends with a semicolon.

I've tried bracing the single statements, but it did not solve the problem.
What DID solve the problem though was adding braces AND newlines, like this:

for( ; y<n; y++) {
    p[y][x] = h;
}

But still, it bothers me to be clueless of why these were required in C, in this case. For example, while debugging I had noticed the second loop is skipped because the value of y changes from 0 to 4. This alone is already a mystery to me.

By the way, my apologies for being vague!

Original post:

Here is my code:

#include <stdio.h>
int main(){
    int n,sqrs,start=0,h,y,x; scanf("%i",&n);
    int p[n][n];

    if(n%2==0) sqrs = n/2;
    else sqrs = n/2+1;
    h = 1;
    y = start;
    x = start;
    for(int t=0; t<sqrs; t++){
        for( ; x<n; x++) p[y][x] = h; // THESE LOOPS
        for( ; y<n; y++) p[y][x] = h; // here, y changes from 0 to 4
        for( ; x>=start; x--) p[y][x] = h; 
        for( ; y>=start; y--) p[y][x] = h;
        y++; x++; h++; start++; n-=2;
    }  
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
            printf("%i",p[i][j]);
        } printf("\n");
    }
}

As you can see, these loops aren't nested. They would nest though if there weren't any statements in between them, but there are.
So, the first one iterates normally but all of the following ones don't. They just skip.
I did manage to get around this, but curiously only when I added both braces and newlines, i.e. when all loops (except the first one, which doesn't seem to require it) looked like this:

for( ; y<n; y++) {
    p[y][x] = h;
}

This remains a mystery to me. Of course, I'm sorry if this is a duplicate. I just couldn't find anything about this specifically.

EDIT: As some of you have thankfully noticed, yes, I'm trying to print a "pyramid" matrix. The reason I didn't mention it is because to me the problem was about syntax only, being the not so relevant.

101is5
  • 309
  • 2
  • 12
  • 7
    Your program has undefined behavior because it accesses the array out of bounds in `for (; y < n; y++) p[y][x] = h;` - Make it `for (; y < n; y++) { printf("%d,%d\n", y, x); fflush(stdout); p[y][x] = h; }` and you'll see for yourself. Are you using `gcc` or `clang`? If you are, add the compiler options `-g -fsanitize=address,undefined` and it will tell you about problems like this when you run the program. [Demo](https://godbolt.org/z/q5Ma83719) – Ted Lyngmo Sep 27 '22 at 19:31
  • 2
    "As you can see, these loops aren't nested." is unclear as `for( ; x – chux - Reinstate Monica Sep 27 '22 at 19:37
  • 1
    This code should not pass any code review. The coding style is very unclear and inviting of mistakes. – Cheatah Sep 27 '22 at 19:57
  • 1
    It's not clear what you mean. Are you looking for something like `for( ; x – William Pursell Sep 27 '22 at 22:15
  • 1
    @AdrianMole "assign the same value of h to elements in the p array" --> No. 2nd loop's `p[y][x] = h;` eventually assigns outside the array - UB. – chux - Reinstate Monica Sep 28 '22 at 00:53
  • @TedLyngmo Thanks! I'm using MinGW64 – 101is5 Sep 28 '22 at 10:32
  • @chux-ReinstateMonica You're right. I meant the 4 loops inside that one weren't nested – 101is5 Sep 28 '22 at 10:33
  • @WilliamPursell It's actually what I'm not looking for – 101is5 Sep 28 '22 at 10:33
  • 1
    @chux I think I get my rookie mistake: when moving on to the next loop, y had been incremented, therefore I'm now out of bound. I wanted to start the next loop where I've left off at the previous one. – 101is5 Sep 28 '22 at 10:36
  • @chux just an update: (keeping the code as is) decrementing x between the first and the second loop won't stop the issue: the second loop still causes ```y``` to increment from ```0``` straight to ```4```, ending itself ("skipping"). – 101is5 Sep 28 '22 at 11:13
  • @101is5 That is likely due to some code accessing `p[y][x]` out of bounds. – chux - Reinstate Monica Sep 28 '22 at 11:28

3 Answers3

2

There are multiple mistakes in your code:

  • you should undo the last increment/decrement after each of the inner loops. As coded, you store h beyond the end of the array p.
  • n should be decremented only by 1
  • since n is modified, the final loops have no effect.

Here is a modified version, keeping your corny style:

#include <stdio.h>
int main(){
    int n,sqrs,start=0,end,h,y,x; scanf("%i",&n);
    int p[n][n];

    if(n%2==0) sqrs = n/2;
    else sqrs = n/2+1;
    h = 1;
    y = start;
    x = start;
    end = n;
    for(int t=0; t<sqrs; t++){
        for( ; x<end; x++) p[y][x] = h; x--;
        for( ; y<end; y++) p[y][x] = h; y--;
        for( ; x>=start; x--) p[y][x] = h; x++;
        for( ; y>=start; y--) p[y][x] = h; y++;
        y++; x++; h++; start++; end--;
    }
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
            printf("%i",p[i][j]);
        } printf("\n");
    }
}

This code can be simplified as:

#include <stdio.h>
int main(){
    int n; scanf("%i",&n);
    int p[n][n];
    int h=1,start=0,stop=n-1;
    for(int t=0; t<n; t+=2,h++,start++,stop--){
        int x=start,y=start; p[y][x] = h;
        while(x<stop) p[y][x++] = h;
        while(y<stop) p[y++][x] = h;
        while(x>start) p[y][x--] = h;
        while(y>start) p[y--][x] = h;
    }
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++) printf("%i",p[i][j]);
        printf("\n");
    }
}

And here is a more classic version:

#include <stdio.h>

int main() {
    int n;
    if (scanf("%i", &n) != 1 || n <= 0)
        return 1;
    int p[n][n];
    int h = 1, start = 0, stop = n - 1;
    for (int t = 0; t < n; t += 2, h++, start++, stop--) {
        int i = start, j = start;
        if (start == stop)
            p[i][j] = h;
        for (; j < stop; j++)
            p[i][j] = h;
        for (; i < stop; i++)
            p[i][j] = h;
        for (; j > start; j--)
            p[i][j] = h;
        for (; i > start; i--)
            p[i][j] = h;
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++)
            printf("%i", p[i][j]);
        printf("\n");
    }
    return 0;
}

Note that instead of tracing successive squares, you can compute the array values directly:

#include <stdio.h>

int min(int a, int b) { return a < b ? a : b; }

int main() {
    int n, i, j;
    if (scanf("%i", &n) != 1 || n <= 0)
        return 1;
    char p[n][n + 1];
    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++)
            p[i][j] = '1' + min(min(i, j), min(n - i - 1, n - j - 1));
        p[i][j] = '\n';
    }
    printf("%.*s", (int)sizeof(p), &p[0][0]);
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
2

It's not clear from either the OP code or the description what it is you are trying to achieve.

Based on another recent SO question, perhaps this is what you are seeking. This takes advantage of the symmetry of the (I believe) desired output. Four array elements are assigned in each iteration until the centre of the pattern is reached.

int main() {
    const uint8_t n = 9;
    uint8_t mat[n][n];

    for( int r = 0; r < (n+1)/2; r++ )
        for( int c = 0; c < (n+1)/2; c++ )
            mat[r    ][c    ] =
            mat[n-1-r][c    ] =
            mat[r    ][n-1-c] =
            mat[n-1-r][n-1-c] =
                1 + (c<r?c:r);

    for( int i = 0; i < n; i++ ) {
        for( int j = 0; j < n; j++ )
            printf("%d ", mat[i][j]);
        puts( "" );
    }
    return 0;
}
1 1 1 1 1 1 1 1 1
1 2 2 2 2 2 2 2 1
1 2 3 3 3 3 3 2 1
1 2 3 4 4 4 3 2 1
1 2 3 4 5 4 3 2 1
1 2 3 4 4 4 3 2 1
1 2 3 3 3 3 3 2 1
1 2 2 2 2 2 2 2 1
1 1 1 1 1 1 1 1 1

Perhaps the "not nested" is the criteria?

int main() {
    const uint8_t n = 9, h = ((n+1)/2); // 'h'alf way
    uint8_t mat[n][n];

    for( int x = 0; x < h*h; x++ ) {
        int r0 = x / h, r1 = n-1-r0; // top & bottom rows of this square
        int c0 = x % h, c1 = n-1-c0; // left & right cols of this square
        uint8_t v = 1 + ( c0 < r0 ? c0 : r0 );

        mat[r0][c0] = mat[r0][c1] =
        mat[r1][c0] = mat[r1][c1] = v;
    }
    /* same nested output loops */
    return 0;
}
Fe2O3
  • 6,077
  • 2
  • 4
  • 20
0

It appears that you are trying to make a pattern of concentric boxes in a matrix. Your logic is wrong. Following is an example using the Ada programming language. Translating that into C should be easy.

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Main is
   type matrix is array (Positive range <>, Positive range <>) of Positive;
   Side : Positive;
begin
   Put ("Enter the number of elements on a side of the array: ");
   Get (Side);
   declare
      Box    : matrix (1 .. Side, 1 .. Side);
      Center : Positive;
      Start  : Positive := 1;
      Stop   : Positive := Side;
      Value  : Positive := 1;
   begin
      Center := (if Side mod 2 = 0 then side / 2 else side / 2 + 1);
      for turn in 1 .. Center loop
         -- sides
         for I in Start .. Stop loop
            Box (Start, I) := Value;
            Box (I, Start) := Value;
            Box (Stop, I)  := Value;
            Box (I, Stop)  := Value;
         end loop;
         -- adjust for inner box values
         Start := Start + 1;
         Stop  := Stop - 1;
         Value := Value + 1;
      end loop;

      for I in Box'Range (1) loop
         for J in Box'Range (2) loop
            Put (Item => Box (I, J), Width => 1);
         end loop;
         New_Line;
      end loop;
   end;
end Main;

The output of a sample execution is:

Enter the number of elements on a side of the array: 7
1111111
1222221
1233321
1234321
1233321
1222221
1111111
Jim Rogers
  • 4,822
  • 1
  • 11
  • 24