about the array

G

Guest

I'm confused about the VARIABLE LENGTH ARRAYS.
{scanf("%d",&n);float a[n];}
In which compiler can I use it?
I tried VC++6.0 SP6,but it's reported error:CONSTANT EXPRESSION!

Another question,
What the differences between:
(1)ElemType array[N]
(2)array=(ElemType*)malloc(N*size of(ElemType))
or array=(ElemType*)calloc(N,size of(ElemType))
<Of course,you can change the N in (2) into a VAR>
I just think they're almost the same.But...ther must be some
differences,not just the type of writting...
(By the way,my English is not very good.I hope that the above have
expressed my ideas without confusions!)
Thank you!谢谢(In Chinese)
 
K

Keith Thompson

Yuri_ÎàØÙ said:
I'm confused about the VARIABLE LENGTH ARRAYS.
{scanf("%d",&n);float a[n];}
In which compiler can I use it?
I tried VC++6.0 SP6,but it's reported error:CONSTANT EXPRESSION!

Variable length arrays are a new feature in C99; the earlier C90
standard doesn't support them. gcc supports them; apparently
your compiler doesn't.
Another question,
What the differences between:
(1)ElemType array[N]
(2)array=(ElemType*)malloc(N*size of(ElemType))
or array=(ElemType*)calloc(N,size of(ElemType))

You declared "array" as an array. malloc() and calloc() both returns
a pointer values, so your code is illegal. (You may have heard that
arrays are really pointers in C; they're not.) See section 6 of the
comp.lang.c FAQ, <http://www.c-faq.com/>.

Here's a legal version of what you wrote:

ElemType *ptr;
ptr = malloc(N * sizeof(ElemType));
/* or */
ptr = calloc(N, sizeof(ElemType));

The difference is that calloc initializes the allocated memory to
all-bits-zero. This is not as useful as you might think;
floating-point 0.0 and null pointer values aren't necessarily
represented as all-bits-zero.

Note: you should never cast the result of malloc() or calloc(). Doing
so can mask errors. Make sure you have a "#include <stdlib.h>".
Also, the following is actually less error-prone than what I wrote
above:

ElemType *ptr;
ptr = malloc(N * sizeof *ptr);
/* or */
ptr = calloc(N, sizeof *ptr);
 
R

Rajesh

Hello Keith,

"Note: you should never cast the result of malloc() or calloc(). Doing

so can mask errors."

AFAIK both them return void pointers which must be casted appropiately
before assigning.

Why should we never cast them and if we do what errors can come.

Regards,
Rajesh
 
P

Peter Nilsson

Rajesh said:
Hello Keith,

"Note: you should never cast the result of malloc() or calloc(). Doing
so can mask errors."

AFAIK both them return void pointers
Yes.

which must be casted appropiately before assigning.

No. The whole point of void * in C is that it (generally) doesn't
need to be cast to other pointer types.
Why should we never cast them and if we do what errors can come.

http://benpfaff.org/writings/clc/malloc-cast.html.
 
R

Rajesh

Hello Peter,

Thanks for the explanations.

Can u put some light on :

"Casting its return value can mask a failure to #include <stdlib.h>,
which leads to undefined behavior"

What type of failure is it?

"C99 requires all functions to be declared before they are called."

Does C89 doesn't requires that?

Rajesh
 
K

Keith Thompson

Rajesh said:
Can u put some light on :

"Casting its return value can mask a failure to #include <stdlib.h>,
which leads to undefined behavior"

What type of failure is it?

"C99 requires all functions to be declared before they are called."

Does C89 doesn't requires that?

Please read <http://cfaj.freeshell.org/google/>. Google is giving you
a badly distorted view of Usenet; that web page explains how to work
around it.

Please don't use abbreviations like "u" for "you". They make it much
more difficult to read what you write.

C89/C90 allows functions to be called without a visible declaration,
though it's a very bad idea. An undeclared function is assumed to
return int and take an unknown number and type of arguments. So, for
example, given:

void *ptr;
ptr = malloc(100);

if the declaration of malloc() isn't visible, the compiler assumes
(incorrectly) that it returns int, and you'll get a warning about a
type mismatch, attempting to assign an int to a void*. If you
give in to temptation and use a cast:

void *ptr;
ptr = (void*)malloc(100);

you haven't fixed the problem. The compiler *still* incorrectly
assumes that malloc() returns an int; you've told it to convert that
bogus int to void*. The result of the conversion won't necessarily be
the void* value that malloc() *tried* to return. This invokes
undefined behavior, which means anything can happen; it can work
correctly, it can crash your program, or (as the standard joke here
goes), it can make demons fly out of your nose.

So drop the cast and add the required "#include <stdlib.h>", and
everything works consistently. (And don't forget to check the result
of malloc(); if it fails, it returns a null pointer.)
 
P

pemo

Rajesh said:
Hello Peter,

Thanks for the explanations.

Can u put some light on :

"Casting its return value can mask a failure to #include <stdlib.h>,
which leads to undefined behavior"

What type of failure is it?

"C99 requires all functions to be declared before they are called."

Does C89 doesn't requires that?

Rajesh

What type of failure is it?

Disclaimer:

I guess the bottom line is - if the cast isn't necessary, why do it, esp. if
there exists some compiler, in the set of all compilers, that will screw up
if you do!

---

Taking the reasons from the webpage cited ...

1- The cast is not required in ANSI C.

2- Casting its return value can mask a failure to #include <stdlib.h>, which
leads to undefined behavior. As C99 slows[sic] becomes more popular, this
will become less of an issue, because C99 requires all functions to be
declared before they are called.

3- If you cast to the wrong type by accident, odd failures can result. This
is especially true if <stdlib.h> is not #included, as above, but alignment
can still cause trouble on particularly odd systems.

1. True - see the disclaimer.

2. IMHO, not likely ... in so far that if you used another function declared
in stdlib, you'd most likely get a warning about *its* use [unless it obeys
the default rules - in which case it's ok] - even if you somehow managed to
escape such a warning about misusing malloc. Esp. not likely to be an issue
when it's mandatory to have declared a function before using it of course.

3.

I think the argument is that *if* you cast wrongly, you could end up in
trouble. E.g., say you had this ...

char * p = (char)malloc(10);

Maybe p will only get CHAR_BIT's worth of data assigned to it [which you
probably don't want right]?

By including stdlib, the compiler should issue a diagnostic - gcc gives:
'cast from pointer to integer of different size'.

However, if you cast \correctly\, but omit stdlib, then the compiler may
make assumptions about what malloc \is\ [how to call/return a value from
it], and screw up, e.g., without the declaration, the compiler *should*
consider malloc to have external linkage, take an unknown set of arguments,
and return an int. So, if you have this usage - which is legal according to
those rules ...

void * p = (void *)malloc(10);

Well, maybe the int taken [off the stack or wherever it comes from] by the
compiler isn't *right* for a void *.

*However*, that all said, in my experience, compilers will typically tell
you that you haven't declared malloc before using it - with/without the
cast. For example, if you have either of these in gcc code ...

char * p = (char *)malloc(10);
char * p = (char)malloc(10);

You'll see warnings like this ...

"implicit declaration of function 'malloc'"
"incompatible implicit declaration of built-in function 'malloc'"
"cast from pointer to integer of different size"
"assignment makes pointer from integer without a cast"

So, if you then include stdlib, the second of those usages [the cast to
(char)] will once again cause gcc to issue the pointer to integer warning
again.

IMHO, most modern compilers would catch misuses, even if the sizes of a void
* and the lvalue are the same - but of diferent types. For example:

If an int is the same size as a void *, and you have this, and no #include
<stdlib.h> ...

int * p = (int)malloc(10);

Most compilers will complain along these lines ...

"assignment makes pointer from integer without a cast"

How about if you do this - where you're casting the return type to the
lvalue type ...

int p = (int)malloc(10);

"implicit declaration of function 'malloc'"
"incompatible implicit declaration of built-in function 'malloc'"

Re gcc, the 'built-in' part of this is interesting - because gcc obviously
*knows* about malloc, as demonstrated by, say, doing this [With *no* headers
included]:

int p;

p = (int)malloc();

gcc says:

"too few arguments to function 'malloc'"

So, switching to another - less smart - compiler, I get this:

'malloc' undefined; assuming extern returning int

And - to another - I get this :

Missing prototype for 'malloc'

So, in summary - IMHO

1. True - don't cast.
2. Hmmm.
3. if there exists some compiler, in the set of ... You can bet there is
more than one of course!
 
P

Peter Nilsson

pemo said:
Taking the reasons from the webpage cited ...
[i.e. said:
1- The cast is not required in ANSI C.

2- Casting its return value can mask a failure to #include <stdlib.h>,
which leads to undefined behavior. As C99 slows[sic] becomes more
popular, this will become less of an issue, because C99 requires all
functions to be declared before they are called.

3- If you cast to the wrong type by accident, odd failures can result.
This is especially true if <stdlib.h> is not #included, as above, but
alignment can still cause trouble on particularly odd systems.

1. True - see the disclaimer.

2. IMHO, not likely ... in so far that if you used another function
declared in stdlib, you'd most likely get a warning about *its* use

Quite often in my code, the _only_ functions being used from <stdlib.h>
are malloc and free. I don't always use the NULL macro, but when I do
it's often available from other headers (e.g. <stdio.h>.)

A call to an implicitly declared free() does not require a diagnostic.
[unless it obeys the default rules - in which case it's ok] - even
if you somehow managed to escape such a warning about misusing
malloc. Esp. not likely to be an issue when it's mandatory to have
declared a function before using it of course.

It isn't mandatory in C90! That's the whole point!!

Personally, I think it's fair to say that most compiler writers
appreciate the problems with using undeclared functions, so most
compilers will issue a diagnostic, but the C90 language itself
does not _require_ compilers to do so. [And there are plenty of
old compilers that won't issue a warning, let alone an error.]
3.

I think the argument is that *if* you cast wrongly, you could end up
in trouble. E.g., say you had this ...

char * p = (char)malloc(10);

That requires a diagnostic too because you're assigning an integer
value to a pointer without a cast (from int to pointer.) To be honest,
I'm not exactly sure what Ben is talking about in point 3.
Maybe p will only get CHAR_BIT's worth of data assigned to it [which
you probably don't want right]?

By including stdlib, the compiler should issue a diagnostic - gcc
gives: 'cast from pointer to integer of different size'.

Yes, it's a _required_ diagnostic, so _every_ conforming compiler
must issue a warning or error.
However, if you cast \correctly\, but omit stdlib, then the compiler
may make assumptions about what malloc \is\ [how to call/return a
value from it], and screw up, e.g., without the declaration, the
compiler *should* consider malloc to have external linkage, take an
unknown set of arguments, and return an int. So, if you have this
usage - which is legal according to those rules ...

void * p = (void *)malloc(10);

It is not legal since malloc returns a void *, not an int. The code
is no different to...

/* no #include <stdlib.h> */
int malloc();

void foo()
{
/* UB since malloc has the wrong signature */
void *p = (void *) malloc(10);
...
Well, maybe the int taken [off the stack or wherever it comes from]
by the compiler isn't *right* for a void *.

Indeed. It may be the wrong size, or may be in a completely different
register. [For example, Motorola's 68000 series has both data and
address registers. Many implementations will return an int in register
D0, and a pointer in register A0. Without a valid declaration, a
compiler may assume malloc's return value is in D0, instead of A0.
Thus, it may use a garbage value totally unrelated to the malloc()
call.]
*However*, that all said, in my experience, compilers will typically
tell you that you haven't declared malloc before using it - with/
without the cast.

I agree, but the issue is not about what _most_ compilers will or
won't do. [Or what most programmers _should_ be doing: turn on the
warning if available.] It's about whether compilers are _required_
to issue diagnostics, be they warnings or errors.

If an int is the same size as a void *, and you have this, and no
#include <stdlib.h> ...

int * p = (int)malloc(10);

Most compilers will complain along these lines ...

"assignment makes pointer from integer without a cast"

Yes, but you clearly don't understand _why_ the compiler is
_required_ to issue the diagnostic. It's to do with assignment.
The situation is identical to...

int *p = 0xFFFE;

I don't think that even the regulars of clc would accuse newbies of
commonly casting malloc to int.
How about if you do this - where you're casting the return type to
the lvalue type ...

int p = (int)malloc(10);

This doesn't require a diagnostic, but you now have implementation
defined behaviour (if you include a prototype for malloc.) Any
subsequent conversion of that int to a void *, e.g. ...

void *vp = (void *) p;

....need _not_ yield the original pointer returned by malloc(),
irrespective of whether int is wider than void * or not.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,176
Messages
2,570,948
Members
47,500
Latest member
ArianneJsb

Latest Threads

Top