Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > initialize for a 2-D dynamic array.

Reply
Thread Tools

initialize for a 2-D dynamic array.

 
 
MBALOVER
Guest
Posts: n/a
 
      02-28-2010
HI all,

I want to create a 2D dynamic array and then initialize all elements
with 0.

I did a search and found:

1. array = (** unsigned char) calloc(NROW, sizeof(unsigned char*));

2. for(i = 0; i < NROW ; i++)
3. {
4. array[i] = calloc(NCOL, sizeof(unsigned char));
5. }


I am wondering if I can replace calloc in line 1 by malloc function
and still get a 2D array with all array[i][j]=0.

By the way, I am wondering if malloc will be faster than calloc?

In my understanding, calloc is equivalent to malloc plus zero-
initialization. Therefore calloc may be slower than malloc. Is it
right?

Thanks

 
Reply With Quote
 
 
 
 
Seebs
Guest
Posts: n/a
 
      02-28-2010
On 2010-02-28, MBALOVER <(E-Mail Removed)> wrote:
> I want to create a 2D dynamic array and then initialize all elements
> with 0.


Really?

Hmm.

> I did a search and found:


> 1. array = (** unsigned char) calloc(NROW, sizeof(unsigned char*));


This is clearly incorrect.

> 2. for(i = 0; i < NROW ; i++)
> 3. {
> 4. array[i] = calloc(NCOL, sizeof(unsigned char));
> 5. }


Are NROW and NCOL known values? If they are, then you can do this much more
simply.

> I am wondering if I can replace calloc in line 1 by malloc function
> and still get a 2D array with all array[i][j]=0.


No, because malloc doesn't guarantee initialized memory. In general, you
can't allocate a multidimensional array of unknown size.

> By the way, I am wondering if malloc will be faster than calloc?


Maybe, maybe not.

> In my understanding, calloc is equivalent to malloc plus zero-
> initialization. Therefore calloc may be slower than malloc. Is it
> right?


Maybe. Honestly: You are not at a stage where you should be trying to
figure things like that out. Understand what they do, don't get caught
up trying to figure out what's "faster". Write for clarity and
understanding for now -- you can work on speed once you can make programs
that do what you want them to do.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / http://www.velocityreviews.com/forums/(E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
 
 
 
Ike Naar
Guest
Posts: n/a
 
      02-28-2010
In article <(E-Mail Removed)>,
MBALOVER <(E-Mail Removed)> wrote:
>I want to create a 2D dynamic array and then initialize all elements
>with 0.
>
>I did a search and found:
>
>1. array = (** unsigned char) calloc(NROW, sizeof(unsigned char*));
>
>2. for(i = 0; i < NROW ; i++)
>3. {
>4. array[i] = calloc(NCOL, sizeof(unsigned char));
>5. }
>
>I am wondering if I can replace calloc in line 1 by malloc function
>and still get a 2D array with all array[i][j]=0.


You can; initializing each array[i] with all-bytes-zero in line 1
is not useful since you immediately overwrite each array[i] with a
pointer value in lines 2-5.
In face, even if you wouldn't overwrite each array[i] with a pointer value,
initializing each array[i] with all-bytes-zero would not be very useful,
because all-bytes-zero is not guaranteed to represent a valid pointer.

So I agree that it's better to replace calloc in line 1 by malloc.
 
Reply With Quote
 
Ike Naar
Guest
Posts: n/a
 
      02-28-2010
In article <(E-Mail Removed)>,
Seebs <(E-Mail Removed)> wrote:
>On 2010-02-28, MBALOVER <(E-Mail Removed)> wrote:
>> I want to create a 2D dynamic array and then initialize all elements
>> with 0.

>
>Really?
>Hmm.
>
>> I did a search and found:
>> 1. array = (** unsigned char) calloc(NROW, sizeof(unsigned char*));

>
>This is clearly incorrect.


Why? It looks like mbalover is constructing a "dynamic 2D array"
as an array of pointers, pointing to 1D arrays. What's incorrect
about that? It's a well-known idiom.

>> 2. for(i = 0; i < NROW ; i++)
>> 3. {
>> 4. array[i] = calloc(NCOL, sizeof(unsigned char));
>> 5. }

>
>Are NROW and NCOL known values? If they are, then you can do this much more
>simply.


You mean, like "char array[NROW][NCOL]"? That's indeed a possibility,
but apparently not what mbalover wants (perhaps he wants to be able to
later resize his "dynamic 2D array", something he can't do with a
regular 2D array).

>> I am wondering if I can replace calloc in line 1 by malloc function
>> and still get a 2D array with all array[i][j]=0.

>
>No, because malloc doesn't guarantee initialized memory. In general, you
>can't allocate a multidimensional array of unknown size.


I think you are using the term "multidimensional array" in a too
restrictive way in this context.

>> By the way, I am wondering if malloc will be faster than calloc?

>
>Maybe, maybe not.
>
>> In my understanding, calloc is equivalent to malloc plus zero-
>> initialization. Therefore calloc may be slower than malloc. Is it
>> right?

>
>Maybe. Honestly: You are not at a stage where you should be trying to
>figure things like that out. Understand what they do, don't get caught
>up trying to figure out what's "faster". Write for clarity and
>understanding for now -- you can work on speed once you can make programs
>that do what you want them to do.


Agreed; the speed difference between calloc and malloc (if there is one,
and if it is measurable) is probably the last thing to worry about.
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      02-28-2010
(E-Mail Removed) (Ike Naar) writes:

> In article <(E-Mail Removed)>,
> Seebs <(E-Mail Removed)> wrote:
>>On 2010-02-28, MBALOVER <(E-Mail Removed)> wrote:

<snip>
>>> I did a search and found:
>>> 1. array = (** unsigned char) calloc(NROW, sizeof(unsigned char*));

>>
>>This is clearly incorrect.

>
> Why? It looks like mbalover is constructing a "dynamic 2D array"
> as an array of pointers, pointing to 1D arrays. What's incorrect
> about that?


It has a syntax error. (** unsigned char) is not a valid cast operator.

<snip>
--
Ben.
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      02-28-2010
MBALOVER <(E-Mail Removed)> writes:

> I want to create a 2D dynamic array and then initialize all elements
> with 0.


This is a FAQ: http://c-faq.com/aryptr/dynmuldimary.html

I like the second suggested method, though I tend to write it like this:

if (ptrs = malloc(NROWS * sizeof *ptrs))
if (ptrs[0] = malloc(NCOLS * NROWS * sizeof *ptrs[0]))
for (int r = 1; r < NROWS; r++)
ptrs[r] = &ptrs[r - 1][NCOLS];
else free(ptrs);

where 'ptrs' is of type T ** for some type T. Using only two malloc
calls make checking and freeing simpler.

> I am wondering if I can replace calloc in line 1 by malloc function
> and still get a 2D array with all array[i][j]=0.


To get a zero-initialised array insert a memset call in the inner if:

if (ptrs[0] = malloc(NCOLS * NROWS * sizeof *ptrs[0])) {
memset(ptrs[0], 0, NCOLS * NROWS * sizeof *ptrs[0]);
for (int r = 1; r < NROWS; r++)
ptrs[r] = &ptrs[r - 1][NCOLS];
}
else free(ptrs);

but this is only guaranteed to work for integer types (though it is
highly likely to work for floating-point types and pointer types).

By the way, if you really do need a 2D array of char (as in your
example) then you can use only one malloc call if you want since char
needs no special alignment.

<snip>
--
Ben.
 
Reply With Quote
 
Ersek, Laszlo
Guest
Posts: n/a
 
      02-28-2010
In article <(E-Mail Removed)>, MBALOVER <(E-Mail Removed)> writes:
> HI all,
>
> I want to create a 2D dynamic array and then initialize all elements
> with 0.


Ignoring the initialization for a second (because you didn't specify the
element type), I think that the following enables the most flexible
usage, if your rows are all full:

#include <stdlib.h>

type *
get_type2d(size_t rows, size_t cols)
{
return (0u < cols && (size_t)-1 / sizeof(type) / cols >= rows)
? malloc(rows * cols * sizeof(type))
: 0;
}

You would index the allocated array like this:

{
type *arr;

arr = get_type2d(nrows, ncols);
if (0 != arr) {
/* Store ... in array[row][col], conceptually. */
arr[row * ncols + col] = ...;

free(arr);
}
}


This can be generalized for N dimensional arrays. The following function
takes "long unsigned" arguments instead of "size_t", because "size_t"
may be promoted by the default argument promotions, and that doesn't
play very well with va_arg().

#include <stdlib.h>
#include <stdarg.h>

/*
Usage:

get_ndim(el_size, dim_1, dim_2, ..., dim_n, 0LU);

Allocate memory for dim_1 * dim_2 * ... * dim_n elements, each being
of size "el_size". All arguments must be of type "long unsigned". The
variable argument list must be terminated with 0LU.

get_ndim(el_size, 0LU)

allocates a zero-dimensional array (= space for a single element).

The caller is responsible for not passing 0LU as el_size.

The function returns a pointer returned by malloc() (which can be 0),
or 0 if the wanted size (in bytes) cannot be represented in size_t.
*/

void *
get_ndim(long unsigned el_size, ...)
{
size_t max_el,
num_el;
va_list ap;
long unsigned next;

max_el = (size_t)-1 / el_size;
num_el = 1u;

va_start(ap, el_size);
while (0LU != (next = va_arg(ap, long unsigned))
&& max_el / next >= num_el) {
num_el *= next;
}
va_end(ap);

return 0LU == next ? malloc(num_el * el_size) : 0;
}


The access pattern implements the Horner scheme.

http://en.wikipedia.org/wiki/Horner_scheme

An example for the Horner scheme with auto arrays might be:

{
type arr[4][5][6]; /* 120 */

arr[1][2][3] = ...; /* [1 * (5*6) + 2 * (6) + 3], [45] */
}

-->

{
type arr[4 * (5 * (6))]; /* 120 */

arr[(1 * 5 + 2) * 6 + 3] = ...; /* [45] */
}


Thus

/*
If arr denotes the non-null return value of

get_ndim(el_size, dim_1, ... dim_n, 0LU)

that is, arr is conceptually

array[dim_1][dim_2] ... [dim_n]

then the conceptual element with valid subscripts

array[i_1][i_2] ... [i_n]

can be accessed with

arr[get_idx(i_1, dim_2, i_2, ..., dim_n, i_n, 0LU)]

For zero-dimensional arrays, the following is valid:

get_ndim(el_size, 0LU)[get_idx(0LU, 0LU)]

*/

size_t
get_idx(long unsigned outermost_idx, ...)
{
size_t sum;
va_list ap;
long unsigned next_size;

sum = outermost_idx;
va_start(ap, outermost_idx);
while (0LU != (next_size = va_arg(ap, long unsigned))) {
sum = sum * next_size + va_arg(ap, long unsigned);
}

return sum;
}


Usage:

int main(void)
{
double *mtr;

/* allocate 100 4x4 matrices */
mtr = get_ndim(sizeof *mtr, 100LU, 4LU, 4LU, 0LU);
if (0 != mtr) {

/* Set the 59th matrix to 0.0 -- starting at &matrix[58][0][0]. */
size_t base,
idx;
base = get_idx(58LU, 4LU, 0LU, 4LU, 0LU, 0LU);
for (idx = 0u; idx < 16u; ++idx) {
mtr[base + idx] = 0.0;
}

free(mtr);
}
return 0;
}


Cheers,
lacos
 
Reply With Quote
 
Ersek, Laszlo
Guest
Posts: n/a
 
      02-28-2010
In article <kxoxF7laR3mK@ludens>, (E-Mail Removed) (Ersek, Laszlo) writes:

> size_t
> get_idx(long unsigned outermost_idx, ...)
> {
> size_t sum;
> va_list ap;
> long unsigned next_size;
>
> sum = outermost_idx;
> va_start(ap, outermost_idx);
> while (0LU != (next_size = va_arg(ap, long unsigned))) {
> sum = sum * next_size + va_arg(ap, long unsigned);
> }
>
> return sum;
> }


Obviously, I forgot va_end(ap) before returning.

Sorry,
lacos
 
Reply With Quote
 
Malcolm McLean
Guest
Posts: n/a
 
      02-28-2010
On Feb 28, 5:46*pm, (E-Mail Removed) (Ersek, Laszlo) wrote:
>
> This can be generalized for N dimensional arrays. The following function
> takes "long unsigned" arguments instead of "size_t", because "size_t"
> may be promoted by the default argument promotions, and that doesn't
> play very well with va_arg().
>

Ho ho, hadn't thought of that. Neither, I bet, had the committee.
size_t introduces all sorts of subtle difficulties.


 
Reply With Quote
 
Ersek, Laszlo
Guest
Posts: n/a
 
      02-28-2010
In article <(E-Mail Removed)>, Malcolm McLean <(E-Mail Removed)> writes:
> On Feb 28, 5:46=A0pm, (E-Mail Removed) (Ersek, Laszlo) wrote:
>>
>> This can be generalized for N dimensional arrays. The following function
>> takes "long unsigned" arguments instead of "size_t", because "size_t"
>> may be promoted by the default argument promotions, and that doesn't
>> play very well with va_arg().
>>

> Ho ho, hadn't thought of that. Neither, I bet, had the committee.


I'm sure they did; after all, C99 has %z. Since any specific
implementation of the standard library knows intimately what size_t is
promoted to (if at all), they can use the promoted type in va_arg() in
the implementation of *printf().

Granted, if one wishes to take size_t's through the ellipsis in a
portable function, he/she has to transfer "long unsigned"'s instead --
in C90.

In C99, the previous paragraph works with s/long unsigned/uintmax_t/g,
but I think there is also a chance to figure out the type size_t is
promoted to -- C99 has SIZE_MAX.

(I wouldn't try it, though, with padding bits and whatnot )

Cheers,
lacos
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Is there a better and fast way to initialize a dynamic array? jerry C Programming 13 10-01-2011 12:49 PM
How do you initialize signals in VHDL? Madhu VHDL 7 05-28-2008 06:43 PM
if instance variable get initialize after assigning some values or after constructor then when does static variable get initialize Tony Morris Java 3 02-04-2006 08:39 AM
initialize memory units Daniel Koethe VHDL 1 11-08-2004 08:36 PM
Initialize dynamic controls on postback Mark Miller ASP .Net 1 07-30-2003 06:00 PM



Advertisments