Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Malloc on 2-dim array

4 views
Skip to first unread message

Walter_BAECK/BE/ALCATEL@alcatel

unread,
Aug 17, 2003, 12:44:24 AM8/17/03
to
I want to use a 2-dimensional array for some data, because I find
this the most intuitive representation. Say that I have a picture:

int Pixel[cHeight][cWidth];

It helps clarity that I can reference individual data as:

Dot = Pixel[Row][Column];

But I also want to be able to get a whole new chunk of memory for
another picture, in a single malloc. It would be great to have:

Pixel = (int**)malloc(cHeight * cWidth * sizeof(int));

but the compiler complains about this being the wrong datatype.
It seems conceptually the wrong thing to do, anyway; after this
malloc, a whole slew of malloc's for the individual rows would
have to follow.

---------------------

My solution so far, has been to declare Pixel as a 1-dim pointer:

int *Pixel;

Allocating memory is then routine:

Pixel = (int*)malloc(cHeight * cWidth * sizeof(int));

But the lookup has to "emulate" the real 2-dim nature of the data:

Dot = Pixel[Row*cWidth + Column];

I would like something more elegant and readable. Suggestions ?

--
____________
\ / Walter Baeck
\ ALCATEL/ Alcatel Telecom
\ BELL / Broadband Networks Division
\ / Microelectronics Design
\ / E-mail : walter...@alcatel.be
\/ Phone : +32 3 240 73 86
--
comp.lang.c.moderated - moderation address: cl...@plethora.net

Douglas A. Gwyn

unread,
Aug 17, 2003, 5:54:45 PM8/17/03
to
Walter_BAECK/BE/ALCATEL@ALCATEL wrote:
> I want to use a 2-dimensional array ...

Isn't that in the C FAQ?

Hans-Bernhard Broeker

unread,
Aug 17, 2003, 5:55:12 PM8/17/03
to
Walter_BAECK/BE/ALCATEL@alcatel wrote:

> But I also want to be able to get a whole new chunk of memory for
> another picture, in a single malloc. It would be great to have:

> Pixel = (int**)malloc(cHeight * cWidth * sizeof(int));

> but the compiler complains about this being the wrong datatype.

That's because it is. Pixel's type is not pointer to pointer to int.
It's array of array of ints. These two types are incompatible.

> I would like something more elegant and readable. Suggestions ?

See the C FAQ, please. Q 6.16 in particular.

--
Hans-Bernhard Broeker (bro...@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.

Ulrich Eckhardt

unread,
Aug 19, 2003, 3:33:12 AM8/19/03
to
Walter_BAECK/BE/ALCATEL@ALCATEL wrote:
> I want to use a 2-dimensional array for some data, because I find
> this the most intuitive representation. Say that I have a picture:
>
> int Pixel[cHeight][cWidth];

Apart from what was already said and the example in the FAQ, I'd like to
suggest an improvement in terms of malloc-overhead by only allocating one
chunk of memory:


size_t const rows = ...;
size_t const cols = ...;

struct pixel** bitmap; // struct, typedef, intrinsic - your choice

size_t const mem_prows = sizeof *bitmap * rows; // for pointers to rows [1]
size_t const mem_row = cols * sizeof **bitmap; // for a row [1]

void* ptr = xalloc(mem_prows+mem_row*rows); // nobody uses malloc ...

bitmap = ptr;
for( i=0; i!=cols; ++i)
bitmap[i] = ptr + mem_prows + i*mem_row; // see [2]


[1]: this in fact does no alignment whatsoever. Can anyone suggest a
portable way to fix that (in case it isn't) ? Padding the preceeding
pointers to the size of the following pixels ?

[2]: this performs arithmetics on typeless pointers. In case that is not
allowed in C(which makes sense), one would first have to cast the pointer
to a char.

thank you for comments and suggestions

Uli

Jerry Feldman

unread,
Aug 21, 2003, 3:21:51 PM8/21/03
to
On 19 Aug 2003 07:33:12 GMT
Ulrich Eckhardt <doom...@knuut.de> wrote:

> void* ptr = xalloc(mem_prows+mem_row*rows); // nobody uses malloc ...

Why do you comment that "nobody uses malloc". I would certainly comment
that many malloc(3) implementations are inefficient, but some commercial
implementations are highly optimized.

--
Jerry Feldman <gaf-nospam-at-blu.org>
Boston Linux and Unix user group
http://www.blu.org PGP key id:C5061EA9
PGP Key fingerprint:053C 73EC 3AC1 5C44 3E14 9245 FB00 3ED5 C506 1EA9

Walter_BAECK/BE/ALCATEL@alcatel

unread,
Aug 21, 2003, 3:21:54 PM8/21/03
to
I thought I had read the entire chapter 6 from the FAQ (about Arrays & Pointers)
but I missed the important part, it seems. Thanks to Hans-Bernhard Broeker for
pointing out Q6.16
The main suggestion in that answer is to use a malloc for each row,
which I wanted to avoid. I was however helped by the last alternative :

"Finally, you could use pointers to arrays: "

int (*array4)[NCOLUMNS] =
(int (*)[NCOLUMNS])malloc(nrows * sizeof(*array4));

I like this single malloc call that gets everything done,
even though the syntax baffles my mind.


> Apart from what was already said and the example in the FAQ, I'd like to
> suggest an improvement in terms of malloc-overhead by only allocating one
> chunk of memory:

> [...]


> struct pixel** bitmap; // struct, typedef, intrinsic - your choice

This didn't work for me - instead, I used:
int **bitmap;

> size_t const mem_prows = sizeof *bitmap * rows; // for pointers to rows [1]
> size_t const mem_row = cols * sizeof **bitmap; // for a row [1]
>
> void* ptr = xalloc(mem_prows+mem_row*rows); // nobody uses malloc ...
>
> bitmap = ptr;
> for( i=0; i!=cols; ++i)
> bitmap[i] = ptr + mem_prows + i*mem_row; // see [2]

It's a funny way of building up your own 2-dim array instead of having C
do it for you. I'm actually surprised that this works, because if you
reference an element

Pixel = bitmap[i][j];

you get back in that shady terrain between arrays and pointers;
as the declaration was: int **bitmap;
Q6.18 of the FAQ mentions explicitly that the equivalence between
*(Arr + i) and Arr[i]
no longer applies for 2-dimensional arrays.
Obviously, I haven't mastered the finesses yet.

Anyway, both your solution and the Q6.16/4 example work for my compiler,
so thanks for the help.

--
____________
\ / Walter Baeck
\ ALCATEL/ Alcatel Telecom
\ BELL / Broadband Networks Division
\ / Microelectronics Design
\ / E-mail : walter...@alcatel.be
\/ Phone : +32 3 240 73 86

Douglas A. Gwyn

unread,
Aug 21, 2003, 3:22:01 PM8/21/03
to
Ulrich Eckhardt wrote:
> [1]: this in fact does no alignment whatsoever. Can anyone suggest a
> portable way to fix that (in case it isn't) ? Padding the preceeding
> pointers to the size of the following pixels ?

But then you have difficulty accessing the pointers.
A portable method is to allocate with the pointer part
sized as an array of union type (union of pointer and
data type), but used as array of pointer (so there is
a potential gap betwen the pointers and the data).

> [2]: this performs arithmetics on typeless pointers.

You mean, on pointer to void. All pointers have type.

> In case that is not
> allowed in C(which makes sense), one would first have to cast the pointer
> to a char.

Indeed, it's not allowed. Doing the arithmetic as
(char *) is simplest, given the way you have set it up.

> thank you for comments and suggestions

Most C programmers would set up the row pointers by
incrementation of a temporary pointer rather than by
multiplying by i.

Hans-Bernhard Broeker

unread,
Aug 22, 2003, 9:31:43 PM8/22/03
to
Walter_BAECK/BE/ALCATEL@alcatel wrote:

> int (*array4)[NCOLUMNS] =
> (int (*)[NCOLUMNS])malloc(nrows * sizeof(*array4));

> I like this single malloc call that gets everything done,
> even though the syntax baffles my mind.

It does not actually get everything done, unless you needed that array
dynamic in *one* dimension only. Note that the second dimension,
NCOLUMNS, is hardwired in this case.

In my experience, the best possible choice is actually the FAQ's
`array2' suggestion. It gives you full dynamic allocation for an
n-dimensional array using n calls to malloc(), which is quite
reasonable. And it leaves you full flexibility to access elements:
both by [][] notation, and by offset calculation:

#define ARRAY2(i,j) (*((*array2) + (i)*ncolumns + (j)))

because array2[0][i*ncolumns + j] and array[i][j] are actually the
same thing, in this construction.

> Q6.18 of the FAQ mentions explicitly that the equivalence between
> *(Arr + i) and Arr[i]
> no longer applies for 2-dimensional arrays.

No, it doesn't ---- it would be a bug in the FAQ if it did.

The above equivalence still holds perfectly. What does *not* hold for
more than one array dimension is the common belief that "arrays and
pointers are the same thing" --- they aren't, but for 1-dimensional
arrays, C lets you believe they are, most of the time, fooling many
newbies (some of them brave enough to write C textbooks ...).


--
Hans-Bernhard Broeker (bro...@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.

Andy Isaacson

unread,
Aug 23, 2003, 1:52:41 PM8/23/03
to
In article <clcm-2003...@plethora.net>,

Jerry Feldman <gaf-n...@blu.org> wrote:
>On 19 Aug 2003 07:33:12 GMT
>Ulrich Eckhardt <doom...@knuut.de> wrote:
>> void* ptr = xalloc(mem_prows+mem_row*rows); // nobody uses malloc ...
>
>Why do you comment that "nobody uses malloc". I would certainly comment
>that many malloc(3) implementations are inefficient, but some commercial
>implementations are highly optimized.

I have a similar utility routine in my toolbasket, and the reason I use
xalloc instead of malloc is because xalloc tests for NULL, and causes a
core dump (or otherwise reports the error as appropriate), rather than
forcing me to test at the call site. Since I have the same error handling
everywhere (if malloc returns NULL the program is broken) I centralize it.

Of course I don't use my xalloc in systems that are meant to be reliable
in the face of out-of-memory conditions.

-andy

Ulrich Eckhardt

unread,
Aug 23, 2003, 1:52:50 PM8/23/03
to
Jerry Feldman wrote:

> On 19 Aug 2003 07:33:12 GMT
> Ulrich Eckhardt <doom...@knuut.de> wrote:
>
>> void* ptr = xalloc(mem_prows+mem_row*rows); // nobody uses malloc ...
> Why do you comment that "nobody uses malloc". I would certainly comment
> that many malloc(3) implementations are inefficient, but some commercial
> implementations are highly optimized.

xalloc = call malloc and exit/abort if no memory was available.

I didn't aim at performance, let me clarify:

How many programs do you know that can handle out-of-memory conditions and
retain a working state ? The only one I have hacked on was Linux, I expect
to find other examples among server-like programs and interpreters. For
other programs without a clear recovery-strategy, the easiest and best way
is usually aborting.

I didn't want to say that there is no reason at all to use malloc(), that
is not the case. I just claim that one should never start using malloc
before one has a strategy for handling out-of-memory. Not checking the
result of malloc() is a clear sign of a lack of such strategy.

Uli

Ulrich Eckhardt

unread,
Aug 23, 2003, 1:52:57 PM8/23/03
to
Douglas A. Gwyn wrote:

> Ulrich Eckhardt wrote:
>> [2]: this performs arithmetics on typeless pointers.
>
> You mean, on pointer to void. All pointers have type.


Well, as I see it, 'void' is a placeholder for cases where you want to omit
a type. In particular, void is not a type because you can't have 'objects
of type void'.

Thinking about it some more, the term 'generic pointer' would have been
better, since a generic pointer fills the requirement where any other
pointer is required. If I am not mistaken, a void pointer will implicitly
convert to any other pointer-type, even without an explicit cast in C.

The term 'typeless pointer' would rather match the C++-meaning of a
void-pointer, which matches no other pointer. There, one has to explicitly
cast the pointer to a typed pointer before being able to use the it.

cheers

Uli

Douglas A. Gwyn

unread,
Aug 24, 2003, 5:37:17 PM8/24/03
to
Ulrich Eckhardt wrote:
> How many programs do you know that can handle out-of-memory conditions and
> retain a working state ?

Any "industrial strength" application needs to do something
sensible in the face of foreseable problems.

0 new messages