Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Why can I not alloc memory in called function?

Reply
Thread Tools

Why can I not alloc memory in called function?

 
 
Ben Bacarisse
Guest
Posts: n/a
 
      07-25-2010
Barry Schwarz <(E-Mail Removed)> writes:

> On Sat, 24 Jul 2010 21:04:56 -0500, "osmium" <(E-Mail Removed)>
> wrote:
>
>>"Ike Naar" wrote:
>>
>>> In article <(E-Mail Removed)>,
>>> osmium <(E-Mail Removed)> wrote:
>>>>So it is your belief that error reporting is sufficient if the user can
>>>>deduce that the proper side effects occurred?
>>>
>>> If it is expected that the caller can handle the error in a better way
>>> than the function can, then the function should just notify the caller
>>> that an error occurred, and leave the handling to the caller.
>>>
>>> Several functions from the standard library (e.g. malloc, fopen) work just
>>> like that.

>>
>>No they don't! malloc returns a void*, and NULL is a legitimate value that
>>can be assigned to a void*.

>
> 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>
--
Ben.
 
Reply With Quote
 
 
 
 
osmium
Guest
Posts: n/a
 
      07-25-2010

"Ben Bacarisse" wrote:

> Barry Schwarz <(E-Mail Removed)> writes:
>
>> On Sat, 24 Jul 2010 21:04:56 -0500, "osmium" <(E-Mail Removed)>
>> wrote:
>>
>>>"Ike Naar" wrote:
>>>
>>>> In article <(E-Mail Removed)>,
>>>> osmium <(E-Mail Removed)> wrote:
>>>>>So it is your belief that error reporting is sufficient if the user can
>>>>>deduce that the proper side effects occurred?
>>>>
>>>> If it is expected that the caller can handle the error in a better way
>>>> than the function can, then the function should just notify the caller
>>>> that an error occurred, and leave the handling to the caller.
>>>>
>>>> Several functions from the standard library (e.g. malloc, fopen) work
>>>> just
>>>> like that.
>>>
>>>No they don't! malloc returns a void*, and NULL is a legitimate value
>>>that
>>>can be assigned to a void*.

>>
>> 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?".


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.



 
Reply With Quote
 
 
 
 
Stephen Sprunk
Guest
Posts: n/a
 
      07-26-2010
On 24 Jul 2010 16:37, Eric Sosman wrote:
> On 7/24/2010 5:01 PM, Stephen Sprunk wrote:
>> However, the use of "output" parameters does not follow C conventions
>> and should be avoided when possible; it is more idiomatic to write:
>>
>> #include<stdlib.h>
>>
>> char* doit() {
>> char *allostring = malloc(6);
>> memcpy(allostring, "Hello\0", 6);

>
> 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

--
Stephen Sprunk "God does not play dice." --Albert Einstein
CCIE #3723 "God is an inveterate gambler, and He throws the
K5SSS dice at every possible opportunity." --Stephen Hawking
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      07-27-2010
On 7/26/2010 10:58 AM, Stephen Sprunk wrote:
> On 24 Jul 2010 16:37, Eric Sosman wrote:
>> On 7/24/2010 5:01 PM, Stephen Sprunk wrote:
>>> However, the use of "output" parameters does not follow C conventions
>>> and should be avoided when possible; it is more idiomatic to write:
>>>
>>> #include<stdlib.h>
>>>
>>> char* doit() {
>>> char *allostring = malloc(6);
>>> memcpy(allostring, "Hello\0", 6);

>>
>> 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.


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?"

--
Eric Sosman
http://www.velocityreviews.com/forums/(E-Mail Removed)lid
 
Reply With Quote
 
Stephen Sprunk
Guest
Posts: n/a
 
      07-27-2010
On 26 Jul 2010 20:27, Eric Sosman wrote:
> On 7/26/2010 10:58 AM, Stephen Sprunk wrote:
>> On 24 Jul 2010 16:37, Eric Sosman wrote:
>>> On 7/24/2010 5:01 PM, Stephen Sprunk wrote:
>>>> However, the use of "output" parameters does not follow C conventions
>>>> and should be avoided when possible; it is more idiomatic to write:
>>>>
>>>> #include<stdlib.h>
>>>>
>>>> char* doit() {
>>>> char *allostring = malloc(6);
>>>> memcpy(allostring, "Hello\0", 6);
>>>
>>> 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.

>
> 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?"


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

--
Stephen Sprunk "God does not play dice." --Albert Einstein
CCIE #3723 "God is an inveterate gambler, and He throws the
K5SSS dice at every possible opportunity." --Stephen Hawking
 
Reply With Quote
 
Nick Keighley
Guest
Posts: n/a
 
      07-27-2010
On 27 July, 15:54, Stephen Sprunk <(E-Mail Removed)> wrote:
> On 26 Jul 2010 20:27, Eric Sosman wrote:
> > On 7/26/2010 10:58 AM, Stephen Sprunk wrote:
> >> On 24 Jul 2010 16:37, Eric Sosman wrote:
> >>> On 7/24/2010 5:01 PM, Stephen Sprunk wrote:


> >>>> However, the use of "output" parameters does not follow C conventions
> >>>> and should be avoided when possible;


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:
>
> >>>> #include<stdlib.h>

>
> >>>> char* doit() {
> >>>> * * * char *allostring = malloc(6);
> >>>> * * * memcpy(allostring, "Hello\0", 6);

>
> >>> * * *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.


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


> > * * 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**);
and void f2 (char*);

> >> (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?"

>
> 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>


 
Reply With Quote
 
Stephen Sprunk
Guest
Posts: n/a
 
      07-27-2010
On 27 Jul 2010 10:16, Nick Keighley wrote:
> On 27 July, 15:54, Stephen Sprunk <(E-Mail Removed)> wrote:
>> On 26 Jul 2010 20:27, Eric Sosman wrote:
>>> On 7/26/2010 10:58 AM, Stephen Sprunk wrote:
>>>> On 24 Jul 2010 16:37, Eric Sosman wrote:
>>>>> On 7/24/2010 5:01 PM, Stephen Sprunk wrote:
>>>>>> However, the use of "output" parameters does not follow C conventions
>>>>>> and should be avoided when possible;
>>>>>
>>>>> 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.

>
> 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.

>>> 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.]

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

--
Stephen Sprunk "God does not play dice." --Albert Einstein
CCIE #3723 "God is an inveterate gambler, and He throws the
K5SSS dice at every possible opportunity." --Stephen Hawking
 
Reply With Quote
 
Nick Keighley
Guest
Posts: n/a
 
      07-28-2010
On 27 July, 18:54, Stephen Sprunk <(E-Mail Removed)> wrote:
> On 27 Jul 2010 10:16, Nick Keighley wrote:
> > On 27 July, 15:54, Stephen Sprunk <(E-Mail Removed)> wrote:
> >> On 26 Jul 2010 20:27, Eric Sosman wrote:
> >>> On 7/26/2010 10:58 AM, Stephen Sprunk wrote:
> >>>> On 24 Jul 2010 16:37, Eric Sosman wrote:
> >>>>> On 7/24/2010 5:01 PM, Stephen Sprunk wrote:

>
>
> >>>>>> However, the use of "output" parameters does not follow C conventions
> >>>>>> and should be avoided when possible;

>
> >>>>> 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.

>
> > 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.


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.

> >>> 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

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.


--

Programming should never be boring, because anything
mundane and repetitive should be done by the computer.
~Alan Turing
 
Reply With Quote
 
Stephen Sprunk
Guest
Posts: n/a
 
      07-29-2010
On 28 Jul 2010 02:15, Nick Keighley wrote:
> On 27 July, 18:54, Stephen Sprunk <(E-Mail Removed)> wrote:
>> On 27 Jul 2010 10:16, Nick Keighley wrote:
>>> On 27 July, 15:54, Stephen Sprunk <(E-Mail Removed)> wrote:
>>>> 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?

>> 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.


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

--
Stephen Sprunk "God does not play dice." --Albert Einstein
CCIE #3723 "God is an inveterate gambler, and He throws the
K5SSS dice at every possible opportunity." --Stephen Hawking
 
Reply With Quote
 
Nick Keighley
Guest
Posts: n/a
 
      07-29-2010
On 29 July, 06:15, Stephen Sprunk <(E-Mail Removed)> wrote:
> On 28 Jul 2010 02:15, Nick Keighley wrote:
> > On 27 July, 18:54, Stephen Sprunk <(E-Mail Removed)> wrote:
> >> On 27 Jul 2010 10:16, Nick Keighley wrote:


<snip>

> >>> You seem to be distinguising

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


<snip>

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

>
> > * * void return_value (value_t**);

>
> 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


> >> 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).


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]);
}

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


> > * *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.


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.

> >> 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.

>
> 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.


--

C++: "an octopus made by nailing extra legs onto a dog"
-- Steve Taylor, 1998


 
Reply With Quote
 
 
 
Reply

Thread Tools

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

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


Similar Threads
Thread Thread Starter Forum Replies Last Post
findcontrol("PlaceHolderPrice") why why why why why why why why why why why Mr. SweatyFinger ASP .Net 2 12-02-2006 03:46 PM
Memory alloc for a Function Ryan Wang C Programming 10 11-15-2005 10:54 AM
string vs const int memory alloc Vulcan Fire C Programming 6 04-19-2005 05:02 AM
How to increase the memory alloc for aspnet_wp.exe? Bob ASP .Net 1 02-13-2004 04:25 AM
Memory Alloc/Dealloc query B. Gandhi C Programming 6 09-25-2003 04:22 AM



Advertisments