Help a beginner - simple lowercase to uppercase and so on function

B

Beej Jorgensen

bartc said:
How about here:

int main(int argc, char **argv) ?

Nothing is fundamentally wrong with modifying those, or the strings
pointed to by argv:

C99 5.1.2.2.1p2:
# The parameters argc and argv and the strings pointed to by the argv
# array shall be modifiable by the program, and retain their last-stored
# values between program startup and program termination.

I've seen argc modified in command line parsing, and it's not entirely
rare in Unix to modify argv which can, on some(?) Unices, cause the "ps"
command to show different values for the names of running programs.

Personally, I leave argc and argv as-is--but I acknowledge there is no
reason for that other than preference.
Parameters are always input data to a C function. You can modify them if
they are not quite right, or if they are doing double duty as local
variables. But usually they are left alone.

One argument for leaving them alone might be one of code maintenance.
For instance, if one is modding a large function and sees parameter
numCPUs, one is probably going to expect it contains the number of CPUs.
But this assumption will be wrong at the end of the function if there is
something like a while(numCPUs--) loop in there somewhere. (A point
which would be caught with a code read or test, but then you're just
going to need to store numCPUs in another temp variable, anyway...)

As inputs to the function, I feel there is something slightly more
sacred to the parameters than typical local variables, I guess! If
sqrt() gets parameter x, its entire external world is x; everything it
needs to know about everything needed for its calculation is x*. So I
suppose I'd prefer to leave its modification until the end of the
function when its no longer needed (e.g. in strcpy(), feel free to
modify the "src" parameter because it happens at the end of the
function.)

-Beej

* exceptions aside
 
B

bartc

Beej Jorgensen said:
Nothing is fundamentally wrong with modifying those, or the strings
pointed to by argv:

C99 5.1.2.2.1p2:
# The parameters argc and argv and the strings pointed to by the argv
# array shall be modifiable by the program, and retain their last-stored
# values between program startup and program termination.

I don't understand how this applies to argc which is a copy of the value
provided by the environment. main() is free to do what it likes with it. And
surely the actual number of command params provided cannot be changed
anyway.
I've seen argc modified in command line parsing, and it's not entirely
rare in Unix to modify argv which can, on some(?) Unices, cause the "ps"
command to show different values for the names of running programs.

Well that comes under:

Although modifying *argv or **argv has nothing to do with modifying (value)
parameters.
One argument for leaving them alone might be one of code maintenance.
For instance, if one is modding a large function and sees parameter
numCPUs, one is probably going to expect it contains the number of CPUs.
But this assumption will be wrong at the end of the function if there is
something like a while(numCPUs--) loop in there somewhere. (A point
which would be caught with a code read or test, but then you're just
going to need to store numCPUs in another temp variable, anyway...)

Exactly. Either a lot of care is needed or numCPUs should be renamed so it's
not quite so specific.
 
S

spinoza1111

Leave him be; he's single-handedly keeping this group alive it seems to me.

Heathfield is a bully. His *modus operandi* is to say something
wounding and critical that makes him the wise, all-knowing Parent and
his mark the Child in such a way that any self-defense from the latter
can be dismissed as whining. He enables other posters to then attack
the mark *du jour*.

Because his own accomplishments are very small, he especially enjoys
trying to destroy reputations of people who make real contributions
including Jacob Navia and Herbert Schildt.

Here, the OP exposes his vulnerability and like a real man questions
his own behavior. This opened him up to an attack from Heathfield, who
never with any sincerity questions his own world view, up to and
including Heathfield's self-serving claims about the "power" of C.

Heathfield is a homophobe and a religious fundamentalist who is made
anxious when two male posters have a friendly and equal exchange where
they admit their own limitations. This, I believe, is why he so
constantly feels the need to interrupt conversations where he is not
wanted.

He relies on the corporate assumption that there is, or should be, no
seniority or expertise EXCEPT seniority and expertise as a form of
terror, which can destroy people.

He is a cold and malicious person. Please just ignore him.
 
S

spinoza1111

I modify parameters at every given opportunity.

That's a large part of the point of having parameters.

I've never written a prototype with a const qualified parameter.

That's C's pathology in a nutshell. Don't piss out the window. In
Beautiful Code, Brian Kernighan exhibits "beautiful" code which uses a
parameter as a work area. He thinks it's kewl. It is not.

Part of programming maturity is realizing that you DON'T have the
right to modify things.
 
J

jacob navia

Richard said:
spinoza1111 said:


Realising falsehoods is hardly mature.

If you don't wish to modify the parameter, const-qualify it. If you
do, don't. Whether you have the right to modify parameters is
properly a decision for you, the programmer, to make.

Modifying a functions parameters is always a bad idea.

o It makes the function not restartable.

o Under the debugger you can't know what was the parameter
you received when the function misbehaves. You can't debug it.

o The small gain in storage you gain is not worth the
associated risks.
 
B

Ben Pfaff

Richard Heathfield said:
What risk do you see in:

void intcopy(int *s, int *t, int term)
{
while((*s++ = *t++) != term) {}
}

that isn't also present in:

void intcopy(int *s, int *t, int term)
{
int *u = s;
int *v = t;
while((*u++ = *v++) != term) {}
}

I would say that the latter is riskier, because there are more
entities for me to keep track of as I read it. It is easier to
understand the behavior of three variables than five.
 
B

bartc

Richard Heathfield said:
jacob navia said:
What risk do you see in:

void intcopy(int *s, int *t, int term)
{
while((*s++ = *t++) != term) {}
}

It's more of a problem in this form:

void intcopy(int *dest, int *source, int term)
{
while((*dest++ = *source++) != term) {}
}

At the end of the while loop, dest and source don't point where you might
expect from their names, at least for someone looking to extend it.

And (a bit of a long-shot), if your code is ported to a language where
parameters are passed by reference, it may generate side-effects in the
caller.
 
B

bpascal123

--
Nick Keighley

"Programs must be written for people to read, and only
incidentally for machines to execute."
- Abelson & Sussman, Structure and Interpretation of Computer Programs

Thanks
 
S

spinoza1111

Modifying a functions parameters is always a bad idea.

o It makes the function not restartable.

o Under the debugger you can't know what was the parameter
   you received when the function misbehaves. You can't debug it.

o The small gain in storage you gain is not worth the
   associated risks.- Hide quoted text -
A Daniel, a Daniel come to judgement. Five star post.
 
S

spinoza1111

jacob navia said:





I disagree. So do K&R (in K&R2, at least). See p105.


You lost me. I am sure it is possible to construct a function in
which modifying its parameter makes it non-restartable, but you
don't /have/ to construct functions that way.

He lost you. You cannot interrupt the function in the debugger, make a
correction to the source, and restart the function from the beginning,
because it's changed its parameter. You can reset the parameter but
that's one more detail.

A real programmer has a strong idea in his mind of a pure zuivere
reine Procedure operating on distinct data.
Maybe you can't, but I can - by setting a breakpoint at an
appropriate place and making a note of the value before the mod.


What risk do you see in:

void intcopy(int *s, int *t, int term)
{
  while((*s++ = *t++) != term) {}

}

that isn't also present in:

void intcopy(int *s, int *t, int term)
{
  int *u = s;
  int *v = t;
  while((*u++ = *v++) != term) {}

}

Semantically as opposed to syntactically, the programs are identical.
If their INTENT is to modify s and t neither suck and the first is
better. We're talking about the modification of value parameters as
seen in Dennis Ritchie's scanner as reproduced in Beautiful Code.

A real programmer doesn't piss on value parameters even though they
are copies of original values on the stack, because before becoming a
coding ape, a real programmer studied real math. He has learned the
power of functions.
 
P

Phil Carmody

Richard Heathfield said:
jacob navia said:


I disagree. So do K&R (in K&R2, at least). See p105.


You lost me. I am sure it is possible to construct a function in
which modifying its parameter makes it non-restartable, but you
don't /have/ to construct functions that way.

I conclude he's got an allergy to, or a phobia of, tail recursion.
And probably other wonderfully useful programming paradigms too, I
wonder.

Phil
 
P

Phil Carmody

bartc said:
It's more of a problem in this form:

void intcopy(int *dest, int *source, int term)
{
while((*dest++ = *source++) != term) {}
}

At the end of the while loop, dest and source don't point where you
might expect from their names, at least for someone looking to extend
it.

Nope, you're thinking of this form:

void intcopy(int *deststart, int *sourcestart, int term)
{
while((*deststart++ = *sourcestart++) != term) {}
}

Phil
 
S

spinoza1111

I conclude he's got an allergy to, or a phobia of, tail recursion.
And probably other wonderfully useful programming paradigms too, I
wonder.

His practice makes it rather hard to optimize compilers. Of course C
optimizers will not if competently written confuse a parameter without
const with a read-only parameter. But the clowns here who are proud of
the studly way they modify non-const parameters passed by value and
without taking the address aren't even aware of how their code can't
be improved by an optimizer, or they are proud of this fact.

Using a non-const parameter without & is like the consultant who
borrows your watch to tell you the time, and walks away with the
watch. The caller never sees these monkeyshines: HIS copy of the
variable is unchanged. Nonetheless the programmer has offended against
the notion of a software contract.

Many runtimes will access local variables faster than parameters
especially for modification. The storage efficiency of munging a
parameter is canceled here by time inefficiency.

And there always remains the practical fact that good C programmers,
especially those coming in from safe languages, will always be
surprised to find that the non-const, non-ref parameter's input value
has changed when they need the original value after the end of the
loop.

Modifying these parameters is bad style.
 
B

bartc

Phil Carmody said:
Nope, you're thinking of this form:

void intcopy(int *deststart, int *sourcestart, int term)
{
while((*deststart++ = *sourcestart++) != term) {}
}

OK, more like this then:

void intcopy(int *originaldeststart, int *originalsourcestart, int term)
{
while((*originaldeststart++ = *originalsourcestart++) != term) {}
}
 
N

Nick Keighley

Richard Heathfield wrote:


Modifying a functions parameters is always a bad idea.

o It makes the function not restartable.

o Under the debugger you can't know what was the parameter
   you received when the function misbehaves. You can't debug it.

o The small gain in storage you gain is not worth the
   associated risks.

how do you return more than one thing?

ErrorCode calculate_average (double *average,
const int values[],
int count);

how would you code this?

void swop (int *n, int *m);
 
J

jacob navia

Nick said:
Richard Heathfield wrote:

Modifying a functions parameters is always a bad idea.

o It makes the function not restartable.

o Under the debugger you can't know what was the parameter
you received when the function misbehaves. You can't debug it.

o The small gain in storage you gain is not worth the
associated risks.

how do you return more than one thing?

ErrorCode calculate_average (double *average,
const int values[],
int count);

The value the calculate-average receives is the address
where it should store the result. That value is not modified
at all!

how would you code this?

void swop (int *n, int *m);

Same as above
 
D

Dik T. Winter

> Using a non-const parameter without & is like the consultant who
> borrows your watch to tell you the time, and walks away with the
> watch.

What is the sense of using '&' with a non-const parameter in C?
 
S

spinoza1111

how do you return more than one thing?

You don't use C. Or, didn't your mother teach you about structs?

   ErrorCode calculate_average (double *average,
                                const int values[],
                                int count);

how would you code this?

I wouldn't. Although it is "good" C, sub specie aeternitatis it's
actually a bone-head mess.

You have two pieces of information in two different places, and if
count is incorrect, you will wind up crashing...or using random data
with no error indication whatsoever.

And DON'T start that shit about "competent programmers", because it's
stupid and macho talk. YOU have no control over the subroutine
parameters as passed, and note that you CANNOT check count for
correctness.

Whereas in a modern language, "count" wouldn't be necessary being the
upper bound.

But even competent programmers in older languages such as Fortran knew
how to minimize the number of different things being returned which
you don't. Void the return but return something that cannot
mathematically be a sensible average in "average".
 
S

spinoza1111

...
 > Using a non-const parameter without & is like the consultant who
 > borrows your watch to tell you the time, and walks away with the
 > watch.

What is the sense of using '&' with a non-const parameter in C?

Clarification: I meant a non-const parm not declared using the inverse
operator *, but it was pretty obvious what I meant. Part of the
problem, and I've said this before, is that Ritchie designed-in some
fairly perverse thought patterns in order to be cute as a member of a
protected technical caste. This means that it's impossible to speak
with either intelligence or elegance about C.
 
D

Dik T. Winter

>
> Clarification: I meant a non-const parm not declared using the inverse
> operator *, but it was pretty obvious what I meant. Part of the
> problem, and I've said this before, is that Ritchie designed-in some
> fairly perverse thought patterns in order to be cute as a member of a
> protected technical caste.

Value parameters that act as local variables is not entirely newly thought
off by Ritchie...
 

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,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top