473,789 Members | 2,774 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Dynamically-allocated Multi-dimensional Arrays

The C-FAQ describes some techniques here: http://c-faq.com/aryptr/dynmuldimary.html

I was using something slightly different from the C-FAQ and I was
wondering if it was legal.

Say I want a two-dimensional array, like this:

int x[2][3];

but I want it dynamically-allocated, and I want expressions that refer
to its elements to use the common subscript syntax.

int i = x[0][1];

I also want it to be one contiguous piece of memory, to avoid overhead
and complications.

Is this legal?

int (*x)[3] = (int (*)[3]) malloc(sizeof(i nt) * 2 * 3);

x[0][0] = 1;
x[0][1] = ...;
x[1][1] = ...;

I don't see anything in the standard that wouldn't allow this. It is
also cleaner than what the C-FAQ mentions, which is:

int (*x)[2][3] = (int (*)[2][3]) malloc(sizeof(i nt) * 2 * 3);

(*x)[0][0] = 1;
(*x)[0][1] = ...;
(*x)[1][1] = ...;

which I want to avoid.

Thanks for any input. If this is illegal, a pointer into the standard
would be appreciated.

if this is legal, I will look into updating the C-FAQ.

-Frank

Mar 16 '07 #1
7 8732
On Mar 15, 8:12 pm, "Serpent" <fwallingf...@g mail.comwrote:
The C-FAQ describes some techniques here:http://c-faq.com/aryptr/dynmuldimary.html

I was using something slightly different from the C-FAQ and I was
wondering if it was legal.

Say I want a two-dimensional array, like this:

int x[2][3];

but I want it dynamically-allocated, and I want expressions that refer
to its elements to use the common subscript syntax.

int i = x[0][1];

I also want it to be one contiguous piece of memory, to avoid overhead
and complications.
The second way listed in the FAQ is what you want:

int **array2 = malloc(nrows * sizeof(int *));
array2[0] = malloc(nrows * ncolumns * sizeof(int));
for(i = 1; i < nrows; i++)
array2[i] = array2[0] + i * ncolumns;

It happens to also be more or less the way that BLAS does it, if I
remember correctly.

Brent

Mar 16 '07 #2
I also want it to be one contiguous piece of memory,
to avoid overhead and complications.

The second way listed in the FAQ is what you want:

int **array2 = malloc(nrows * sizeof(int *));
array2[0] = malloc(nrows * ncolumns * sizeof(int));
for(i = 1; i < nrows; i++)
array2[i] = array2[0] + i * ncolumns;
This looks like two pieces of memory to me. It also looks like
additional overhead.

I'm looking for a solution that uses one piece, like the one I
suggested. Is my suggestion legal C? It compiles and executes with no
out-of-bounds accesses on the platforms and compilers I've tested, and
I can't find any contradicting paragraphs in the standard, but I may
have missed something.

-Frank

Mar 16 '07 #3
Serpent wrote:
>
The C-FAQ describes some techniques here: http://c-faq.com/aryptr/dynmuldimary.html

I was using something slightly different from the C-FAQ and I was
wondering if it was legal.

Say I want a two-dimensional array, like this:

int x[2][3];

but I want it dynamically-allocated, and I want expressions that refer
to its elements to use the common subscript syntax.

int i = x[0][1];

I also want it to be one contiguous piece of memory, to avoid overhead
and complications.

Is this legal?

int (*x)[3] = (int (*)[3]) malloc(sizeof(i nt) * 2 * 3);

x[0][0] = 1;
x[0][1] = ...;
x[1][1] = ...;

I don't see anything in the standard that wouldn't allow this.
The only thing wrong with it,
is that only one of the dimensions can be a variable.
If that's OK with you, then there's nothing wrong with it.

/* BEGIN new.c */

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

#define XX 2
#define YY 3

int main(void)
{
int x, y;
int (*array)[YY];

x = XX;
array = malloc(x * sizeof *array);
if (array == NULL) {
puts("array == NULL");
exit(EXIT_FAILU RE);
}
while (x-- != 0) {
for (y = 0; y != YY; ++y) {
array[x][y] = x + y;
}
}
for (x = 0; x != XX; ++x) {
for (y = 0; y != YY; ++y) {
printf("%d\n", array[x][y]);
}
}
free(array);
return 0;
}

/* END new.c */

--
pete
Mar 16 '07 #4
On Mar 15, 9:30 pm, "Serpent" <fwallingf...@g mail.comwrote:
I also want it to be one contiguous piece of memory,
to avoid overhead and complications.
The second way listed in the FAQ is what you want:
int **array2 = malloc(nrows * sizeof(int *));
array2[0] = malloc(nrows * ncolumns * sizeof(int));
for(i = 1; i < nrows; i++)
array2[i] = array2[0] + i * ncolumns;

This looks like two pieces of memory to me. It also looks like
additional overhead.
You have to allocate the pointers for *array2[nrows]. A two-
dimensional array in C looks like a pointer to an array of pointers.

The reason that technique is useful is that you can dynamically
allocate an array of any dimensions at runtime.

You can also, for efficiency, use array2[0] as if it were a one-
dimensional array of size rows*columns.
I'm looking for a solution that uses one piece, like the one I
suggested. Is my suggestion legal C?
Now that I thought through what your code does, you do end up with an
array that's laid out like a statically allocated array. The
disadvantage is, you have to declare the number of columns at compile
time.

int (*x)[3] = (int (*)[3]) malloc((sizeof int) * nrows * 3);

is legal.

int (*x)[ncols] = (int (*)[ncols]) malloc((sizeof int) * nrows *
ncols);

is not.

And now that I've thought it through, I remember there's a long
discussion of these matters in Peter van Der Linden's _Expert C
Programming: Deep C Secrets_.

Brent

Mar 16 '07 #5
br************@ gmail.com wrote:
int (*x)[3] = (int (*)[3]) malloc((sizeof int) * nrows * 3);
is legal.
int (*x)[ncols] = (int (*)[ncols]) malloc((sizeof int) * nrows *
ncols);
is not.
Isn't the second form legal as of C99 ?
--
pa at panix dot com
Mar 16 '07 #6
On Mar 16, 1:34 pm, p...@see.signat ure.invalid (Pierre Asselin) wrote:
brent.buesc...@ gmail.com wrote:
int (*x)[3] = (int (*)[3]) malloc((sizeof int) * nrows * 3);
is legal.
int (*x)[ncols] = (int (*)[ncols]) malloc((sizeof int) * nrows *
ncols);
is not.

Isn't the second form legal as of C99 ?

--
pa at panix dot com
I don't know. So you have a pointer to an array of ncols ints. C99
should let you allocate that, right? And OK, it ends up getting
pointed to a contiguous block of ints on the heap that's ncols*nnrows
big. Seems like it should work.

Note that in that case you could just write

int x[ncols][nrows];

couldn't you? Or does that approach gives you an Iliffe vector like
in the example I pulled from the FAQ? It does apparently allocate the
array on the stack, which you might want to avoid.

As an aside, is it safe to trust real-world implementations of C99
variable-size arrays yet?

Brent

Mar 16 '07 #7
In article <11************ *********@l77g2 000hsb.googlegr oups.com>
Serpent <fw**********@g mail.comwrote:
>The C-FAQ describes some techniques here:
http://c-faq.com/aryptr/dynmuldimary.html

I was using something slightly different from the C-FAQ and I was
wondering if it was legal.

Say I want a two-dimensional array, like this:

int x[2][3];

but I want it dynamically-allocated, and I want expressions that refer
to its elements to use the common subscript syntax.

int i = x[0][1];

I also want it to be one contiguous piece of memory, to avoid overhead
and complications.

Is this legal?

int (*x)[3] = (int (*)[3]) malloc(sizeof(i nt) * 2 * 3);
Yes, but it is better to write, e.g.:

int (*x)[3];
...
x = malloc(n * sizeof *x);

where "n" is the number of rows to use. If the malloc() succeeds,
you can then do:

for (i = 0; i < n; i++)
for (j = 0; j < 3; j++)
... operate on x[i][j] ...

Note that the number of columns is fixed: it must always be exactly
three. If you want the number of columns to be variable as well,
you have a problem.

In C99 (but not older versions of C), there is a new feature called
a "variable length array" or VLA. This new feature allows you to
change the number of columns, as well as the number of rows. Here,
you might write, e.g.:

void do_something(si ze_t m, size_t n) {
int arr[m][n];
size_t i, j;

for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
... operate on arr[i][j] ...

/* "arr" is automatic, so it vanishes when we return */
}

If the array needs to have "allocated" storage duration, i.e., come
from malloc(), rather than having automatic storage duration, you
can still do that:

void do_more(size_t m, size_t n) {
int (*p)[n];
size_t i, j;

p = malloc(m * sizeof *p);
if (p == NULL)
... handle error ...

for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
... operate on p[i][j] ...
}

but now there is an annoying problem: the type of "p" is "pointer
to VLA (of size n) of int", where n is determined by the call to
do_more(). So you must give up some degree of type-safety in order
to do something useful with the value in p (such as store it in a
return value, or store it in some "global" variable, or whatever)
before returning. It then becomes very easy to store the pointer
in a VLA of different "shape" (e.g., "pointer to VLA (of size 99)
of int" instad of "pointer to VLA (of size 33) of int"). If you
do this, tragedy will ensue. Hence, while VLAs are quite useful,
they are not a panacea.

If you do not have C99 (most people still do not, or at least not a
full version) and/or are unwilling to depend on having at least the
VLA feature, you have just two options.

A) Use a minimum of two malloc() calls: one to create the space
for the array, and one to create the space for a vector of
"row pointers". This technique is shown in the FAQ. It is
tempting to use one malloc() to create both regions, but to
do so invites the Gods of Alignment to strike your program
down when you least expect it. :-) (More seriously: some
machines have particular alignment constraints, and getting
both the row-vector *and* the data-area aligned requires
machine dependent trickery. The malloc() function contains
exactly this trickery, and calling it twice makes both areas
properly aligned.)

B) Use one malloc() call to allocate the data area, then do your
own "manual" calculations:

int *do_it_with_C89 (size_t m, size_t n) {
int *p;
size_t i, j;

p = malloc(m * n * sizeof *p);
if (p == NULL)
... handle error ...
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
... operate on p[i * n + j] ...
return p;
}

Method (B) works in C99 as well, of course. While it is type-safe,
it is easy to make mistakes in remembering "m" and/or "n" and/or
doing the subscript calculation. You can minimize the chances of
such problems by using a structure to encapsulate everything:

/* in some header */
struct int_matrix {
size_t m;
size_t n;
int *p;
};
#ifndef NDEBUG
#define INT_MAT_ELEM(mp , i, j) \
(assert((i) < (mp)->m && (j) < (mp)->n), (mp)->p[(i) * (mp)->n + (j)])
#else
#define INT_MAT_ELEM(mp , i, j) ((mp)->p[(i) * (mp)->n + (j)])
#endif

/* in some source file that includes the above header, plus <stdlib.h*/
struct int_matrix *int_mat_create (size_t m, size_t n) {
struct int_matrix *mp;
size_t i, end;

mp = malloc(sizeof *mp);
if (mp == NULL)
return NULL;
mp->p = malloc(m * n * sizeof *mp->p);
if (mp->p == NULL) {
free(mp);
return NULL;
}
mp->m = m;
mp->n = n;

/* init to all-zeros */
for (i = 0, end = m * n; i < end; i++)
mp->p[i] = 0;

return mp;
}

void int_mat_destroy (struct int_matrix *mp) {
free(mp->p);
free(mp);
}

/* in some file that uses the integer matrix */
...
...
struct int_matrix *p;

p = int_mat_create( m, n);
if (p == NULL)
... handle error ...
...
INT_MAT_ELEM(p, i, j) = 42;
... other operations on INT_MAT_ELEM(p, i, j) ...

It is a little peculiar to have a function-like macro that expands
to an lvalue (so that you can assign to INT_MAT_ELEM(p, i,j) as in
the example above), but it should work.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Mar 17 '07 #8

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

Similar topics

7
3262
by: Tim T | last post by:
Hi, I have the need to use dynamically loaded user controls in a webform page. I have the controls loading dynamically, and that part works fine. this is the code used in a webform to dynamically load one of several controls: private void btnCategory_Click(object sender, System.EventArgs e) { Control myControl = LoadControl(DropDownList1.SelectedItem.Text + ".ascx"); PlaceHolder1.Controls.Add(myControl);
8
4317
by: Donald Xie | last post by:
Hi, I noticed an interesting effect when working with controls that are dynamically loaded. For instance, on a web form with a PlaceHolder control named ImageHolder, I dynamically add an image button at runtime: //----- Code snippet protected System.Web.UI.WebControls.PlaceHolder ImageHolder; private void Page_Load(object sender, System.EventArgs e)
2
2929
by: R Duke | last post by:
I have tried everything I can think of to change the visible property of a design time created control from a dynamically created control's command event handler. Here is the scenario. I have a WebForm with some textboxes, dropdownlists, a panel, imagebutton and so on. When I click on the image button (which was created at design time) I dynamically build a table. In each of row of that new table I put several cells and one cell...
1
2580
by: Kamal Jeet Singh | last post by:
Hi Friends !! I am facing problem in controlling the dynamically created controls on web page. The problem Scenario is Scenario:- My requirement is to load the web user controls on the web page dynamically. To do this, First I including a web page (MainPage.aspx) and I made form tag to Runat=Server. I included one table tag and also made this table Runat=Server side. Second I created three Web User Controls e.g. wucCustomerInfo.ascx,
1
1022
by: Reza Nabi | last post by:
Bakground: I have a webform (LoadCtl.aspx) which loads the user control to a placeholder dynamically based on the ctlName querystring passed in the URL. Webform (LoadCtl.aspx) also passes a variable (targetId) in to the usercontrol (IntergySite.aspx) by calling its setter method. Currently, I am using if-then-else and hardcoded the User Control Object to do casting and call the setter method. Question: Is there any way I could load,...
7
6787
by: pmclinn | last post by:
I was wondering if it is possible to dynamically create a structure. Something like this: public sub main sql = "Select Col1, Col2 from Table a" dim al as new arraylist al = LoadOracleData(sql) '____Do amazing things
2
2457
by: Pete Moss | last post by:
During a postback event, I am having trouble retrieving the state of a CheckBox Control that I am dynamically adding to a DataGrid Control using ASP.NET 1.1. I have no trouble adding the TemplateColumn dynamically. I persist a DataSet in my Session object and I bind the CheckBox to the DataSet. So far so good. The CheckBoxes show up and the user interacts with them (checks a few, unchecks a few). The problem is that during a postback...
9
7042
by: netasp | last post by:
hi all, how can I populate one aspx form when page is loading based on page ID? for example: loading page A (to search for VB code) would display labels and texboxes, dropdown lists all related to VB, plus the address bar would show something like this: www.somethinghere?id=3 and if you change number 3 from the address bar to (for example) 34 or 71 you would get different page with the same formatting like I.e: www.somethinghere?id=34...
4
2976
by: mohaaron | last post by:
I can think of a lot of reasons why this might need to be done but as far as I can tell it's not possible. I've been looking for a way to add HtmlTableRows to a table using a button click for a while and it seems it's not possible because the row that gets added with each click won't get recreated after a post back. After all the reading it seems that any dynamically created controls must be created in the Init event to be recreated after...
7
6672
by: RichB | last post by:
I am trying to get to grips with the asp.net ajaxcontrol toolkit, and am trying to add a tabbed control to the page. I have no problems within the aspx file, and can dynamically manipulate a tabcontainer which has 1 panel already, however I want to try create the TabPanels dynamically. I followed the advice here: http://www.asp.net/learn/ajax-videos/video-156.aspx (3rd comment - Joe Stagner)
0
9666
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...
0
10408
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
10139
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
9020
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
7529
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
6769
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
5417
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...
2
3700
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2909
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.