[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c

Allocating multi-dim'l arrays

Jack

7/12/2011 9:06:00 PM

Hello. I have a few questions about allocating memory to a 32k (approx)
character buffer declared as:

char string [415] [78];

To be more precise, it's a multidimensional array that is my memo
body for a messaging system I am writing. 415 lines by 78 characters,
yields about 31.9k. Therefore, is the following malloc statement correct?

if ((string[215][0] = (char)malloc(32000)) == NULL);

I'm 99% sure its wrong. It compiles OK and when I increase
malloc's argument, the execution seems to fail - which is what I expect.

Thank's for any and all of your time.
8 Answers

Ben Bacarisse

7/12/2011 10:04:00 PM

0

Jack <spamtrap@trashcan.invalid> writes:

> Hello. I have a few questions about allocating memory to a 32k (approx)
> character buffer declared as:
>
> char string [415] [78];
>
> To be more precise, it's a multidimensional array that is my memo
> body for a messaging system I am writing. 415 lines by 78 characters,
> yields about 31.9k. Therefore, is the following malloc statement correct?
>
> if ((string[215][0] = (char)malloc(32000)) == NULL);
>
> I'm 99% sure its wrong.

The good news is that you are 100% right -- it's wrong!

A good place to start is the C FAQ, specifically question 6.16:
http://c-faq.com/aryptr/dynmuld...

To address a few point here... The declaration you wrote is enough,
there is no need to allocate any more memory. I.e.

char string[415][78];

makes "string" (an odd name for such a thing) exactly what you say you
want. However, you should ask yourself if you really, really want that.
What are you going to do with the data? Will having it in such a
fixed-size array help or hinder that? I can't tell because there is
very little to go on, but my suspicion is that it won't help much and
may well be a hindrance.

<snip>
--
Ben.

John Gordon

7/12/2011 10:20:00 PM

0

In <ivicuv$302$1@speranza.aioe.org> Jack <spamtrap@trashcan.invalid> writes:

> Hello. I have a few questions about allocating memory to a 32k (approx)
> character buffer declared as:

> char string [415] [78];

> if ((string[215][0] = (char)malloc(32000)) == NULL);

> I'm 99% sure its wrong. It compiles OK and when I increase
> malloc's argument, the execution seems to fail - which is what I expect.

Yes, it's wrong. string is already fully allocated; there's no need to
call malloc at all. it already has the full 415 * 78 char storage amount.

If string were declared like this:

char **string;

Or this:

char *string[415];

Then you would need to call malloc to allocate space for the character
pointers, as they don't point anywhere. But since you declared string
as a fully-formed array, there's no need to call malloc at all.

(By the way, "string" isn't such a good name choice for a variable.)

--
John Gordon A is for Amy, who fell down the stairs
gordon@panix.com B is for Basil, assaulted by bears
-- Edward Gorey, "The Gashlycrumb Tinies"

jt

7/12/2011 10:21:00 PM

0

Jack <spamtrap@trashcan.invalid> wrote:
> Hello. I have a few questions about allocating memory to a 32k (approx)
> character buffer declared as:

> char string [415] [78];

This already gives you a 2-dimensional array with 415x78 bytes
of memory assigned to it. So there actually is no need at all
for allcation.

> To be more precise, it's a multidimensional array that is my memo
> body for a messaging system I am writing. 415 lines by 78 characters,
> yields about 31.9k. Therefore, is the following malloc statement correct?

> if ((string[215][0] = (char)malloc(32000)) == NULL);

> I'm 99% sure its wrong. It compiles OK

This is about as wrong as you can get;-) And it compiles "OK"
only because you silenced the compiler by a cast. I also guess
that the '215' above actually was meant to be '415'. Now if
you do

string[415][0] = (char)malloc(32000)

then several bad things happen. First of all you assign to an
element with indices 415,0 of the 2-dimensional array. That's
an element that is past the end of that array, which already
leads to undefined behaviour. And what you assign to it is
the value that results when you convert an address (that you
received from malloc() to a character value. So, if the address
was e.g. x0x7F265A25 then its conversion to a char value is
probably something like 0x25 (in ASCII the equivalent of the
'%' character) and that's what you're assigning.

None of this obviously is what you planned to do here. First
of all, you already have defined an 2-dimensional array named
'string' with the size you seem to need. And by defining the
array you already made the compiler take care of organizing
the required memory. So there's no point at all in allocating
further memory - you already got all you will ever need with
that array.

And since an array already comes with all the memory needed
you can't assign memory to it. All you can do is assign to
its elements. That's what you did above. And that's also why
you thought you had to add a cast - without it the compiler
would rather likely have grumbled about you trying to assign
a void pointer to something that's a char (assuming that you
have included <stdlib.h> which has the declaration of the
malloc() function, which in turn tells the compler that
malloc returns a void pointer). The cast just kept the com-
piler from telling you about the problem.

I don't know what your intentions actually are and if you
really want to dynamically allocate memory or if having a
finished-for-use array isn't already all you need. If you
want to work with allocated memory for some reasons (e.g.
because you don't know in advance how many lines there will
be needed to be stored or how long the lines will be) then
you will have to work with pointers or arrays of pointers
and assign what malloc() returns to these pointers.

E.g., if the line length is not known in advance but you
know that you'll never need nore than 415 lines you might
do

char *strings[ 415 ];
for ( size_t i = 0; i < 415; ++i )
strings[ i ] = malloc( MAX_STRING_LENGTH );

That would give you an array of 415 char pointers, with
each of them initialized to point to memory for
'MAX_STRING_LENGTH' chars, i.e. each could hold a line
with a length of up to 'MAX_STRING_LENGTH-1' chars (plus
the trailing '\0' character at the end of the string).

Or, if don't know the number of lines nor the lengths
of the lines in advance, one thing you might do is

char ** strings = malloc( NUM_STRINGS * sizeof *strings );
for ( size_t i = 0; i < NUM_STRINGS; ++i )
strings[ i ] = malloc( MAX_STRING_LENGTH );

to get memory for NUM_STRINGS char pointers that in turn
get initilized to point to memory for 'MAX_STRING_LENGTH'
chars.

Of course, there are lots of further variations. If you
tell a bit more about what you want to do it's going to
be easier to come up with a reasonable way to dynamically
allocate the required memory (if that is necessary at all).

Regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\__________________________ http://t...

pete

7/12/2011 11:28:00 PM

0

Jack wrote:
>
> Hello. I have a few questions about allocating memory to a 32k (approx)
> character buffer declared as:
>
> char string [415] [78];
>
> To be more precise, it's a multidimensional array that is my memo
> body for a messaging system I am writing. 415 lines by 78 characters,
> yields about 31.9k.
> Therefore, is the following malloc statement correct?
>
> if ((string[215][0] = (char)malloc(32000)) == NULL);
>
> I'm 99% sure its wrong. It compiles OK and when I increase
> malloc's argument,
> the execution seems to fail - which is what I expect.
>
> Thank's for any and all of your time.

I'm going to interpret your question to mean
"How do I allocate a 2 dimensional array
for 415 lines by 78 characters?"

/* BEGIN new.c */

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

#define LINES 415
#define CHARACTERS 78

int
main(void)
{
int n;
char (*string)[CHARACTERS];

string = malloc(LINES * sizeof *string);
puts("\n/* BEGIN new.c output */\n");
if (string != NULL) {
for (n = 0; n != LINES; ++n) {
sprintf(string[n], "Line%69c%d\n", ' ', n);
}
for (n = 0; n != LINES; ++n) {
fputs(string[n], stdout);
}
} else {
puts("string == NULL");
}
puts("\n/* END new.c output */");
return 0;
}

/* END new.c */

--
pete

Malcolm McLean

7/13/2011 7:26:00 AM

0

On Jul 13, 12:05 am, Jack <spamt...@trashcan.invalid> wrote:
> Hello. I have a few questions about allocating memory to a 32k (approx)
> character buffer declared as:
>
>         char string [415] [78];      
>
Multi-dimensional arrays are basically broken in C.

You can declare a 2d array of size fixed at compile time, but you
almost never want to do that. Normally you want to allocate
dynamically. If the x dimension is known, it can be done, but the
syntax is so strange as to make the program unreadable. If you know
neither dimension, it can't be done.

The simple answer is to allocate the array uing the expression ptr =
malloc(width * height * sizeof(type));
Then address each element ptr[y * width + x].

However with arrays of strings, you almost always want to declare the
array as a char **, and allocate the array itself dynamically and all
the strings individually, and also dynamically.

--
Vist my website
http://www.malcolmmclean.site...

Ben Bacarisse

7/13/2011 12:06:00 PM

0

Malcolm McLean <malcolm.mclean5@btinternet.com> writes:

> On Jul 13, 12:05 am, Jack <spamt...@trashcan.invalid> wrote:
>> Hello. I have a few questions about allocating memory to a 32k (approx)
>> character buffer declared as:
>>
>>         char string [415] [78];      
>>
> Multi-dimensional arrays are basically broken in C.
>
> You can declare a 2d array of size fixed at compile time, but you
> almost never want to do that. Normally you want to allocate
> dynamically. If the x dimension is known, it can be done, but the
> syntax is so strange as to make the program unreadable. If you know
> neither dimension, it can't be done.

[I assume you mean "know at compile-time" rather than "know". If you
don't know either size of the array even at run-time you can't do much
at all, including your proposal here:]

> The simple answer is to allocate the array uing the expression ptr =
> malloc(width * height * sizeof(type));

To the OP: if you want to try this unreadable syntax for something that
can't be done, try this:

type (*dynamic_array)[width] = malloc(sizeof(type[height][width]));

or if you want to use the common malloc idiom that avoids repeating the
type (and in this case, also the width):

type (*dynamic_array)[width] = malloc(height * sizeof *dynamic_array);

> Then address each element ptr[y * width + x].

which you can now address like this:

dynamic_array[y][x]

You can even pass these things to functions that can deal with arrays of
arbitrary dimensions.

This needs C99's variably modified arrays which is presumably what
Malcolm McLean was taking about when he said it can't be done. You
can't do the above in C90.

<snip>
--
Ben.

Francois Grieu

7/13/2011 1:45:00 PM

0

On 2011/07/13 09:26, Malcolm McLean wrote :
> (..) allocate the array using the expression
> ptr = malloc(width * height * sizeof(type));

Watch for overflow of width * height, or use
ptr = malloc( width * sizeof(type) * height );


> Then address each element ptr[y * width + x].

Again watch for overflow or use
ptr[y * (size_t)width + x]


Francois Grieu

Keith Thompson

7/13/2011 4:32:00 PM

0

Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
> On Jul 13, 12:05 am, Jack <spamt...@trashcan.invalid> wrote:
>> Hello. I have a few questions about allocating memory to a 32k (approx)
>> character buffer declared as:
>>
>>         char string [415] [78];      
>>
> Multi-dimensional arrays are basically broken in C.
>
> You can declare a 2d array of size fixed at compile time, but you
> almost never want to do that. Normally you want to allocate
> dynamically. If the x dimension is known, it can be done, but the
> syntax is so strange as to make the program unreadable. If you know
> neither dimension, it can't be done.
>
> The simple answer is to allocate the array uing the expression ptr =
> malloc(width * height * sizeof(type));
> Then address each element ptr[y * width + x].
>
> However with arrays of strings, you almost always want to declare the
> array as a char **, and allocate the array itself dynamically and all
> the strings individually, and also dynamically.

Or just allocate a one-dimensional array and store the entire
message as a single string. The OP said that the array is intended
to hold a memo for a messaging system, consisting of 415 lines of
78 characters each. It's very likely that storing the memo as a
single string, with line endings marked by '\n' characters, will
work better. It also lets you relax the line length restriction
if you're so inclined. And if you allocate the array dynamically,
base on the actual size of the memo, hou can avoid wasting a lot
of memory.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.ne...
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"