Discussion:
Why manually allocating memory instead of standard stack memory?
(too old to reply)
Omar Radwan
2014-07-18 02:33:19 UTC
Permalink
I'm a beginner C programmer, it's my first programming language. Honestly, I think I chose the right language. All the other languages have something that I don't agree with. But a programming concept that makes me wonder is why someone might do this:

int arr[] = malloc((sizeof(int)) * 8);


instead of :

int arr[8];


or even with structs:

typedef struct Person
{
int age;
float height;
float weight;
char name[];
};

struct Guy Bobby = malloc(sizeof(Guy))

when someone could just call it in as

struct Guy Bobby;
glen herrmannsfeldt
2014-07-18 02:58:51 UTC
Permalink
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming language.
Honestly, I think I chose the right language. All the other
languages have something that I don't agree with.
But a programming concept that makes me wonder is why someone
int arr[] = malloc((sizeof(int)) * 8);
int arr[8];
You are likely to get a lot of replies to this, but, so far, it looks
like I am the first.

It isn't always so obvious, but somewhat generally, is the former
when 8 is large, and the latter when it is small. But 8 is never large.
(If it is n, and n is not constant or n might be large, use the former.)

But there are some more differences. For one, in the

int arr[8];

case, the array is on the stack, or otherwise deallocated when
the function returns. (That doesn't matter in main.)

And there is also a third case that you didn't mention:

static int arr[8];

In this case, it is allocated only once, and stays allocated even
if the function returns.

And actually, your first once should be:

int *arr = malloc((sizeof(int)) * 8);

-- glen
Kaz Kylheku
2014-07-18 03:18:57 UTC
Permalink
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming language. Honestly, I
think I chose the right language. All the other languages have something that
I don't agree with. But a programming concept that makes me wonder is why
int arr[] = malloc((sizeof(int)) * 8);
This is invalid; it must be

int *arr = malloc(sizeof(int) * 8);

arrays cannot be assigned.
Post by Omar Radwan
int arr[8];
If this "int arr[8]" is at file scope, then you have only one instance of it,
whereas each successful execution of malloc creates a new object.

If this "int arr[8]" is at block scope, then its lifetime is tied to the
activation of that block; when the block terminates, then the object
disappears. The object which came from malloc persists until it is explicitly
destroyed.

A C-like language could conceal the difference between these two, by allowing
local arrays to be passed out of blocks, and providing some way to deal
with deallocation (providing garbage collection, or imposing the rule that
local objects which escape from a block must be explicitly liberated with the
free function.)

C hasn't taken on this design choice. Probably because garbage collection is
a foreign concept in the C culture, regarded as slow, nondeterministic, and
an unnecessary burden in small systems.

Allowing local objects to be returned from blocks, but then requiring them to
be explicitly freed would create a burden on the compiler to determine which
objects "escape" and which do not. The rules would have to be precise,
because programmers would have to know which objects must be freed and which
must not. This is not easy for a compiler to know.

For instance:

{
int arr[8];
external_function(arr);
}
/* should arr be automatically destroyed here, or is it someone else's
* responsibility? */

We don't know whether external_function has only "borrowed" the pointer
for the duration of the call or whether it has "stashed" the pointer in
some global variable, so that it can be used later by some piece of code,
long after the above block has terminated. Since C is compiled in separate
translation units, and is widely implemented in toolchains that have very
simple object file formats, the problem of determining escaping objects is not
solvable.

Compilers for Lisp and related languages solve the escape problem, but
imperfectly so, as an optimization. They fall back on garbage collection to
clean up.
Post by Omar Radwan
struct Guy Bobby = malloc(sizeof(Guy))
This is also incorrect; malloc returns a pointer and so this must be corrected
to:

struct Guy *Bobby = malloc(sizeof (Guy));
Ike Naar
2014-07-18 05:21:19 UTC
Permalink
Post by Kaz Kylheku
Post by Omar Radwan
struct Guy Bobby = malloc(sizeof(Guy))
This is also incorrect; malloc returns a pointer and so this must be corrected
struct Guy *Bobby = malloc(sizeof (Guy));
Sorry for picking nits, but it must be corrected to

struct Guy *Bobby = malloc(sizeof (struct Guy));

or, alternatively,

struct Guy *Bobby = malloc(sizeof *Bobby);
Richard Heathfield
2014-07-18 03:34:39 UTC
Permalink
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming language. Honestly,
I think I chose the right language. All the other languages have something
that I don't agree with. But a programming concept that makes me wonder is
int arr[] = malloc((sizeof(int)) * 8);
As has already been noted, this should be int *arr, not int arr[]

More generally (and more robustly):

T *p = malloc(n * sizeof *p); for any object type T.
Post by Omar Radwan
int arr[8];
What if you don't know in advance how many you want?
Post by Omar Radwan
typedef struct Person
{
int age;
float height;
float weight;
char name[];
};
struct Guy Bobby = malloc(sizeof(Guy))
when someone could just call it in as
struct Guy Bobby;
Well, you have a few syntax issues there. If we leave those aside for now
and also skip lightly around the "struct hack" (which some would argue is an
excellent reason for doing the above), you're right - there isn't really
much point, at least not at a beginner level.

The big win for malloc is when you don't know in advance how many members of
an array you are going to need, and/or when you need to be able to hang on
to the array even after the control flow has the function in which it was
created.

I think it would be quite a challenge to write a large non-trivial program
without resorting to malloc (or its cousins calloc and realloc) at some
point.

Using malloc correctly is in itself non-trivial. Step 1 is to become
completely and utterly familiar with pointers. Until you understand
pointers, malloc is never going to make much sense to you.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
James Kuyper
2014-07-18 12:10:21 UTC
Permalink
Post by Richard Heathfield
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming language. Honestly,
I think I chose the right language. All the other languages have something
that I don't agree with. But a programming concept that makes me wonder is
int arr[] = malloc((sizeof(int)) * 8);
As has already been noted, this should be int *arr, not int arr[]
T *p = malloc(n * sizeof *p); for any object type T.
Post by Omar Radwan
int arr[8];
What if you don't know in advance how many you want?
As of C99, this is no longer a sufficient justification for using
malloc(). If you define an array

int arr[positive_integer_expression];

where positive_integer_expression isn't an integer constant expression,
it used to be a constraint violation, but as of C99 it declares a
variable length array (VLA).

The single most important reason for using malloc() rather than a VLA is
if your code has to be portable to implementations which don't support
VLAs. C90 didn't have VLAs, and in C2011, support for VLAs was made
optional; if not provided, the macro __STDC_NO_VLA__ must be pre-#defined.

Another important issue is that malloc() and VLAs might be allocated
from different pools of memory - but there's nothing that can portably
be said about that issue, since the C standard says nothing about that
issue.

Even when portability concerns do allow the use of VLAs, one good reason
for using malloc() instead is that it allows you to find out when there
isn't enough memory. The behavior of

int *arr = malloc(num_elements * sizeof *arr);

is well-defined if there's insufficient memory available: arr will
contain a null pointer, and you can (and should!) test for that
possibility before dereferencing the pointer. In contrast, you don't get
any warning if

int arr[num_elements];

is too large - your code simply has undefined behavior. Note that this
is not specific to VLAs; it's equally true of fixed-length arrays. If
there's less than 8*sizeof(int) bytes of memory left, entering a block
containing

int arr[8];

will also have undefined behavior.
--
James Kuyper
Keith Thompson
2014-07-18 15:42:16 UTC
Permalink
James Kuyper <***@verizon.net> writes:
[...]
Post by James Kuyper
The single most important reason for using malloc() rather than a VLA is
if your code has to be portable to implementations which don't support
VLAs. C90 didn't have VLAs, and in C2011, support for VLAs was made
optional; if not provided, the macro __STDC_NO_VLA__ must be pre-#defined.
Another important issue is that malloc() and VLAs might be allocated
from different pools of memory - but there's nothing that can portably
be said about that issue, since the C standard says nothing about that
issue.
[...]

Nothing can portably be said about it, but it can be important
anyway. In most implementations, VLAs and other locally defined
objects are allocated on the "stack", and malloc() allocates memory
on the "heap". Typically the "stack" has much less space available.

It's usually a good idea to avoid allocating very large objects on
the "stack" (i.e., as objects with automatic storage duration).

Though I don't think I've ever seen it done in real-world code, it's
also possible to allocate VLAs via malloc(), which avoids the problem
of undefined behavior when there's not enough available space:

const size_t len = some_value;
typedef double vla[len];
vla *ptr = malloc(sizeof *ptr);

Elements of the allocated array can be referred to as

(*ptr)[i]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Richard Heathfield
2014-07-18 15:51:31 UTC
Permalink
<snip>
Post by James Kuyper
Post by Richard Heathfield
What if you don't know in advance how many you want?
As of C99, this is no longer a sufficient justification for using
malloc(). If you define an array
int arr[positive_integer_expression];
where positive_integer_expression isn't an integer constant expression,
it used to be a constraint violation, but as of C99 it declares a
variable length array (VLA).
The existence of VLAs is not sufficient justification for using them. ;-)

Actually, I was just trying to keep things simple for what appears to be a
rookie. This is often a mistake in clc.

Allow me to re-phrase:

What if you don't know in advance how many you want, and would therefore
like to specify how many you want at runtime, but don't want to run the risk
of the memory not being available without your program being informed so
that you can deal with the paucity of memory in a controlled manner?

There - that's much clearer and simpler, isn't it? :-)
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
James Kuyper
2014-07-18 16:12:20 UTC
Permalink
Post by Richard Heathfield
<snip>
Post by James Kuyper
Post by Richard Heathfield
What if you don't know in advance how many you want?
As of C99, this is no longer a sufficient justification for using
malloc(). If you define an array
int arr[positive_integer_expression];
where positive_integer_expression isn't an integer constant expression,
it used to be a constraint violation, but as of C99 it declares a
variable length array (VLA).
The existence of VLAs is not sufficient justification for using them. ;-)
True - it's their greater convenience compared to using malloc() which
provides that justification; mere existence was not sufficient. The
convenience advantage gets even bigger when the array is
multi-dimensional, with dimensions other than the first one being variable.

I've already explicitly acknowledged the corresponding disadvantages.
Malcolm McLean
2014-07-18 21:16:27 UTC
Permalink
Post by James Kuyper
True - it's their greater convenience compared to using malloc() which
provides that justification; mere existence was not sufficient. The
convenience advantage gets even bigger when the array is
multi-dimensional, with dimensions other than the first one being variable.
But multi-dimensional arrays can get very big, very quickly.

The stack should be kept for small objects, logarithmic with program
size and complexity. That makes it easier for compilers to optimise,
and it avoids fail conditions.
That's even true of recursive functions. Normally they should be
written so that call depth is a logarithm of N.
Ben Bacarisse
2014-07-18 22:19:03 UTC
Permalink
Malcolm McLean <***@btinternet.com> writes:
<snip>
Post by Malcolm McLean
But multi-dimensional arrays can get very big, very quickly.
The stack should be kept for small objects, logarithmic with program
size and complexity. That makes it easier for compilers to optimise,
and it avoids fail conditions.
What optimisations do you have in mind? And does one assess a
program's complexity on order to follow this advice?

<snip>
--
Ben.
Malcolm McLean
2014-07-19 17:12:17 UTC
Permalink
Post by Ben Bacarisse
Post by Malcolm McLean
The stack should be kept for small objects, logarithmic with program
size and complexity. That makes it easier for compilers to optimise,
and it avoids fail conditions.
What optimisations do you have in mind? And does one assess a
program's complexity on order to follow this advice?
If most of the frequently-used variables are on the stack,
and it's known to be small, the entire stack can be assigned to
fast memory.
In C, a programs complexity can be estimated by counting the number
of functions (assuming most library calls are simple leaves).
If the call tree is roughly balanced, and the number of variables
in a function follows a bell curve-like distribution, then
as you add functions, the maximum stack depth grows logarithmically.

However if you have recursive calls, then call depth can be bounded
by the size of the data you are operating on. That's one reason to
try to keep recursion rare.
Ben Bacarisse
2014-07-19 18:52:38 UTC
Permalink
Post by Malcolm McLean
Post by Ben Bacarisse
Post by Malcolm McLean
The stack should be kept for small objects, logarithmic with program
size and complexity. That makes it easier for compilers to optimise,
and it avoids fail conditions.
What optimisations do you have in mind? And does one assess a
program's complexity on order to follow this advice?
If most of the frequently-used variables are on the stack,
and it's known to be small, the entire stack can be assigned to
fast memory.
In C, a programs complexity can be estimated by counting the number
of functions (assuming most library calls are simple leaves).
If the call tree is roughly balanced, and the number of variables
in a function follows a bell curve-like distribution, then
as you add functions, the maximum stack depth grows logarithmically.
Interesting, but I think I'll just write for clarity rather than worry
about this particular measure.

<snip>
--
Ben.
Phil Carmody
2014-07-24 22:11:27 UTC
Permalink
Post by Ben Bacarisse
Post by Malcolm McLean
Post by Ben Bacarisse
Post by Malcolm McLean
The stack should be kept for small objects, logarithmic with program
size and complexity. That makes it easier for compilers to optimise,
and it avoids fail conditions.
What optimisations do you have in mind? And does one assess a
program's complexity on order to follow this advice?
If most of the frequently-used variables are on the stack,
and it's known to be small, the entire stack can be assigned to
fast memory.
In C, a programs complexity can be estimated by counting the number
of functions (assuming most library calls are simple leaves).
If the call tree is roughly balanced, and the number of variables
in a function follows a bell curve-like distribution, then
as you add functions, the maximum stack depth grows logarithmically.
Interesting, but I think I'll just write for clarity rather than worry
about this particular measure.
You're not alone. But those that do care about such things don't need
to rely on the induced function call stack frames for such behaviour.
As long as you're prepared to take care about pointers not escaping
(just as you would with addresses of local variables), it's perfectly
possible to create a dynamic memory pool which has the same cache-
friendliness. And free frees to boot.

However, personally, I don't accept that any real world program has a
call "tree". Many don't even have DAGs.

Phil
--
The best part of re-inventing the wheel is that you get to pick how
many sides the new one has. -- egcagrac0 on SoylentNews
glen herrmannsfeldt
2014-07-18 23:05:32 UTC
Permalink
Malcolm McLean <***@btinternet.com> wrote:

(snip)
Post by Malcolm McLean
But multi-dimensional arrays can get very big, very quickly.
The stack should be kept for small objects, logarithmic with program
size and complexity. That makes it easier for compilers to optimise,
and it avoids fail conditions.
Seems to me this is a side effect of the history of C.

For one, it began on small memory machines without virtual addressing,
and usually with a stack. Also, the need to use malloc/free for
variable sized allocation made that the more common use.

For objects that have the lifetime of the function that they are
allocated in, it isn't so obvious, other than for historial reasons,
that auto allocation (either fixed or variable length arrays) isn't
a better choice.

Many systems do have a small default for stack, but that can change.

The choice of allocation method should depend on the lifetime of
the allocation, not its size.
Post by Malcolm McLean
That's even true of recursive functions. Normally they should be
written so that call depth is a logarithm of N.
Yes, one should be careful when writing recursive routines to
avoid stack overflow. Simple things like tail recursion optimization
along with appropriate ordering of the recursive calls helps a lot.

-- glen
Anand Hariharan
2014-07-19 16:25:42 UTC
Permalink
Post by James Kuyper
Post by Richard Heathfield
Post by James Kuyper
Post by Richard Heathfield
What if you don't know in advance how many you want?
As of C99, this is no longer a sufficient justification for using
malloc(). If you define an array
int arr[positive_integer_expression];
where positive_integer_expression isn't an integer constant expression,
it used to be a constraint violation, but as of C99 it declares a
variable length array (VLA).
The existence of VLAs is not sufficient justification for using them. ;-)
True - it's their greater convenience compared to using malloc() which
provides that justification; mere existence was not sufficient. The
convenience advantage gets even bigger when the array is
multi-dimensional, with dimensions other than the first one being variable.
I've already explicitly acknowledged the corresponding disadvantages.
How would one use a VLA for a member in a struct that is intended to
hold a number of elements determined at runtime?

- Anand
Kaz Kylheku
2014-07-19 16:30:44 UTC
Permalink
How would one use a VLA for a member in a struct ...
One wouldn't. VLA's are defined as variables with automatic storage class:
non-static block scope variables and function arguments.
Keith Thompson
2014-07-19 18:15:11 UTC
Permalink
[...]
Post by Anand Hariharan
Post by James Kuyper
Post by Richard Heathfield
The existence of VLAs is not sufficient justification for using them. ;-)
True - it's their greater convenience compared to using malloc() which
provides that justification; mere existence was not sufficient. The
convenience advantage gets even bigger when the array is
multi-dimensional, with dimensions other than the first one being variable.
I've already explicitly acknowledged the corresponding disadvantages.
How would one use a VLA for a member in a struct that is intended to
hold a number of elements determined at runtime?
One wouldn't; a VLA cannot be a member of a struct.

You can have a *pointer* to a VLA, but then you have to manage the
storage for it. Or you can use a flexible array member.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
David Lee Lambert
2014-09-04 19:11:18 UTC
Permalink
Post by James Kuyper
Post by Richard Heathfield
What if you don't know in advance how many you want?
As of C99, this is no longer a sufficient justification for using
malloc(). If you define an array
int arr[positive_integer_expression];
where positive_integer_expression isn't an integer constant expression,
it used to be a constraint violation, but as of C99 it declares a
variable length array (VLA).
It seems like VLAs should work exactly like the non-standard keyword `alloca` supported by some compilers, but for some reason gcc 4.4.7 (on Linux AMD64) generates longer code in the VLA case. `alloca` and VLAs also both cause a segmentation fault with sufficiently large allocations, but the limit for a VLA is lower.

int * data = alloca(size * sizeof(int));
/* versus */
int data[size];

Even stranger, the equivalent malloc()/free() pair compiles to even fewer assembly-language instructions. malloc also allows much larger allocations without a segmentation fault.
Kaz Kylheku
2014-09-04 19:37:20 UTC
Permalink
Post by David Lee Lambert
Post by James Kuyper
Post by Richard Heathfield
What if you don't know in advance how many you want?
As of C99, this is no longer a sufficient justification for using
malloc(). If you define an array
int arr[positive_integer_expression];
where positive_integer_expression isn't an integer constant expression,
it used to be a constraint violation, but as of C99 it declares a
variable length array (VLA).
It seems like VLAs should work exactly like the non-standard keyword `alloca`
supported by some compilers, but for some reason gcc 4.4.7 (on Linux AMD64)
generates longer code in the VLA case. `alloca` and VLAs also both cause a
segmentation fault with sufficiently large allocations, but the limit for a
VLA is lower.
int * data = alloca(size * sizeof(int));
/* versus */
int data[size];
Even stranger, the equivalent malloc()/free() pair compiles to even fewer
assembly-language instructions. malloc also allows much larger allocations
without a segmentation fault.
* VLA's have block scope, whereas alloca has function scope.
* There is no way to free an alloca block other than returning from
the function, but a VLA goes away when the enclosing block terminates,
making it possible to use temporary VLA in a loop without continuously
extending automatic storage.
* In principle alloca *can* provide an indication of failure, whereas a VLA
doesn't have an interface for it. This is the main argument agqainst
using VLA's in situations where an upper bound on the size is not
known in advance, or known to be unreasonably large. In reality it
seems that alloca just moves the stack pointer and hopes for the best.
If you get a segfault, you are lucky: the pointer landed in a guard
page. The pointer could land in the middle of an unrelated memory mapping.
* The behavior of alloca tends to be specified in terms of its stack
implementation; it is not as abstract as VLA's, which could be
implemented with malloc and free, nearly transparently to the user.
The VLA implementation could even choose dynamically between malloc
and using stack space, based on the size of the request. If malloc
is used, the compiler can arrange for unconditional cleanup (even
in the face of longjmp: an implementaton of longjmp can perform
unwinding.)
* Because it is so tied to the implementation, alloca has bizarre restrictions
on the context of its use; for instance, IIRC, calls to alloca cannot occur
in the middle of code that is compiled into machine code which moves the
stack pointer around, namely the argument expressions of function calls. (How
the implemetnation defends against code motion causing the same problem even
for alloca calls which are not in function call expressions is unclear.)
James Kuyper
2014-09-04 20:15:19 UTC
Permalink
Post by David Lee Lambert
Post by James Kuyper
Post by Richard Heathfield
What if you don't know in advance how many you want?
As of C99, this is no longer a sufficient justification for using
malloc(). If you define an array
int arr[positive_integer_expression];
where positive_integer_expression isn't an integer constant expression,
it used to be a constraint violation, but as of C99 it declares a
variable length array (VLA).
It seems like VLAs should work exactly like the non-standard keyword `alloca` supported by some compilers, but for some reason gcc 4.4.7 (on Linux AMD64) generates longer code in the VLA case. `alloca` and VLAs also both cause a segmentation fault with sufficiently large allocations, but the limit for a VLA is lower.
I'm unfamiliar with 'alloc' as a keyword. I am familiar with a function
named alloc(). It's not part of the C standard library, nor is it part
Post by David Lee Lambert
There is evidence that the alloca() function appeared in 32V, PWB,
PWB.2, 3BSD, and 4BSD. There is a man page for it in 4.3BSD. Linux
uses the GNU version.
There are some important differences between alloc() and a VLA, other
than just in the way the memory is allocated. According to the man page
on my system, the memory allocated by alloc() is automatically freed
when the function returns, or when longjmp() or siglongjmp() is called.

A VLA must have block or function prototype scope, and must not have
static or thread storage duration. It's lifetime therefore ends at the
end of the corresponding block, which need not be the outermost block of
a function.
If longjmp() is called, and "... the invocation of the setjmp
macro was within the scope of an identifier with variably modified type
and execution has left that scope in the interim, the behavior is
undefined." (7.13.2.1p2) Note that it is the longjmp() call itself that
has undefined behavior - it doesn't matter whether any attempt is made
to access the VLA.
Keith Thompson
2014-09-04 20:52:49 UTC
Permalink
Post by David Lee Lambert
Post by James Kuyper
Post by Richard Heathfield
What if you don't know in advance how many you want?
As of C99, this is no longer a sufficient justification for using
malloc(). If you define an array
int arr[positive_integer_expression];
where positive_integer_expression isn't an integer constant expression,
it used to be a constraint violation, but as of C99 it declares a
variable length array (VLA).
It seems like VLAs should work exactly like the non-standard keyword
`alloca` supported by some compilers, but for some reason gcc 4.4.7
(on Linux AMD64) generates longer code in the VLA case. `alloca` and
VLAs also both cause a segmentation fault with sufficiently large
allocations, but the limit for a VLA is lower.
int * data = alloca(size * sizeof(int));
/* versus */
int data[size];
Even stranger, the equivalent malloc()/free() pair compiles to even
fewer assembly-language instructions. malloc also allows much larger
allocations without a segmentation fault.
One more difference between alloca() and VLAs is that VLAs are *types*.
Simply defining an object of a VLA type:

int n = ...;
double vla[n];

carries all the risks of allocating an arbitrary amount of memory on
the stack (er, I mean with automatic storage duration) with no way
to check for allocation failures. But you can also define a VLA type
and then, for example, use malloc() to allocate objects of that type.
For multidimensional VLAs, that means you can use `(*ptr)[x][y]`
to access individual elements rather than computing the offset
manually, and malloc() lets you detect allocation failures.

The committee's decision to make VLAs optional in C11 means that, in
theory at least, you can't depend on this. Still, if a C compiler
doesn't support VLAs it's more likely to mean that it's pre-C99
than that it's a C11 compiler that doesn't support them.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
glen herrmannsfeldt
2014-07-18 16:34:26 UTC
Permalink
(snip)
Post by James Kuyper
Post by Richard Heathfield
What if you don't know in advance how many you want?
As of C99, this is no longer a sufficient justification for using
malloc(). If you define an array
int arr[positive_integer_expression];
where positive_integer_expression isn't an integer constant expression,
it used to be a constraint violation, but as of C99 it declares a
variable length array (VLA).
(snip of first reason)
Post by James Kuyper
Another important issue is that malloc() and VLAs might be allocated
from different pools of memory - but there's nothing that can portably
be said about that issue, since the C standard says nothing about that
issue.
Also, VLAs (and constant length arrays) are often allocated on the
stack (even though the standard doesn't say that) and the stack is
often more restrictive in size.

It is, then, better to use malloc() for larger arrays, though you
don't always know what "larger" is.
Post by James Kuyper
Even when portability concerns do allow the use of VLAs, one good
reason for using malloc() instead is that it allows you to
find out when there isn't enough memory. The behavior of
int *arr = malloc(num_elements * sizeof *arr);
is well-defined if there's insufficient memory available: arr will
contain a null pointer, and you can (and should!) test for that
possibility before dereferencing the pointer.
Another reason to use malloc() for larger allocation, as you are
more likely to run out of available memory for larger ones.
Post by James Kuyper
In contrast, you don't get any warning if
int arr[num_elements];
is too large - your code simply has undefined behavior. Note that this
is not specific to VLAs; it's equally true of fixed-length arrays. If
there's less than 8*sizeof(int) bytes of memory left, entering a block
containing
int arr[8];
will also have undefined behavior.
Not to mention any other memory that might be needed on entering
a block. Often a lot more than 8*sizeof(int).

-- glen
Keith Thompson
2014-07-18 16:03:58 UTC
Permalink
Post by Richard Heathfield
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming language. Honestly,
I think I chose the right language. All the other languages have something
that I don't agree with. But a programming concept that makes me wonder is
int arr[] = malloc((sizeof(int)) * 8);
As has already been noted, this should be int *arr, not int arr[]
T *p = malloc(n * sizeof *p); for any object type T.
Post by Omar Radwan
int arr[8];
What if you don't know in advance how many you want?
[snip]

There are two major uses for malloc().

One, as discussed here already, is when you need to allocate an
array but don't know (until the program is already running) how
long the array needs to be.

The other is when you don't know how many *distinct* object you're
going to need. Common examples are linked lists and trees, where
the objects being allocated are usually structs rather than arrays.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Joe Pfeiffer
2014-07-18 03:57:44 UTC
Permalink
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming
language. Honestly, I think I chose the right language. All the other
languages have something that I don't agree with. But a programming
Others have mentioned the specifics of the particular declaration and
allocation you used as examples; more generally:

If you can know how much of something you need at compile-time, use a
fixed-size array or other local variable.

If what you need won't be known until run-time, use dynamic memory
allocation.

Sometimes, you can know you will just need an array, but the size of the
array can't be known until run-time. Here, you can use a
variable-length array.
August Karlstrom
2014-07-18 11:50:29 UTC
Permalink
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming language.
Honestly, I think I chose the right language. All the other languages
have something that I don't agree with. But a programming concept
int arr[] = malloc((sizeof(int)) * 8);
The function `malloc' returns a pointer whereas the variable `arr' is an
array. Therefore the assignment is not valid. On the other hand the
assignment is valid if we instead declare `arr' as a pointer to an integer:

int *arr = malloc(8 * sizeof (int));

Dynamic memory allocation with `malloc' is typically used in this manner
when we want to use an array but don't know in advance how large it
needs to be.
Post by Omar Radwan
typedef struct Person { int age; float height; float weight; char
name[]; };
struct Guy Bobby = malloc(sizeof(Guy))
Here too the variable `Bobby' needs to be declared as a pointer:

struct Guy *Bobby = malloc(sizeof (struct Guy));

Dynamic memory allocation of records is used for instance with recursive
data structures like lists and trees which grow and/or shrink as the
program is executed.

In my C projects I use the following macros to make the code more robust
and less cluttered:

#define NEW_N(p, n) (p) = malloc((n) * sizeof *(p))
#define NEW(p) NEW_N((p), 1)

With these in place we can simply write

NEW_N(arr, 8);

and

NEW(Bobby);


-- August
Stefan Ram
2014-07-18 16:40:56 UTC
Permalink
Post by August Karlstrom
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming language.
Honestly, I think I chose the right language. All the other languages
have something that I don't agree with. But a programming concept
int arr[] = malloc((sizeof(int)) * 8);
The function `malloc' returns a pointer whereas the variable `arr' is an
array. Therefore the assignment is not valid. On the other hand the
int *arr = malloc(8 * sizeof (int));
But IIRC, one can write something like:

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

void f( int a[] ){ if( a )free( a ); }

int main( void )
{ f( malloc( 8 * sizeof( int )));
printf( "2014-07-18\n" ); }
Ike Naar
2014-07-18 16:55:44 UTC
Permalink
Post by Stefan Ram
Post by August Karlstrom
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming language.
Honestly, I think I chose the right language. All the other languages
have something that I don't agree with. But a programming concept
int arr[] = malloc((sizeof(int)) * 8);
The function `malloc' returns a pointer whereas the variable `arr' is an
array. Therefore the assignment is not valid. On the other hand the
int *arr = malloc(8 * sizeof (int));
#include <stdio.h>
#include <stdlib.h>
void f( int a[] ){ if( a )free( a ); }
IIRC one can write that as

void f(int *a) { free(a); }
Richard Heathfield
2014-07-18 17:58:34 UTC
Permalink
<snip>
Post by Ike Naar
Post by Stefan Ram
#include <stdio.h>
#include <stdlib.h>
void f( int a[] ){ if( a )free( a ); }
IIRC one can write that as
void f(int *a) { free(a); }
YRC.

7.20.3.2 The free function
Synopsis
1 #include <stdlib.h>
void free(void *ptr);
Description
2 The free function causes the space pointed to by ptr to be deallocated,
that is, made available for further allocation. If ptr is a null
pointer, no action occurs.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
James Kuyper
2014-07-18 17:02:40 UTC
Permalink
Post by Stefan Ram
Post by August Karlstrom
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming language.
Honestly, I think I chose the right language. All the other languages
have something that I don't agree with. But a programming concept
int arr[] = malloc((sizeof(int)) * 8);
The function `malloc' returns a pointer whereas the variable `arr' is an
array. Therefore the assignment is not valid. On the other hand the
int *arr = malloc(8 * sizeof (int));
#include <stdio.h>
#include <stdlib.h>
void f( int a[] ){ if( a )free( a ); }
int main( void )
{ f( malloc( 8 * sizeof( int )));
printf( "2014-07-18\n" ); }
Yes, and the reason for that is one of the more confusing aspects of C:
"A declaration of a parameter as ‘‘array of type’’ shall be adjusted to
‘‘qualified pointer to type’’, where the type qualifiers (if any) are
those specified within the [ and ] of the array type derivation."
(6.7.6.3p7)

Thus

void f1(int param[const]);

is adjusted to

void f1(int * const param);

Allowing qualifiers like 'const' in the square brackets was introduced
in C99.
August Karlstrom
2014-07-19 09:30:18 UTC
Permalink
Post by Stefan Ram
#include <stdio.h>
#include <stdlib.h>
void f( int a[] ){ if( a )free( a ); }
int main( void )
{ f( malloc( 8 * sizeof( int )));
printf( "2014-07-18\n" ); }
In this case the type of the formal parameter `a' is just syntactic
sugar to indicate that the function expects a pointer to a sequence of
integers. The real type, though, is "pointer to integer".


-- August
Keith Thompson
2014-07-19 18:14:14 UTC
Permalink
Post by August Karlstrom
Post by Stefan Ram
#include <stdio.h>
#include <stdlib.h>
void f( int a[] ){ if( a )free( a ); }
int main( void )
{ f( malloc( 8 * sizeof( int )));
printf( "2014-07-18\n" ); }
In this case the type of the formal parameter `a' is just syntactic
sugar to indicate that the function expects a pointer to a sequence of
integers. The real type, though, is "pointer to integer".
More correctly, `int a[]` as a parameter declaration is syntactic sugar
for `int *a`, which defines as a pointer to an int object. That object
may or may not be the first element (or some other element) of an array
(though even a single int object can be treated as a single-element
array).

The use of [] rather than * is a strong hint *to the reader* that `a`
points to the first element of an array, but that hint has no meaning to
the compiler.

Another point: it's important to distinguish between "int" and
"integer". int is just one of several integer types.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
August Karlstrom
2014-07-20 09:27:02 UTC
Permalink
Post by Keith Thompson
Post by August Karlstrom
Post by Stefan Ram
#include <stdio.h>
#include <stdlib.h>
void f( int a[] ){ if( a )free( a ); }
int main( void )
{ f( malloc( 8 * sizeof( int )));
printf( "2014-07-18\n" ); }
In this case the type of the formal parameter `a' is just syntactic
sugar to indicate that the function expects a pointer to a sequence of
integers. The real type, though, is "pointer to integer".
More correctly, `int a[]` as a parameter declaration is syntactic sugar
for `int *a`, which defines as a pointer to an int object. That object
may or may not be the first element (or some other element) of an array
(though even a single int object can be treated as a single-element
array).
Not necessarily more correct but more detailed.
Post by Keith Thompson
The use of [] rather than * is a strong hint *to the reader* that `a`
points to the first element of an array, but that hint has no meaning to
the compiler.
Is it correct to call a dynamically allocated object an array? It's
important to distinguish between array variables (whose length is known
at compile-time), and allocated objects accessed as arrays.
Post by Keith Thompson
Another point: it's important to distinguish between "int" and
"integer". int is just one of several integer types.
I think the context made it clear what was meant.


-- August
Malcolm McLean
2014-07-20 15:33:45 UTC
Permalink
Post by August Karlstrom
Is it correct to call a dynamically allocated object an array? It's
important to distinguish between array variables (whose length is known
at compile-time), and allocated objects accessed as arrays.
Depends how you're using the term.
At the data structures and algorithms level, an array is a collection
which is indexed by an integer subscript, with no gaps, and allowing
random access in O(1) time. The obvious way to implement it is as
storage in contiguous regions of memory. So when we're talking about
C, we usually mean that.
But if you're talking about the compiler's type system, an array is
specifically objects declared with an array type.
Keith Thompson
2014-07-21 01:38:25 UTC
Permalink
Post by Malcolm McLean
Post by August Karlstrom
Is it correct to call a dynamically allocated object an array? It's
important to distinguish between array variables (whose length is known
at compile-time), and allocated objects accessed as arrays.
Depends how you're using the term.
At the data structures and algorithms level, an array is a collection
which is indexed by an integer subscript, with no gaps, and allowing
random access in O(1) time. The obvious way to implement it is as
storage in contiguous regions of memory. So when we're talking about
C, we usually mean that.
But if you're talking about the compiler's type system, an array is
specifically objects declared with an array type.
Can you provide a citation for that? I've just provided a citation
(N1570 6.5.2.1, "A postfix expression followed by an expression in
square brackets [] is a subscripted designation of an element of an
array object.") that clearly implies otherwise.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Tim Rentsch
2014-07-23 18:14:23 UTC
Permalink
Post by r***@gmail.com
Post by August Karlstrom
Is it correct to call a dynamically allocated object an array? It's
important to distinguish between array variables (whose length is known
at compile-time), and allocated objects accessed as arrays.
[snip]
But if you're talking about the compiler's type system, an array is
specifically objects declared with an array type.
That's wrong. Array types may exist, and dynamically allocated
memory may be accessed by means of an array type, even in programs
that declare no variables as arrays. The arrayness of a type is
not tied to whether it must reference a declared array.
Keith Thompson
2014-07-21 01:37:04 UTC
Permalink
Post by August Karlstrom
Post by Keith Thompson
Post by August Karlstrom
Post by Stefan Ram
#include <stdio.h>
#include <stdlib.h>
void f( int a[] ){ if( a )free( a ); }
int main( void )
{ f( malloc( 8 * sizeof( int )));
printf( "2014-07-18\n" ); }
In this case the type of the formal parameter `a' is just syntactic
sugar to indicate that the function expects a pointer to a sequence of
integers. The real type, though, is "pointer to integer".
More correctly, `int a[]` as a parameter declaration is syntactic sugar
for `int *a`, which defines as a pointer to an int object. That object
may or may not be the first element (or some other element) of an array
(though even a single int object can be treated as a single-element
array).
Not necessarily more correct but more detailed.
Your description said that the [] syntax indicates that a points to a
*sequence* of integers. Did you mean to include a single standalone
integer object under the term "sequence"?
Post by August Karlstrom
Post by Keith Thompson
The use of [] rather than * is a strong hint *to the reader* that `a`
points to the first element of an array, but that hint has no meaning to
the compiler.
Is it correct to call a dynamically allocated object an array?
Yes. N1570 6.5.2.1p2:

A postfix expression followed by an expression in square brackets []
is a subscripted designation of an element of an array object.

Since [] can be applied to a pointer to a dynamically allocated object,
it follows that such an object can be an array object. (There should be
a more direct demonstration of that, but this seems clearer.)
Post by August Karlstrom
It's
important to distinguish between array variables (whose length is known
at compile-time), and allocated objects accessed as arrays.
I don't disagree, but "array" vs. "not an array" is not the way to make
that distinction.
Post by August Karlstrom
Post by Keith Thompson
Another point: it's important to distinguish between "int" and
"integer". int is just one of several integer types.
I think the context made it clear what was meant.
Not to someone who doesn't know the difference between "int" and
"integer". I'm not suggesting that you don't, but others may not.
(And "int" is less typing!)
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Tim Rentsch
2014-07-23 18:04:14 UTC
Permalink
Post by August Karlstrom
Post by Keith Thompson
Post by August Karlstrom
Post by Stefan Ram
#include <stdio.h>
#include <stdlib.h>
void f( int a[] ){ if( a )free( a ); }
int main( void )
{ f( malloc( 8 * sizeof( int )));
printf( "2014-07-18\n" ); }
In this case the type of the formal parameter `a' is just syntactic
sugar to indicate that the function expects a pointer to a sequence of
integers. The real type, though, is "pointer to integer".
More correctly, `int a[]` as a parameter declaration is syntactic sugar
for `int *a`, which defines as a pointer to an int object. That object
may or may not be the first element (or some other element) of an array
(though even a single int object can be treated as a single-element
array).
Not necessarily more correct but more detailed.
Post by Keith Thompson
The use of [] rather than * is a strong hint *to the reader* that `a`
points to the first element of an array, but that hint has no meaning to
the compiler.
Is it correct to call a dynamically allocated object an array?
Yes. Please refer to section 7.20.3 paragraph 1 in

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
Post by August Karlstrom
It's
important to distinguish between array variables (whose length is
known at compile-time), and allocated objects accessed as arrays.
A more common distinction is whether the array in question has a
single element or more than one element. Also there are other
ways to declare array variables (or struct members) so that they
have array type but the lengths are not known at compile time.
In some cases it's important to distinguish between objects whose
identifier is declared with array type and other objects used as
arrays; for purposes of parameter declarations, however, they
are all considered just arrays.

Incidentally, note that there are arrays in C that are neither
(in or part of) dynamically allocated objects nor do they
correspond to any array variable (or member) declaration. Can
you think of one?
James Kuyper
2014-07-18 12:12:44 UTC
Permalink
On 07/17/2014 10:33 PM, Omar Radwan wrote:
Other people have already addressed most of the relevant issues, but no
Post by Omar Radwan
typedef struct Person
{
int age;
float height;
float weight;
char name[];
};
struct Guy Bobby = malloc(sizeof(Guy))
That should be

struct Person *Bobby = malloc(sizeof *Bobby);
--
James Kuyper
Keith Thompson
2014-07-18 15:54:32 UTC
Permalink
Post by James Kuyper
Other people have already addressed most of the relevant issues, but no
Post by Omar Radwan
typedef struct Person
{
int age;
float height;
float weight;
char name[];
};
struct Guy Bobby = malloc(sizeof(Guy))
That should be
struct Person *Bobby = malloc(sizeof *Bobby);
Since this is addressed to a beginner, we should explain *why* it should
be written that way.

The quoted code seems to confuse the names "Person" and "Guy".

If you want to have a struct type whose name is a single identifier, you
need to use a "typedef":

typedef struct {
/* ... */
} Person;

Or, if you don't mind using the "struct" keyword, you can drop the
typedef:

struct Person {
/* ... */
};

In the former case, the type's name is "Person"; in the latter, it's
"struct Person", and you need to use the "struct" keyword every time you
refer to it. (I prefer the latter because it's more explicit, but the
former is quite common.)

You can allocate a single "struct Person" object using malloc():

struct Person *Bobby = malloc(sizeof (struct Person));

This is perfectly legal and will work correctly, but it's a bit fragile,
because the type name "struct Person" has to be written twice. If you
later decide that Bobby needs to be a pointer to a "struct Employee"
(which is bigger because it contains more information), you might update
one occurrence but forget to update the other:

struct Employee *Bobby = malloc(sizeof (struct Person)); /* WRONG */

You can avoid that using a technique that lets you write the type name
just once:

struct Employee *Bobby = malloc(sizeof *Bobby);

This newsgroup has an excellent FAQ at:

http://www.c-faq.com/
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
r***@gmail.com
2014-07-18 14:43:58 UTC
Permalink
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming language. Honestly, I think I chose the right language. All the other languages have something that I don't agree with.
[snip]

If it's your first programming language, how can you tell that all of the
other languages have something that you don't agree with. What, exactly, do you disagree with in Pascal? Ada? Fortran? Forth? J? Prolog? Lisp? Haskell?

C is a wonderful language -- and in many ways the best choice for a first
language, but don't dismiss the rest of the programming language landscape
based upon knowledge on e.g. a limited exposure to Java, C++ and JavaScript
(or whatever you were basing your comment on).
Keith Thompson
2014-07-18 15:55:33 UTC
Permalink
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming
language. Honestly, I think I chose the right language. All the other
languages have something that I don't agree with.
[...]

Trust me, as you learn more about C, you *will* encounter things you
don't agree with.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Richard Bos
2014-07-18 16:08:55 UTC
Permalink
Post by Keith Thompson
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming
language. Honestly, I think I chose the right language. All the other
languages have something that I don't agree with.
Trust me, as you learn more about C, you *will* encounter things you
don't agree with.
Also, if you learn programming using C and you don't have a _very_ good
teacher, you _will_ later encounter both programmers and compilers which
won't agree with you, because you've learned sloppy habits.

Learn programming using Pascal. It is a horrible, horrible bondage-and-
discipline language, which is not good for everyday use, but _very_ good
for instilling proper structured programming habits into novice
programmers. Some day you'll be grateful for it. This day will come
when you've graduated to actually _programming_ in C, or another
professional, non-educational language, and you realise that the crash-
inducing error someone else just made on your turf is because _he_
learned using C, or worse, Basic, and _you_ learned to spot such memory
access errors, over-reliance on system specifics, and other rookie
mistakes.

Richard
Stefan Ram
2014-07-18 16:45:21 UTC
Permalink
Post by Richard Bos
Learn programming using Pascal. It is a horrible, horrible bondage-and-
My opinion is based on the assumption that one is learning to
program for some purpose. One wants to do something with that
one has learned. In this case, I believe, one should go ahead
and try to find out what language is used in that field. For
example, for HTML5 programming, it would be JavaScript. Then,
one should go straight ahead and learn that language, not wasting
time learning another language first that one does not need. Pascal
might be suited for the field of history of programming didactics.
Tim Streater
2014-07-18 17:24:35 UTC
Permalink
Post by Richard Bos
Post by Keith Thompson
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming
language. Honestly, I think I chose the right language. All the other
languages have something that I don't agree with.
Trust me, as you learn more about C, you *will* encounter things you
don't agree with.
Also, if you learn programming using C and you don't have a _very_ good
teacher, you _will_ later encounter both programmers and compilers which
won't agree with you, because you've learned sloppy habits.
Learn programming using Pascal. It is a horrible, horrible bondage-and-
discipline language, which is not good for everyday use, but _very_ good
for instilling proper structured programming habits into novice
programmers. Some day you'll be grateful for it. This day will come
when you've graduated to actually _programming_ in C, or another
professional, non-educational language, and you realise that the crash-
inducing error someone else just made on your turf is because _he_
learned using C, or worse, Basic, and _you_ learned to spot such memory
access errors, over-reliance on system specifics, and other rookie
mistakes.
I learnt pascal from its author and didn't consider it good for
anything. It was meant for teaching, but the first generations of
students who learnt it went out, got jobs, and persuaded their managers
that pascal was this wonderful language that their company should be
selling compilers for. Some of its more obvious drawbacks included the
lack of a return statement and that strings of different lengths were
different types. Perhaps I was lucky in that I had already seen Snobol
and BCPL.

Remember: it's possible to write FORTRAN in any language.
--
"If you're not able to ask questions and deal with the answers without feeling
that someone has called your intelligence or competence into question, don't
ask questions on Usenet where the answers won't be carefully tailored to avoid
tripping your hair-trigger insecurities." - D M Procida, UCSM
Stefan Ram
2014-07-18 17:38:50 UTC
Permalink
Post by Tim Streater
Some of its more obvious drawbacks included
that strings of different lengths were
different types
#include <stdio.h>
int main( void )
{ char( * const word )[ 5 ]= &"word";
printf( "2014-07-18\n" ); }

The above compiles fine.

Now go ahead and replace the »5« by »4«.
Tim Rentsch
2014-07-23 17:45:28 UTC
Permalink
Post by Tim Streater
Post by r***@gmail.com
[snip]
Remember: it's possible to write FORTRAN in any language.
The person who said that never tried to write FORTRAN code
in Prolog.
Joe Pfeiffer
2014-07-18 21:43:12 UTC
Permalink
Post by Richard Bos
Post by Keith Thompson
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming
language. Honestly, I think I chose the right language. All the other
languages have something that I don't agree with.
Trust me, as you learn more about C, you *will* encounter things you
don't agree with.
Also, if you learn programming using C and you don't have a _very_ good
teacher, you _will_ later encounter both programmers and compilers which
won't agree with you, because you've learned sloppy habits.
Learn programming using Pascal. It is a horrible, horrible bondage-and-
discipline language, which is not good for everyday use, but _very_ good
for instilling proper structured programming habits into novice
programmers. Some day you'll be grateful for it. This day will come
when you've graduated to actually _programming_ in C, or another
professional, non-educational language, and you realise that the crash-
inducing error someone else just made on your turf is because _he_
learned using C, or worse, Basic, and _you_ learned to spot such memory
access errors, over-reliance on system specifics, and other rookie
mistakes.
I thought I was the only person left who thought Pascal was a great
first language!
Richard Bos
2014-07-18 23:20:00 UTC
Permalink
Post by Joe Pfeiffer
Post by Richard Bos
Learn programming using Pascal. It is a horrible, horrible bondage-and-
discipline language, which is not good for everyday use, but _very_ good
for instilling proper structured programming habits into novice
programmers. Some day you'll be grateful for it. This day will come
when you've graduated to actually _programming_ in C, or another
professional, non-educational language, and you realise that the crash-
inducing error someone else just made on your turf is because _he_
learned using C, or worse, Basic, and _you_ learned to spot such memory
access errors, over-reliance on system specifics, and other rookie
mistakes.
I thought I was the only person left who thought Pascal was a great
first language!
Mind you, that's the only thing it _is_ good at. Pascal is to
programming what a tricycle is to riding a bike.

Richard
Ian Collins
2014-07-18 23:30:43 UTC
Permalink
Post by Richard Bos
Learn programming using Pascal. It is a horrible, horrible bondage-and-
discipline language, which is not good for everyday use, but _very_ good
for instilling proper structured programming habits into novice
programmers. Some day you'll be grateful for it.
As one who did learn programming using Pascal I have to agree. Although
I did write my first "real" non-assembly project in DEC's rather good
Pascal derivative (MicroPower Pascal), so the experience wasn't all bad.
--
Ian Collins
Stefan Ram
2014-07-18 23:50:18 UTC
Permalink
Post by Ian Collins
Post by Richard Bos
Learn programming using Pascal. It is a horrible, horrible bondage-and-
discipline language, which is not good for everyday use, but _very_ good
for instilling proper structured programming habits into novice
programmers. Some day you'll be grateful for it.
As one who did learn programming using Pascal I have to agree.
Of course, you have! This is a mental mechanism that is known as
»dissonance reduction«:

»people engage in a process called dissonance reduction
to bring their cognitions and actions in line with one
another. This creation of uniformity allows for a
lessening of psychological tension and distress«.

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

It goes along these lines of thought:

- »I was born before 1985.«

- »I have spent a lot of time learning Pascal.«

- »If another path would be better, all that time
would have possibly been wasted. This cannot be!!
No! No! No! So it must be so that all this effort
made loads of sense!«

- »Therefore, I will now recommend even to someone who
might have been born after 1995 that he should start
programming using Pascal.«
Ben Bacarisse
2014-07-19 00:49:37 UTC
Permalink
Post by Stefan Ram
Post by Ian Collins
Post by Richard Bos
Learn programming using Pascal. It is a horrible, horrible bondage-and-
discipline language, which is not good for everyday use, but _very_ good
for instilling proper structured programming habits into novice
programmers. Some day you'll be grateful for it.
As one who did learn programming using Pascal I have to agree.
Of course, you have! This is a mental mechanism that is known as
»people engage in a process called dissonance reduction
to bring their cognitions and actions in line with one
another. This creation of uniformity allows for a
lessening of psychological tension and distress«.
http://en.wikipedia.org/wiki/Cognitive_dissonance
- »I was born before 1985.«
- »I have spent a lot of time learning Pascal.«
- »If another path would be better, all that time
would have possibly been wasted. This cannot be!!
No! No! No! So it must be so that all this effort
made loads of sense!«
- »Therefore, I will now recommend even to someone who
might have been born after 1995 that he should start
programming using Pascal.«
That's a very complicated and, if I may say so, a rather patronising way
of describing a very simple experience: people who are good at something
have some reason (however unscientific) to think it might be related to
how they learned to do it. They may be wrong, but it's something of a
stretch to conclude that it *must* be a post-hoc rationalisation of the
time wasted. It seems to me much more likely that, in most cases, there
is no dissonance at all, for that requires us to know that the time was
wasted and I'll bet few of us know that, even if, in fact, it was.

I do think there is a problem, though, for it is easy to get into a
rather conservative frame of mind where one images that the best way to
learn must be the way you learned, or at least something similar to it.
(After all, you teach at a great university -- you must have had a great
education!). But that can (and should) be countered without dissonance
theory being involved. Indeed it may apply even if, in fact, you did
have the very best education possible -- that's insufficient reason to
assume that it still is the best.

And the advantage of seeing it that way is that you don't get everyone's
goat up.
--
Ben.
Stefan Ram
2014-07-18 16:34:23 UTC
Permalink
Subject: Why manually allocating memory instead of standard stack memory?
I prefer something with a finite verb after »why«, like:

Why does one use dynamic memory instead of automatic memory?
int arr[] = malloc((sizeof(int)) * 8);
int arr[8];
This can be required when the memory should outlife the
duration of the execution of the block.

It also allows to detect and handle an out-of-memory
condition at run time.
Evgeney Knyazhev
2014-07-21 02:04:08 UTC
Permalink
Post by Omar Radwan
int arr[] = malloc((sizeof(int)) * 8);
int arr[8];
typedef struct Person
{
int age;
float height;
float weight;
char name[];
};
struct Guy Bobby = malloc(sizeof(Guy))
when someone could just call it in as
struct Guy Bobby;
Omar, if you deal w/ huge arrays -- it needs to free memory from dead data. 2nd moment, dynamic heaps are maximally suited for multithreaded code. 3rd thinge, stack doesn't allow to change array's size on-fly. frankly, memory management always has been amongst damnest crapola in programming. XD
John Bode
2014-07-21 16:54:49 UTC
Permalink
Post by Omar Radwan
I'm a beginner C programmer, it's my first programming language. Honestly,
I think I chose the right language.
That feeling probably won't last. C makes a *lousy* teaching language. It's
a great systems and app programming language, but as a first language, it
has more than its share of flaws.
Post by Omar Radwan
All the other languages have something that I don't agree with. But a
int arr[] = malloc((sizeof(int)) * 8);
That should be

int *arr = malloc...;

instead of

int arr[] = malloc...;

"malloc" returns a pointer value, so "arr" has to be declared with a pointer
type (arrays and pointers are *not* the same thing).

A preferred way of writing that would be

int *arr = malloc( sizeof *arr * 8 );

The expression "*arr" has type "int", so "sizeof *arr" will return the same
value as "sizeof (int)". This way, If you ever change the type of "*arr"
(say from "int" to "long"), then you only have to make the change in one
place.
Post by Omar Radwan
int arr[8];
There are two reasons why you would do this.

1. You don't know how many elements you need until runtime;
2. You want to create a *really big* array.

You won't always know that you need to set aside 8 (or 10, or 100, or whatever)
elements in the array ahead of time, or the array may need to grow or shrink
as the program runs. Using dynamic memory allocation means you can set aside
exactly the amount of memory you need based on runtime inputs.

The pool of memory for auto variables (aka the stack) may be fairly limited,
and trying to declare *very large* arrays (megabyte or larger) at block scope
may lead to a runtime error. The dynamic memory pool (aka the heap) is typically
much larger, and it allows you to (potentially) set aside *very large* blocks
of memory.

C99 introduced variable-length arrays. Unlike regular arrays, their size isn't
established until runtime, like so:

int size = some_value();
int arr[size];

Like regular arrays, memory for VLAs is allocated from the stack, so like
regular arrays they can't be used for *very large* objects. They cannot be
used as struct members, nor can they be declared "static" or appear outside
of a function.

Also, VLA support has always been a little spotty, and as of the 2011 standard
they are optional, so you can't always count on them being available. They can
be *very* useful in some circumstances, though.
Post by Omar Radwan
typedef struct Person
{
int age;
float height;
float weight;
char name[];
};
struct Guy Bobby = malloc(sizeof(Guy))
should be

struct Guy *Bobby = malloc( sizeof *Bobby );
Post by Omar Radwan
when someone could just call it in as
struct Guy Bobby;
Same deal; you don't know how many structs you need until runtime, or you need
to allocate a *very large* object.

Once you start learning about basic data structures like lists and trees,
you'll start to see where and how dynamic memory comes in to play (you don't
*need* dynamic memory to implement those structures, but it makes life a lot
easier).
Loading...