473,837 Members | 1,516 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Is the syntax for multi-dimensional arrays counter-intuitive?

All this time I was under the illusion that I understand the concept of
multi-dimensional arrays well ---- however the following code snippet
belies my understanding.

I had assumed all along that a declaration like:
int intArray[3][5]
means that there is an array of pointers to int with a size of 5, each
of whose elements is an array of int with a size of 3.

This definition seemed intuitive to me since a declaration like
int intVar[5]
means that there is an array of integers with a size of 5.

In my "intuitive" thinking, to dynamically create a 2D array with 3
rows and 5 columns, we would do the following:

Allocate memory for 5 pointers to int (i.e. pointer array)
For each entry in the pointer array
Do
Allocate memory for 3 ints
Done

My code had a bug, which was fixed by switching my logic to something
like this (as can be seen from the coding example):

Allocate memory for 3 pointers to int (i.e. pointer array)
For each entry in the pointer array
Do
Allocate memory for 5 ints
Done

This indicates to me that the correct interpretation of a declaration
like:

int intArray[3][5]

is that there is an array of pointers to int with a size of 3, each of
whose elements is an array of int with a size of 5. Is this a correct
interpretation? This sounds counter intuitive to me (for reasons
mentioned above) but I have reconciled to this interpretation. I will
jump off the cliff if I am wrong again!
Masood
/*************** *************** *************** ****/
#include <stdio.h>
#include <stdlib.h>

#define MAXROWS 3
#define MAXCOLS 5

main()
{
int startVal = 5;

int **tbl;

tbl = (int **)malloc(MAXRO WS*sizeof(int*) );
/* C++ : tbl = new (int*)[MAXROWS]; */

for(size_t i = 0; i < MAXCOLS; i++)
tbl[i] = (int *)malloc(MAXCOL S*sizeof(int));
/* C++: tbl[i] = new (int)[MAXCOLS]; */

for(size_t row = 0; row < MAXROWS; row++)
for(size_t col = 0; col < MAXCOLS; col++)
tbl[row][col] = startVal++;

for(size_t row = 0; row < MAXROWS; row++)
for(size_t col = 0; col < MAXCOLS; col++)
printf("Row: %d, Col: %d => %d\n",
row, col, tbl[row][col]);
return 0;
}

Nov 14 '05 #1
8 2254
["Followup-To:" header set to comp.lang.c.]
On 2005-02-03, ma**********@ly cos.com <ma**********@l ycos.com> wrote:
All this time I was under the illusion that I understand the concept of
multi-dimensional arrays well ---- however the following code snippet
belies my understanding.

I had assumed all along that a declaration like:
int intArray[3][5]
means that there is an array of pointers to int with a size of 5, each
of whose elements is an array of int with a size of 3.

This definition seemed intuitive to me since a declaration like
int intVar[5]
means that there is an array of integers with a size of 5.
In C multi-dimensioned arrays are arrays of arrays. With the above
declarations, intVar in an expression is treated as pointer to an int.
Similarily, intArray in an expression is treated as a pointer to an
array of 5 ints.
In my "intuitive" thinking, to dynamically create a 2D array with 3
rows and 5 columns, we would do the following:

Allocate memory for 5 pointers to int (i.e. pointer array)
For each entry in the pointer array
Do
Allocate memory for 3 ints
Done
In C arrays are stored row-wise; the rightmost subscript varies the
fastest. If the rightmost dimension is 5, you need to allocte memory
for 5 ints for each occurrence of the next dimension to the left.

To the designers of C to dynamically create a 2D array with 3 rows
and 5 columns, you could use

int (*intArray_p)[3][5] = malloc(sizeof(* intArray_p));

to declare and allocate the array and use (*intArray_p)[i][j] to refer
to the i-th, j-th element.

If you know all but the leftmost dimension at compile time, you could
use

int (*intArray_p)[][5] = malloc(leftDimC ount*sizeof(**i ntArray_p));

to declare and allocate the array and use (*intArray_p)[i][j] to refer
to the i-th, j-th element.

If you know neither of the dimensions at compile time, you could
use

int *int_p = malloc(leftDimC ount*rightDimCo unt*sizeof(*int _p));

to declare and allocate the array and use int_p[i*rightDimCount + j]
to refer to the i-th, j-th element.
My code had a bug, which was fixed by switching my logic to something
like this (as can be seen from the coding example):

Allocate memory for 3 pointers to int (i.e. pointer array)
You want to allocate memory for 3 pointers arrays of 5 ints. However,
in most implementations a pointer to int and a pointer to and array of
5 ints have the same representation.
For each entry in the pointer array
Do
Allocate memory for 5 ints
Done

This indicates to me that the correct interpretation of a declaration
like:

int intArray[3][5]

is that there is an array of pointers to int with a size of 3, each of
whose elements is an array of int with a size of 5. Is this a correct
interpretation? This sounds counter intuitive to me (for reasons
mentioned above) but I have reconciled to this interpretation. I will
jump off the cliff if I am wrong again!


The correct interpretation is that there is an array of 3 elements, each
of whose elements is an array of 5 ints. When intArray appears in an
expression, it is treated as a pointer to its first element, which is
and array of 5 ints. However, intArray is not stored as an array of
pointers.
[snip]
Nov 14 '05 #2
ma**********@ly cos.com writes:
All this time I was under the illusion that I understand the concept of
multi-dimensional arrays well ---- however the following code snippet
belies my understanding.

I had assumed all along that a declaration like:
int intArray[3][5]
means that there is an array of pointers to int with a size of 5, each
of whose elements is an array of int with a size of 3.


Strictly speaking, C doesn't have multi-dimensional arrays. It does
have arrays of arrays, though.

The above declaration declares an array of 3 elements. Each element
is an array of 5 ints.

It doesn't create any pointers.

There's a rule that, in an expression, the name of an array is
(usually) converted to a pointer to its first element. (This
conversion doesn't happen if the array name is the operand of a sizeof
or unary "&" operator.) This rule is the source of the fallacy that
arrays and pointers are somehow the same thing. They aren't.

The fact that a parameter declaration
some_type *param
can be written as
some_type param[]
just adds to the confusion.

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #3
On Thu, 03 Feb 2005 05:28:55 +0000, A. Bolmarcich wrote:
["Followup-To:" header set to comp.lang.c.]
On 2005-02-03, ma**********@ly cos.com <ma**********@l ycos.com> wrote:
All this time I was under the illusion that I understand the concept of
multi-dimensional arrays well ---- however the following code snippet
belies my understanding.

I had assumed all along that a declaration like:
int intArray[3][5]
means that there is an array of pointers to int with a size of 5, each
of whose elements is an array of int with a size of 3.
There are no pointers here, and pointers don't have elements arrays do.
Pointers point to OTHER objects and there is only one overall object here.
intArray would be laid out in memory as 15 contiguous int objects,
treated as 3 groups of 5 ints. If you output sizeof intArray you'll see it
is 15*sizeof(int).
This definition seemed intuitive to me since a declaration like
int intVar[5]
means that there is an array of integers with a size of 5.
That's fine, but it doesn't suggest anything about pointers in arrays of
arrays. In that case you're just replacing the element type int here with
a different element type that happens itself to be an array. An equivalent
way of defining intArray would be:

typedef int Int5[5];
Int5 intArray[3];
In C multi-dimensioned arrays are arrays of arrays. With the above
declarations, intVar in an expression is treated as pointer to an int.
Similarily, intArray in an expression is treated as a pointer to an
array of 5 ints.
In my "intuitive" thinking, to dynamically create a 2D array with 3
rows and 5 columns, we would do the following:

Allocate memory for 5 pointers to int (i.e. pointer array)
For each entry in the pointer array
Do
Allocate memory for 3 ints
Done
In C arrays are stored row-wise; the rightmost subscript varies the
fastest. If the rightmost dimension is 5, you need to allocte memory
for 5 ints for each occurrence of the next dimension to the left.

To the designers of C to dynamically create a 2D array with 3 rows
and 5 columns, you could use

int (*intArray_p)[3][5] = malloc(sizeof(* intArray_p));


But typically you wouldn't, you would use

int (*intArray_p)[5] = malloc(3 * sizeof *intArray_p);
to declare and allocate the array and use (*intArray_p)[i][j] to refer
to the i-th, j-th element.
And then you can refer to the elements using intArray_p[i][j]
If you know all but the leftmost dimension at compile time, you could
use

int (*intArray_p)[][5] = malloc(leftDimC ount*sizeof(**i ntArray_p));

to declare and allocate the array and use (*intArray_p)[i][j] to refer
to the i-th, j-th element.
The simpler version works here too.
If you know neither of the dimensions at compile time, you could
use

int *int_p = malloc(leftDimC ount*rightDimCo unt*sizeof(*int _p));

to declare and allocate the array and use int_p[i*rightDimCount + j]
to refer to the i-th, j-th element.
This is a case where using an intermediate array of pointers can help. If
you do that you can still use the int_p[i][j] syntax for accessing
elements.
My code had a bug, which was fixed by switching my logic to something
like this (as can be seen from the coding example):

Allocate memory for 3 pointers to int (i.e. pointer array)


You want to allocate memory for 3 pointers arrays of 5 ints. However,
in most implementations a pointer to int and a pointer to and array of
5 ints have the same representation.


3 pointers to int is correct. When you access an array using a pointer you
use a pointer to the array's element type. So to access an array of 5 ints
you need a pointer of type pointer to int.
For each entry in the pointer array
Do
Allocate memory for 5 ints
Done

This indicates to me that the correct interpretation of a declaration
like:

int intArray[3][5]

is that there is an array of pointers to int with a size of 3, each of
whose elements is an array of int with a size of 5. Is this a correct
interpretation?
Again, there are no pointers involved. You simply have a bunch of int
objects together in memory and the type of intArray supplies the
information the compiler needs to figure out the address of the correct
one by direct offset calculation.
This sounds counter intuitive to me (for reasons
mentioned above) but I have reconciled to this interpretation. I will
jump off the cliff if I am wrong again!


Then make it a very small cliff.
The correct interpretation is that there is an array of 3 elements, each
of whose elements is an array of 5 ints. When intArray appears in an
expression, it is treated as a pointer to its first element, which is
and array of 5 ints. However, intArray is not stored as an array of
pointers.
[snip]


Yes.

Lawrence

Nov 14 '05 #4
The following is an example function that uses a more efficient method
for allocating memory on a multi dimensional array.
This code is for a 3D array, but the logic can easily be modified for
2D array:

#include <stdlib.h>
#include <stdio.h>
#include <memory.h>

int ***Allocate3DAr ray_C( int x, int y, int z)
{
int *** pppx = (int ***)malloc(x*si zeof(int**));
int ** pool_y = (int **)malloc(x*y*s izeof(int*));
int * pool_z = (int *)malloc(x*y*z* sizeof(int));
int i_x, i_y;
for(i_x = 0; i_x < x; ++i_x){
pppx[i_x] = pool_y;
pool_y +=y;
for(i_y = 0;i_y < y;++i_y){
pppx[i_x][i_y] = pool_z;
pool_z +=z;
}
}
return pppx;
}

void Free3DArray_C(i nt*** Array)
{
free(**Array);
free(*Array);
free(Array);
}

void Test3DArray(int *** Array, int x, int y, int z)
{
int ix, iy, iz;
for(ix = 0;ix < x;++ix)
{
for(iy = 0;iy < y;++iy)
{
for(iz=0;iz<z;+ +iz)
{
printf("%03i\n" , Array[ix][iy][iz]);
}
}
}
}

int main()
{
int x = 2;
int y = 3;
int z = 5;
int ix, iy, iz;
int *** d = Allocate3DArray _C(x, y, z);
for(ix = 0;ix < x;++ix)
{
for(iy = 0;iy < y;++iy)
{
for(iz=0;iz<z;+ +iz)
{
d[ix][iy][iz] = ix*100 + iy*10 + iz;
}
}
}

Test3DArray(d, x , y , z);

Free3DArray_C(d );

system("pause") ;
return 0;
}

Check out following link for more information on 2D arrays.
http://www.tek-tips.com/faqs.cfm?fid=5575

Nov 14 '05 #5
axter wrote:

The following is an example function that uses a more efficient method
for allocating memory on a multi dimensional array.
This code is for a 3D array, but the logic can easily be modified for
2D array:

#include <stdlib.h>
#include <stdio.h>
#include <memory.h>

int ***Allocate3DAr ray_C( int x, int y, int z)
{
int *** pppx = (int ***)malloc(x*si zeof(int**));
Better: int ***pppx = malloc(x * sizeof *pppx);
int ** pool_y = (int **)malloc(x*y*s izeof(int*));
Better: int **pool_y = malloc(x * y * sizeof *pool_y);
int * pool_z = (int *)malloc(x*y*z* sizeof(int));
Better: int *pool_z = malloc(x * y * z * sizeof *pool_z);
int i_x, i_y;
for(i_x = 0; i_x < x; ++i_x){
pppx[i_x] = pool_y;
Aren't you assuming something here that needn't be true?
pool_y +=y;
for(i_y = 0;i_y < y;++i_y){
pppx[i_x][i_y] = pool_z;
And here.

<snip>
system("pause") ;


And here.
Nov 14 '05 #6
>>int *** pppx = (int ***)malloc(x*si zeof(int**));
Better: int ***pppx = malloc(x * sizeof *pppx);
IMHO, not better.
The example code was type cast so that it could compile in both C and
C++.
Including it, doesn't hurt.
Aren't you assuming something here that needn't be true?

Can you please be more explicit?
If you have a point to make, please make it.

Nov 14 '05 #7
You snipped the attributions and somehow created a problem
with citation levels.
Please do not do that.

axter wrote:
int *** pppx = (int ***)malloc(x*si zeof(int**));
Better: int ***pppx = malloc(x * sizeof *pppx);
IMHO, not better.
The example code was type cast so that it could compile in both C and
C++.
Including it, doesn't hurt.
Maybe. Have you looked at the changes to the argument of malloc()?
These are indeed an improvement.
Together with the missing cast, you can change the type of
pppx in one place (at declaration) without having to change
any cast-expressions. Even without that, sizeof *pppx is
always the right size.

Aren't you assuming something here that needn't be true?


Can you please be more explicit?
If you have a point to make, please make it.


Unfortunately, you snipped so much that I cannot help you.
-Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #8
axter wrote:
int *** pppx = (int ***)malloc(x*si zeof(int**));
Better: int ***pppx = malloc(x * sizeof *pppx);
IMHO, not better.
Then I think YHO is based on incomplete data.
The example code was type cast so that it could compile in both C and
C++.
With very few exceptions (pjp being the canonical example), this is
unwise. C and C++ are very different languages.
Including it, doesn't hurt.


It doesn't help, either, in C (we don't discuss C++ in comp.lang.c,
but you'd normally expect to use new or std::vector in C++ rather
than malloc).

Furthermore, including it can indeed hurt if you forget to include
<stdlib.h> (which on this occasion you did not, although I now
notice that you also added a <memory.h> - I am not sure why you did
that).

The cast makes the code harder to read, too.
Aren't you assuming something here that needn't be true?

Can you please be more explicit?
If you have a point to make, please make it.


When you ask malloc for memory, it's a good idea to check that you
actually /received/ that memory before you start to use it.
Nov 14 '05 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

699
34356
by: mike420 | last post by:
I think everyone who used Python will agree that its syntax is the best thing going for it. It is very readable and easy for everyone to learn. But, Python does not a have very good macro capabilities, unfortunately. I'd like to know if it may be possible to add a powerful macro system to Python, while keeping its amazing syntax, and if it could be possible to add Pythonistic syntax to Lisp or Scheme, while keeping all of the...
41
2883
by: John Marshall | last post by:
How about the following, which I am almost positive has not been suggested: ----- class Klass: def __init__(self, name): self.name = name deco meth0: staticmethod def meth0(x):
31
2454
by: Brian Sabbey | last post by:
Here is a pre-PEP for what I call "suite-based keyword arguments". The mechanism described here is intended to act as a complement to thunks. Please let me know what you think. Suite-Based Keyword Arguments ----------------------------- Passing complicated arguments to functions is currently awkward in Python. For example, the typical way to define a class property winds up polluting the class's namespace with the property's get/set...
7
43993
by: Jan van Veldhuizen | last post by:
The UPDATE table FROM syntax is not supported by Oracle. I am looking for a syntax that is understood by both Oracle and SqlServer. Example: Table1: id name city city_id 1 john newyork null
14
3657
by: aaron kempf | last post by:
I find that ADP does not support any Stored Procedures that use the 'CREATE PROC spHAPPY' syntax. CREATE PROC syntax is listed in books online. This syntax should be supported Here is a scenario: 1) create proc using query analyzer and CREATE PROC spHAPPY syntax 2) open this proc in ADP
4
7632
by: Bob hotmail.com> | last post by:
Everyone I have been spending weeks looking on the web for a good tutorial on how to use regular expressions and other methods to satisfy my craving for learning how to do FAST c-style syntax highlighting in C# but I have yet to find anything useful I know there are people at MS that know this stuff like the front of their hand and I know there are many people out on the web that are proficient in doing this as well but it seems nobody...
2
2943
by: Terry C. | last post by:
I have a bit of code that loops through a listbox and creates a string of multiple selections and then passes that string to a SQL statement. However, I cannot seem to get a handle on the proper syntax for the WHERE clause to properly pass the string in the format of 'X' OR 'Y' to the query's criteria field. Can someone clarify this syntax or point me to a good example of using a varible string in the WHERE clause of a SQL statement?...
20
2609
by: W Karas | last post by:
Would the fear factor for concepts be slightly reduced if, instead of: concept C<typename T> { typename T::S; int T::mem(); int nonmem(); };
4
1400
by: 2D Rick | last post by:
Dim dtDay1 As Date Dim dtDay2 As Date Dim dtDay3 As Date 'once working I'll load these variables from a multi listbox. dtDay1 = #7/22/2007# dtDay2 = #7/24/2007# dtDay3 = #7/25/2007#
17
3147
by: trose178 | last post by:
Good day all, I am working on a multi-select list box for a standard question checklist database and I am running into a syntax error in the code that I cannot seem to correct. I will also note that I am using Allen Browne's multi-select list box for a report as a guide. I should also note that my access skills are not the best so I may need some explaining on certain things. First let me give some background on the database: I have a...
0
9840
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
1
10623
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10270
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
9397
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7806
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
7000
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5668
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
4474
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
4040
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.