449,407 Members | 1,045 Online
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,407 IT Pros & Developers. It's quick & easy.

Some doubts on variable-length array

 P: n/a Hello experts, I have seen following the code snippet given by Marc Boyer (with slight changes by me for a better format), and have doubts on it. I am so grateful if you can give me your kindly help and hints on this problem. 1. Does the function call `foo(3, 3, tab);' refer to the data outside the array `int tab[9];'. The available subscription for a 3X3 2-D array should be 0..2 X 0..2, I think. 2. For the available function call `foo(2, 2, tab);' (I do not think the second one is unavailable, just not sure.), which element in the array `int tab[9];' does tab[0][0] refer to inside the body of the function `foo'. I want to know the exact one int the format `tab[0] .. tab [8]'. And which element in `int tab[9];' does tab[1][1] refer to. I can not figure it out for some while on it. The GCC4.1 says it does not support the variable-length array of C99, but I can compile this program on even GCC3.3.5, and also on GCC4.1 after I installed this newest one. I also get the same result of the program as Marc Boyer. Sincerely, lovecreatesbeauty /* sample by Marc Boyer */ #include void foo(int size_x, int size_y, int tab[size_x][size_y]) { printf("tab[1][1] == %d\n", tab[1][1]); } int main() { int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; foo(2, 2, tab); foo(3, 3, tab); return 0; } news> ./a.out tab[1][1] == 3 tab[1][1] == 4 Mar 31 '06 #1
8 Replies

 P: n/a I can understand the behaviour of these statements marked `/* A. don't understand */' in following code, but do not understand the statements marked `/* B. understand */' . The behaviour of the following statements of A kind is different to B kind. Thank you. #include void foo(int size_x, int size_y, int tab[size_x][size_y]) { printf("tab[1][1] == %d\n", tab[1][1]); } int main() { /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */ int tab[3][3] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; foo(2, 2, tab); /* A. don't understand */ printf("%i\n", tab[2][2]); /* B. understand */ printf("%i\n", *(*(tab+2)+2)); /* B. understand */ printf("\n\n"); foo(3, 3, tab); /* A. don't understand */ printf("%i\n", tab[3][3]); /* B. understand */ printf("%i\n", *(*(tab+3)+3)); /* B. understand */ printf("\n\n"); return 0; } Mar 31 '06 #2

 P: n/a "lovecreatesbeauty" wrote in message news:11*********************@i39g2000cwa.googlegro ups.com...I can understand the behaviour of these statements marked `/* A. don't understand */' in following code, but do not understand the statements marked `/* B. understand */' . The behaviour of the following statements of A kind is different to B kind. Thank you. #include void foo(int size_x, int size_y, int tab[size_x][size_y]) Here foo is being told that tab is an array with dimensions [size_x][size_y]. It will assume that this is actually the case, regardless of the true size of the array passed to it in the calling function. { printf("tab[1][1] == %d\n", tab[1][1]); } if this were void foo( int **tab), foo would not know the rank of the array int main() { /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */ int tab[3][3] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; foo(2, 2, tab); /* A. don't understand */ Call function foo, and tell foo that tab is a 2x2 array printf("%i\n", tab[2][2]); /* B. understand */ printf("%i\n", *(*(tab+2)+2)); /* B. understand */ printf("\n\n"); foo(3, 3, tab); /* A. don't understand */ Call function foo, and tell foo that tab is a 3x3 array printf("%i\n", tab[3][3]); /* B. understand */ Error - index out of bounds printf("%i\n", *(*(tab+3)+3)); /* B. understand */ Error - index out of bounds printf("\n\n"); return 0; } -- Fred L. Kleinschmidt Boeing Associate Technical Fellow Technical Architect, Software Reuse Project Mar 31 '06 #3

 P: n/a On Fri, 31 Mar 2006 02:00:45 -0800, lovecreatesbeauty wrote: I can understand the behaviour of these statements marked `/* A. don't understand */' in following code, but do not understand the statements marked `/* B. understand */' . Did you mean it that way round? I've commented on both just in case. #include void foo(int size_x, int size_y, int tab[size_x][size_y]) { printf("tab[1][1] == %d\n", tab[1][1]); prints the 2nd element of the 2nd element of tab. } int main() { /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */ int tab[3][3] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; My compiler (gcc 4.0.1) warns me I should write: int tab[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}}; although it accepts the flat list as well. foo(2, 2, tab); /* A. don't understand */ This calls "lies" to foo telling it that the array is 2x2 so foo sees it as if it were "int tab[2][2] = {{0, 1}, {2, 3}};". Element [1][1] is 3 and this is what is printed. printf("%i\n", tab[2][2]); /* B. understand */ The declaration of tab is in scope here so there should be no confusion. The third element of the third element of tab is 8. printf("%i\n", *(*(tab+2)+2)); /* B. understand */ This is another way to write the same thing. The array name tab is treated as a pointer to its first element (an array of three ints). Adding 2 to this pointer (tab + 2) moves it by two "strides" to make a pointer that points to the third element (another array of three ints). *(tab + 2) is this array, but again, the array is treated as a pointer to its first element (an int). Adding 2 to that gives a pointer that points to the number 8. The final * de-references that pointer to give the value 8. printf("\n\n"); foo(3, 3, tab); /* A. don't understand */ This call does not "lie". So inside foo it is seen as it was defined and element [1][1] is the number 4. printf("%i\n", tab[3][3]); /* B. understand */ printf("%i\n", *(*(tab+3)+3)); /* B. understand */ These two are exactly as above, but the array is being index out of bounds so you get undefined behaviour (probably a segmentation fault, or maybe just garbage being printed). printf("\n\n"); return 0; } -- Ben. Mar 31 '06 #4

 P: n/a Ben Bacarisse wrote: foo(2, 2, tab); /* A. don't understand */ This calls "lies" to foo telling it that the array is 2x2 so foo sees it as if it were "int tab[2][2] = {{0, 1}, {2, 3}};". Element [1][1] is 3 and this is what is printed. I know it before that functions regard an array argument same as a pointer. So how can the layout/dimension of an actual array argument be known inside the function body? Are new meanings/semantics given to array arguments when they are variable-length array? foo(3, 3, tab); /* A. don't understand */ This call does not "lie". So inside foo it is seen as it was defined and element [1][1] is the number 4. The original array is: /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */ , if it is used instead, then foo(3, 3, tab); lies again, right? I can understand the original sample code in your way, but get more anxious on how a function knows the layout/dimension of actual array arguments. Mar 31 '06 #5

 P: n/a On Fri, 31 Mar 2006 09:12:25 -0800, lovecreatesbeauty wrote: Ben Bacarisse wrote: > foo(2, 2, tab); /* A. don't understand */ This calls "lies" to foo telling it that the array is 2x2 so foo sees it as if it were "int tab[2][2] = {{0, 1}, {2, 3}};". Element [1][1] is 3 and this is what is printed. I know it before that functions regard an array argument same as a pointer. So how can the layout/dimension of an actual array argument be known inside the function body? Are new meanings/semantics given to array arguments when they are variable-length array? Yes. The special syntax of these arguments lets the compiler know how big each row of the parameter array is. > foo(3, 3, tab); /* A. don't understand */ This call does not "lie". So inside foo it is seen as it was defined and element [1][1] is the number 4. The original array is: /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */ , if it is used instead, then foo(3, 3, tab); lies again, right? Yes and this is a bigger lie. But I put "lie" in quotes, because it may be OK to do it. Telling a function the "shape" of the data array is fine so long as you know what will happen when you do that. If you want to treat a flat array as a collection of rows, then you are free to do so but you will need to persuade the compiler with a cast in the call to foo: foo(3, 3, (int (*)[3])tab) and you will not be able to write tab[2][2] within scope of the flat definition. Nor will the mess with all the pointer arithmetic work. In short, you need a very good reason to go messing about like that. If you have 2D array, then just declare it and use it. Pass at least the "row size" to any functions that use the array and all will be fine. Passing both sizes makes sense for many applications and helps to document the code. -- Ben. Mar 31 '06 #6

 P: n/a Ben Bacarisse wrote: On Fri, 31 Mar 2006 09:12:25 -0800, lovecreatesbeauty wrote: Ben Bacarisse wrote: > foo(2, 2, tab); /* A. don't understand */ This calls "lies" to foo telling it that the array is 2x2 so foo sees it as if it were "int tab[2][2] = {{0, 1}, {2, 3}};". Element [1][1] is 3 and this is what is printed. I know it before that functions regard an array argument same as a pointer. So how can the layout/dimension of an actual array argument be known inside the function body? Are new meanings/semantics given to array arguments when they are variable-length array? Yes. The special syntax of these arguments lets the compiler know how big each row of the parameter array is. > foo(3, 3, tab); /* A. don't understand */ This call does not "lie". So inside foo it is seen as it was defined and element [1][1] is the number 4. The original array is: /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */ , if it is used instead, then foo(3, 3, tab); lies again, right? Yes and this is a bigger lie. But I put "lie" in quotes, because it may be OK to do it. Telling a function the "shape" of the data array is fine so long as you know what will happen when you do that. If you want to treat a flat array as a collection of rows, then you are free to do so but you will need to persuade the compiler with a cast in the call to foo: foo(3, 3, (int (*)[3])tab) and you will not be able to write tab[2][2] within scope of the flat definition. Nor will the mess with all the pointer arithmetic work. In short, you need a very good reason to go messing about like that. If you have 2D array, then just declare it and use it. Pass at least the "row size" to any functions that use the array and all will be fine. Passing both sizes makes sense for many applications and helps to document the code. -- Ben. Thank you. How is it going whan I add `foo(0, 0, tab)' and `foo(1, 1, tab)' in the code snippet as following? Can I think each function call refers to the array element as following (I get inspired on it form another people goodluckyxl): foo(0, 0, tab) refers to: tab[1+sizeof(int[0])/sizeof(int)] or tab[1+0/sizeof(int)] foo(0, 0, tab) refers to: tab[1+sizeof(int[1])/sizeof(int)] foo(0, 0, tab) refers to: tab[1+sizeof(int[2])/sizeof(int)] foo(0, 0, tab) refers to: tab[1+sizeof(int[3])/sizeof(int)] #include void foo(int size_x, int size_y, int tab[size_x][size_y]) { printf("tab[1][1] == %d\n", tab[1][1]); } int main() { int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; foo(0, 0, (int(*)[0])tab); /* foo(0, 0, tab); */ foo(1, 1, (int(*)[1])tab); /* foo(1, 1, tab); */ foo(2, 2, (int(*)[2])tab); foo(3, 3, (int(*)[3])tab); return 0; } Apr 1 '06 #7

 P: n/a Ben Bacarisse wrote: On Fri, 31 Mar 2006 09:12:25 -0800, lovecreatesbeauty wrote: Ben Bacarisse wrote: > foo(2, 2, tab); /* A. don't understand */ This calls "lies" to foo telling it that the array is 2x2 so foo sees it as if it were "int tab[2][2] = {{0, 1}, {2, 3}};". Element [1][1] is 3 and this is what is printed. I know it before that functions regard an array argument same as a pointer. So how can the layout/dimension of an actual array argument be known inside the function body? Are new meanings/semantics given to array arguments when they are variable-length array? Yes. The special syntax of these arguments lets the compiler know how big each row of the parameter array is. > foo(3, 3, tab); /* A. don't understand */ This call does not "lie". So inside foo it is seen as it was defined and element [1][1] is the number 4. The original array is: /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */ , if it is used instead, then foo(3, 3, tab); lies again, right? Yes and this is a bigger lie. But I put "lie" in quotes, because it may be OK to do it. Telling a function the "shape" of the data array is fine so long as you know what will happen when you do that. If you want to treat a flat array as a collection of rows, then you are free to do so but you will need to persuade the compiler with a cast in the call to foo: foo(3, 3, (int (*)[3])tab) and you will not be able to write tab[2][2] within scope of the flat definition. Nor will the mess with all the pointer arithmetic work. In short, you need a very good reason to go messing about like that. If you have 2D array, then just declare it and use it. Pass at least the "row size" to any functions that use the array and all will be fine. Passing both sizes makes sense for many applications and helps to document the code. -- Ben. Thank you. How is it going whan I add `foo(0, 0, tab)' and `foo(1, 1, tab)' in the code snippet as following? Can I think each function call refers to the array element as following (I get inspired on it form another people goodluckyxl): (sorry to make mistakes on following descriptions in my previous post) foo(0, 0, tab) refers to: tab[1+sizeof(int[0])/sizeof(int)] or tab[1+0/sizeof(int)] foo(1, 1, tab) refers to: tab[1+sizeof(int[1])/sizeof(int)] foo(2, 2, tab) refers to: tab[1+sizeof(int[2])/sizeof(int)] foo(3, 3, tab) refers to: tab[1+sizeof(int[3])/sizeof(int)] #include void foo(int size_x, int size_y, int tab[size_x][size_y]) { printf("tab[1][1] == %d\n", tab[1][1]); } int main() { int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; foo(0, 0, (int(*)[0])tab); /* foo(0, 0, tab); */ foo(1, 1, (int(*)[1])tab); /* foo(1, 1, tab); */ foo(2, 2, (int(*)[2])tab); foo(3, 3, (int(*)[3])tab); return 0; } Apr 1 '06 #8

 P: n/a "Ben Bacarisse" wrote in message news:pa****************************@bsb.me.uk... On Fri, 31 Mar 2006 02:00:45 -0800, lovecreatesbeauty wrote: #include void foo(int size_x, int size_y, int tab[size_x][size_y]) { printf("tab[1][1] == %d\n", tab[1][1]); prints the 2nd element of the 2nd element of tab. } int main() { /* int tab[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; */ int tab[3][3] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; My compiler (gcc 4.0.1) warns me I should write: int tab[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}}; although it accepts the flat list as well. foo(2, 2, tab); /* A. don't understand */ This calls "lies" to foo telling it that the array is 2x2 so foo sees it as if it were "int tab[2][2] = {{0, 1}, {2, 3}};". Element [1][1] is 3 and this is what is printed. This lie makes my compiler produce a warning. That is reasonable because the types are incompatible. So that makes me wonder: is this guaranteed to work; always produce the same result? I would think yes but i would like someone to confirm it. Apr 2 '06 #9

This discussion thread is closed

Replies have been disabled for this discussion.