1

As you can check this code:

#include<stdio.h>

int main(){
    int a[3][4];
    int i;
    for(i=0;i<12;i++){
        a[0][i]=12-i;
        printf("a[0][%i] = %i\n", i, a[0][i]);
    }
    return 0;
}

It properly prints number from 12 to 1. However this piece of code:

#include<stdio.h>

int main(){
    int a[3][4];
    int i;
    for(i=0;i<12;i++){
        a[i][0]=12-i;
        printf("a[%i][0] = %i\n", i, a[i][0]);
    }
    return 0;
}

It prints 12, 11, 10, 1, 2, 1. What may be the problem? I know you can print it by using 2 loops and variables, but I am trying to learn how to do it this way.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
MaranX
  • 13
  • 1
  • 6
  • "I am trying to learn how to do it this way" - just don't OK. It's not a great idea to learn to code by breaking the rules. If you want a linear<->two dimensional mapping, don't rely on 'neat tricks' that sometimes work. Code the mapping properly as per Heuster's answer. – Skizz Aug 14 '13 at 13:35
  • Trust me, I write the code like you said. However my university teacher does not, and I lost valuable points on the exam because he wrote the code in this manner. – MaranX Aug 14 '13 at 14:30
  • Maybe it should be pointed out to your teacher that this sort of thing would fail run time memory checks (like BoundsChecker) and almost certainly fail various coding standards (e.g. MISRA). I wonder if it's possible to lodge a formal complaint about him teacher bad practices? – Skizz Aug 14 '13 at 14:58

3 Answers3

3

What you are doing there is bad practice in both cases. You are just lucky that the first way works (because the 3 sub arrays of size 4 are consecutive in memory).

If you want to work with two-dimensional arrays in a one-dimensional loop, you should use the two ways of integer division: / and %:

int main(){
    int a[3][4];
    int i;
    for(i=0;i<12;i++){
        a[i/4][i%4]=12-i;
        printf("a[%i][%i] = %i\n", i/4, i%4, a[i/4][i%4]);
    }
    return 0;
}

For instance, for i = 7, we have i/4 == 1 ('divide and round down to whole number') and i%4 == 3 ('remainder after division').

Vincent van der Weele
  • 12,927
  • 1
  • 33
  • 61
0

It has to do with the way the data are stored in memory. In first case, you add them sequentially, and it has space for 3*4 = 12 elements. So you can luckily put all the elements inside, as you totally have 3*4 cells. On the second case, you are trying to put the data only on each row's first cell, but you have not indicated a space of 12, having indicated 3 rows. For more on memory in multi-dimensional arrays, look here:

How are multi-dimensional arrays formatted in memory?

Community
  • 1
  • 1
Nick Louloudakis
  • 5,856
  • 4
  • 41
  • 54
  • I understand now, so it only works for columns, but not for rows. Thank you. – MaranX Aug 14 '13 at 13:22
  • You might want to write `a[rowindex][columnindex] <--> *(&a[0][0] + rowindex*columns + columnindex)`, to replace the vague conceptual `<-->` relation by a C equality. `a` alone is not enough; you really want to have a pointer to `int` there (`(int*)a` will work too). – anatolyg Aug 14 '13 at 13:32
  • This part was not right the way I wrote it, therefore I deleted it not to confuse the asker and all others. I apologise for the inconvenience guys! – Nick Louloudakis Aug 14 '13 at 13:52
-1
+---------------------------------------------------------------------------------+
|    a[0][0]      <--a[0][1]         <--a[0][0]                                   |
|    a[0][1]      <--a[0][2]                                                      |
|    a[0][2]      <--a[0][3]                                                      |
|    a[0][3]            .                                                         |
|    a[1][0]            .            <--a[1][0]                                   |
|    a[1][1]            .                                                         |
|    a[1][2]            .                                                         |
|    a[1][3]            .                                                         |
|    a[2][0]            .            <--a[2][0]                                   |
|    a[2][1]            .                                                         |
|    a[2][2]      <--a[0][10]                                                     |
|    a[2][3]      <--a[0][11]                                                     |
|       ^               ^            <--a[3][0]  <-- already memory overflow !    |
|       |               |                .                                        |
|  array memory     Y 1th code           .                                        |
|                                  others all memory overflow!                  |
|                                                                                 |
|                                      you 2th code                               |
+---------------------------------------------------------------------------------+

So, you can usea[i/4][i%4] just make sure no memory overflow .

Let me say : of course you first code is right , I don't think it is luck.In C , a two dimensional array is always just put two one dimensional togather. However, see my downvote, It is not good to use that.

If you really need speed, you don't want the / and '%' I think you still can use cide 1th.

Lidong Guo
  • 2,817
  • 2
  • 19
  • 31
  • 1
    Using `a[0][i]` violates the rules of C when `i` exceeds the bounds of the second dimension. The fact that it sometimes works in some C implementations does not mean it will always work. Please do not advise people to use it. – Eric Postpischil Aug 14 '13 at 13:31
  • @EricPostpischil 1. if we can use `int a[2][2] = {1,2,3,4};` why we can not use the `a[0][i]` 2. I am not familiar to compiler , Is the *i it sometimes works in some C implementations does not mean it will always work* means different compilers has different way deal with it? – Lidong Guo Aug 15 '13 at 03:28
  • 1. The C language standard specifies how a list of initializers is used to provide values for a compound object, such as an array of arrays. It does not specify that out-of-bounds addressing in the last dimension can be used to access elements of a multidimensional array. An initializer list is matched to array elements at compile time; it does not involve calculating addresses in the way that subscripting does. 2. Yes, different compilers and C implementations may do various things differently. They can enforce array bounds, and some do, as a debugging feature. – Eric Postpischil Aug 15 '13 at 09:45