Why can I not alloc memory in called function?

B

Ben Bacarisse

Barry Schwarz said:
Are you deliberately trying to be obtuse. The NULL value returned
does exactly what was suggested, notify the user that the request
failed.

I suspect there has been a misunderstanding. As you helpfully quote,
Ike Naar said:

| The function, as written by the OP, does nothing useful (well, it
| leaks some memory), but others have already explained how that can be
| fixed. If those fixes are applied, the caller can detect that a
| malloc failure occurred by looking at the function's output, which, in
| that case, is NULL.

There have been two suggested fixes. One would have a NULL return
on error, the other would set a char * argument (passed to a char **
parameter) to NULL on error. Both can be seen as the "the function's
output".

I *think* osmium is objecting to the clumsiness of testing for this side
effect and his/her "No they don't!" was because malloc and friends *do*
return a char * rather than setting one.

Just a guess, but I could not ascribe any other meaning to the original
objection: "So it is your belief that error reporting is sufficient if
the user can deduce that the proper side effects occurred?".

<snip>
 
O

osmium

Ben Bacarisse said:
I suspect there has been a misunderstanding. As you helpfully quote,
Ike Naar said:

| The function, as written by the OP, does nothing useful (well, it
| leaks some memory), but others have already explained how that can be
| fixed. If those fixes are applied, the caller can detect that a
| malloc failure occurred by looking at the function's output, which, in
| that case, is NULL.

There have been two suggested fixes. One would have a NULL return
on error, the other would set a char * argument (passed to a char **
parameter) to NULL on error. Both can be seen as the "the function's
output".

I *think* osmium is objecting to the clumsiness of testing for this side
effect and his/her "No they don't!" was because malloc and friends *do*
return a char * rather than setting one.

Just a guess, but I could not ascribe any other meaning to the original
objection: "So it is your belief that error reporting is sufficient if
the user can deduce that the proper side effects occurred?".

Yes, that's right, thank you, Ben, for reading what I wrote.

I'll have to try to remember that word "clumsy", it's not one that I use
very often. BTW osmium is a him :).

The language is such that one can call a function and see if it was
successful, all in a single statement, if the returned value is used to
indicate success or failure and C programmers are already experienced in
that idiom. The proposed method of testing the side effects abandons that
foundation with very little gain. Any time saved in coding is going to be
used up by extra documentation effort by the person who writes the code for
the function.
 
S

Stephen Sprunk

Note the "output parameter" in this call. It's possible, I
guess, for a Standard library function to have an unconventional
interface, but I see nothing unconventional about the first
arguments of memcpy, strcpy, strcat, sprintf, qsort, ...

Those functions modify the object that the argument points to, not the
argument itself.

(Yes, you can nit-pick that example, but I'm pretty sure you know what
I'm trying to say; I just can't get the wording right.)
(Also, if it's "more idiomatic" to omit checking malloc's
value for NULL, and "more idiomatic" to copy strings with hand-
counted memcpy than with strcpy, then I think a "t" has been
omitted somewhere.)

At the time I was more concerned with making minimal modifications to
the OP's program, and cluttering it up with error handling code would
have obscured the point I was making, but I'll admit I should have at
least put comments in indicating it was needed.

S
 
E

Eric Sosman

Those functions modify the object that the argument points to, not the
argument itself.

No C function can modify its arguments, not ever. It can modify
its parameters, but no caller can detect that it has or has not done
so.
(Yes, you can nit-pick that example, but I'm pretty sure you know what
I'm trying to say; I just can't get the wording right.)

Actually, I'm not at all sure what you're saying. The phrase
"output parameter," not defined in the Standard, seems to have
different meanings for us -- I thought I knew what you meant, but
given your follow-up I'm now quite sure that I don't know.

What's an "output parameter?"
 
S

Stephen Sprunk

No C function can modify its arguments, not ever. It can modify
its parameters, but no caller can detect that it has or has not done
so.


Actually, I'm not at all sure what you're saying. The phrase
"output parameter," not defined in the Standard, seems to have
different meanings for us -- I thought I knew what you meant, but
given your follow-up I'm now quite sure that I don't know.

What's an "output parameter?"

I'll be more verbose this time in hopes that will help.

To me, an "output parameter" is one whose value is written but not read
by the function. In C, this is not directly supported, so one has to
(ab)use pass-by-pointer syntax to get the same effect.

An example might help. This is the standard malloc() we all know:

void *malloc(size_t size)

Here, size is an input parameter and the only output of the function is
the return value; this is the normal C convention. However, malloc()
could have been designed like this:

void malloc(size_t size, void **ptr)

In this version, size is still an input parameter, but *ptr is an output
parameter of type (void *). One would expect this function to be called
like this:

void *ptr;
malloc(1, &ptr); // ptr modified

While not perfectly reliable, the unary & in a function argument is a
strong indication of an output parameter, as in this case.

<OT>
In C++, one could also redesign the function like this:

void malloc(size_t size, void *&ptr)

In this context, "&" indicates pass-by-reference, i.e. ptr is a
reference-to-pointer-to-void, and allows the function to be called like
this, with true output parameter semantics:

void *ptr;
malloc(1, ptr); // ptr modified
</OT>

Of course, some parameters could be both input and output, such as with
this redesigned realloc():

_Bool realloc(void **ptr, size_t size)

In this version, *ptr is an input/output parameter of type (void *),
size is still an input parameter, and the return value indicates whether
the call succeeded or failed. *ptr would be modified if realloc() had
to relocate the pointed-to object. This is arguably easier to use than
the standard realloc() but violates C conventions.

<OT>
The C++ version of this would be:

bool realloc(void *&ptr, size_t size)
</OT>

S
 
N

Nick Keighley

in what sense is an output parameter non-idiomatic? And who says the
standard library doesn't use them?
it is more idiomatic to write:

I think you're trying to be pedantic at this point


so he was pedantic back. We all know C can't modify the value of a
parameter (or at least the modified value doesn't escape from the
function). But as soon as you use the term "output parameter" I assume
you're talking about messing around with pointers. And that involves
"modifying the thing pointed to".

You seem to be distinguising

void f1 (char**);
and void f2 (char*);
I'll be more verbose this time in hopes that will help.

To me, an "output parameter" is one whose value is written but not read
by the function.
memcpy()?


 In C, this is not directly supported, so one has to
(ab)use pass-by-pointer syntax to get the same effect.

An example might help.  This is the standard malloc() we all know:

void *malloc(size_t size)

Here, size is an input parameter and the only output of the function is
the return value; this is the normal C convention.  However, malloc()
could have been designed like this:

void malloc(size_t size, void **ptr)

In this version, size is still an input parameter, but *ptr is an output
parameter of type (void *).  One would expect this function to be called
like this:

void *ptr;
malloc(1, &ptr);  // ptr modified

While not perfectly reliable, the unary & in a function argument is a
strong indication of an output parameter, as in this case.

<snip>
 
S

Stephen Sprunk

I think you're trying to be pedantic at this point

I'm not; I'm having difficulty finding the exact words to express what I
_thought_ was a well-understood concept.
so he was pedantic back. We all know C can't modify the value of a
parameter (or at least the modified value doesn't escape from the
function). But as soon as you use the term "output parameter" I assume
you're talking about messing around with pointers. And that involves
"modifying the thing pointed to".

You seem to be distinguising

void f1 (char **arg1);
and void f2 (char *arg2);

In a way. [Argument names added above.]

f1() might have an input parameter named arg1 of type (char **) or might
have an output parameter named *arg1 of type (char *).

f2() might have an input parameter named arg2 of type (char *) or might
have an output parameter named *arg2 of type (char).

(char *) is a special case that makes this more difficult because C
doesn't have a native string type. It's a lot easier to see with a
simpler type:

void f3(int *arg3);
void f4(int arg4);

arg4 is obviously an input parameter of type (int), but while arg3 _may_
be an input parameter of type (int *), it's much more likely that *arg3
is an output parameter of type (int).

Now that (I hope) I have established what I think "output parameter"
means, I can further explain my original comment: While one _can_ use
output parameters in C, the idea that a function should have a single
output seems pretty central to the design of the language itself, as
evidenced by only having one return value (i.e. output) and all
arguments (i.e. inputs) passed by value. If a function has multiple
outputs and therefore needs output parameters, it is "common knowledge"
that the function should be redesigned and/or broken up into multiple
functions, each with one output. And it seems very un-C-like to have a
function returning void with an output parameter, as the OP's code did.

S
 
N

Nick Keighley

I'm not; I'm having difficulty finding the exact words to express what I
_thought_ was a well-understood concept.

well "output parameter" was clear enough but your rejection of those
standard library functions as having "output" parameters kind of
muddied the waters. I sort of see what you mean. The C pointer
mechanism is being utilised to achieve two different things. Things
that are conceptually (and actually, in a higher level langauge)
different.

1. returning a values or values
2. modifying a value, especially an array

most of those stanmdard library functions are conceptually modifying
an array. Actually all of them are.
so he was pedantic back. We all know C can't modify the value of a
parameter (or at least the modified value doesn't escape from the
function). But as soon as you use the term "output parameter" I assume
you're talking about messing around with pointers. And that involves
"modifying the thing pointed to".
You seem to be distinguising
      void f1 (char **arg1);
and   void f2 (char *arg2);

In a way.  [Argument names added above.]

arguments not necessary on declarations

you are distinguishing (if I may put words in your mouth)

void return_value (value_t**);
void modify_array (value_t[]);

I often use array notation precisely for this reason. Thoght many clc
pedantic regulars (but I repeat myself) would argue that value_t[] is
*really* value_t* in disguise. And therefore it is clearer to use the
pointer form.
f1() might have an input parameter named arg1 of type (char **) or might
have an output parameter named *arg1 of type (char *).

f2() might have an input parameter named arg2 of type (char *) or might
have an output parameter named *arg2 of type (char).

(char *) is a special case that makes this more difficult because C
doesn't have a native string type.  It's a lot easier to see with a
simpler type:

void f3(int *arg3);
void f4(int arg4);

arg4 is obviously an input parameter of type (int), but while arg3 _may_
be an input parameter of type (int *), it's much more likely that *arg3
is an output parameter of type (int).

or it could be passing an array.

Now that (I hope) I have established what I think "output parameter"
means, I can further explain my original comment: While one _can_ use
output parameters in C, the idea that a function should have a single
output seems pretty central to the design of the language itself, as
evidenced by only having one return value (i.e. output) and all
arguments (i.e. inputs) passed by value.

returning a single value is common to most languages (there are
exceptions) and in line with normal mathematical usage
 If a function has multiple
outputs and therefore needs output parameters, it is "common knowledge"
that the function should be redesigned and/or broken up into multiple
functions, each with one output.

woo! Disturb not the sleeping Inner Pedant! It ain't common knowledge
to me!

void get_point_list (Point *point_list[], size_t *list_size, int
index);
Error_val queue_pop (Queue *q, int *value);

Some languages allow multiple return values. Presumably the designers
of such languages don't agree that all functions should return a
single value.

In fact C's usage of function is pretty weird. Algol-like languages
had functions that returned values (and if they'd been cleaner would
have forbidden side-effects) and procedures that didn't return
anything but had side effects such as modifying their arguments. Ada
for instance has "in", "out" and "in out" arguments.
 And it seems very un-C-like to have a
function returning void with an output parameter, as the OP's code did.

There are more things in C code, Horatio,
Than are dreamt of in your philosophy.
 
S

Stephen Sprunk

On 26 Jul 2010 20:27, Eric Sosman wrote:
No C function can modify its arguments, not ever. It can modify
its parameters, but no caller can detect that it has or has not done
so.
so he was pedantic back. We all know C can't modify the value of a
parameter (or at least the modified value doesn't escape from the
function). But as soon as you use the term "output parameter" I assume
you're talking about messing around with pointers. And that involves
"modifying the thing pointed to".
You seem to be distinguising
void f1 (char **arg1);
and void f2 (char *arg2);

In a way. [Argument names added above.]

arguments not necessary on declarations

Agreed, but I thought they helped make the following paragraph clearer.
you are distinguishing (if I may put words in your mouth)

void return_value (value_t**);

ITYM "void return_value (value_t*);" there.
void modify_array (value_t[]);

I often use array notation precisely for this reason. Thoght many clc
pedantic regulars (but I repeat myself) would argue that value_t[] is
*really* value_t* in disguise. And therefore it is clearer to use the
pointer form.

I use T* when I'm expecting to be passed a pointer to a single T and T[]
when I'm expecting to be passed an array of T, i.e. it's more an
indication of how many Ts I'm expecting rather than what I intend to do
with them. I think that's fairly conventional, but there's definitely
some debate there.
If a function has multiple outputs and therefore needs output
parameters, it is "common knowledge" that the function should be
redesigned and/or broken up into multiple functions, each with one
output.

woo! Disturb not the sleeping Inner Pedant! It ain't common knowledge
to me!

void get_point_list (Point *point_list[], size_t *list_size, int
index);

If I understand what that does correctly, and I'm not sure I do, I would
have returned a struct point_list that contained the size as well as the
points themselves (probably via the struct hack). I'm not sure what
your index parameter does, though, so maybe that wouldn't work.
Error_val queue_pop (Queue *q, int *value);

Error indications would be the common exception, and the C convention
for that is to stuff a "special" value (e.g. NULL or -1) into the return
value and/or some error code into errno.
In fact C's usage of function is pretty weird. Algol-like languages
had functions that returned values (and if they'd been cleaner would
have forbidden side-effects) and procedures that didn't return
anything but had side effects such as modifying their arguments.

I like that separation. I've always been a fan of GCC's notion of
"const" and "pure" functions; they make functions seem, well, more
pure--and may enable significant optimizations in their callers.
Ada for instance has "in", "out" and "in out" arguments.

I'm not familiar with Ada at all; does it have a concept similar to C's
return value, or do "out" (or "in out") arguments do that job?
There are more things in C code, Horatio,
Than are dreamt of in your philosophy.

Of course. However, I subscribe to the philosophy that the primary
audience for my code is other humans, not the compiler, so I strive to
make my code as "obvious" as possible, which IMHO means adhering to
established conventions and idioms. While the Standard Library isn't
perfect, it does provide a fairly consistent model for our own
interfaces that has been adopted equally consistent by most other
experienced programmers over the last several decades, and I'm certainly
not qualified to imply they're all wrong by doing something different.

S
 
N

Nick Keighley

ITYM "void return_value (value_t*);" there.

yes, I think I do!

    void modify_array (value_t[]);
I often use array notation precisely for this reason. [Though] many
[people] would argue that value_t[] is *really* value_t* in disguise.
And therefore it is clearer to use the pointer form.

I use T* when I'm expecting to be passed a pointer to a single T and T[]
when I'm expecting to be passed an array of T, i.e. it's more an
indication of how many Ts I'm expecting rather than what I intend to do
with them.  I think that's fairly conventional, but there's definitely
some debate there.

I'm with you here

woo! Disturb not the sleeping Inner Pedant! It ain't common knowledge
to me!
   void get_point_list (Point *point_list[], size_t *list_size,
int index);

If I understand what that does correctly, and I'm not sure I do, I would
have returned a struct point_list that contained the size as well as the
points themselves (probably via the struct hack).

not sure I would. I don't like hiding arrays in structs but that's
probably just a style thing.

 I'm not sure what
your index parameter does, though, so maybe that wouldn't work.

it would. I was thinking of code like this

void draw_alert_item (void)
{
Point_list *p_list;
size_t list_size;
int i;

/* get the 99th point list */
get_point_list (&p_list, &list_size, 99);

/* draw item */
for (i = 0; i < list_size; i++)
plot (p);
}

(I wouldn't *really* embed a majik number in my code!)

Error indications would be the common exception, and the C convention
for that is to stuff a "special" value (e.g. NULL or -1) into the return
value and/or some error code into errno.

yuk! In-band-signalling is Evil(tm). Every function has a different
way of returning an error. At least with the error return method I can
treat all functions the same (maybe wrap my error checking in a
macro). Some functions have no easy way of indicating an error. You've
got to call *another* function to find out exactly what went wrong.
Maybe C++ exceptions were not such a bad idea...

I have written software that used the Error_val method. Though I
tended to call it Return_val as Error_val == NO_ERROR tended to make
my hackles rise!
In fact C's usage of function is pretty weird. Algol-like languages
had functions that returned values (and if they'd been cleaner would
have forbidden side-effects) and procedures that didn't return
anything but had side effects such as modifying their arguments. [...]
Ada for instance has "in", "out" and "in out" arguments.

I'm not familiar with Ada at all; does it have a concept similar to C's
return value, or do "out" (or "in out") arguments do that job?

Ada (my knowledge is slim) has functions and procedures as well as the
"out" and "in out" parameters. Ada is Pascal with knobs on.
Of course.  However, I subscribe to the philosophy that the primary
audience for my code is other humans, not the compiler, so I strive to
make my code as "obvious" as possible,

I don't find "output parameters" particularly non-obvious.

which IMHO means adhering to
established conventions and idioms.  

up to a point... I don't see a problem in defining my own conventions.
Provided they're clear.
While the Standard Library isn't perfect,

no?

:)

I notice you didn't mention copying errno
it does provide a fairly consistent model for our own
interfaces

it's not *that* consistant!
that has been adopted equally consistent by most other
experienced programmers over the last several decades,

our experiences obviously differ!

and I'm certainly
not qualified to imply they're all wrong by doing something different.

I haven't seen "most other experienced programmers" copy the standard
library conventions as you suggest.
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top