Critique my assignment please

P

pete

CBFalconer said:
On Aug 23, 6:12 pm, (e-mail address removed) wrote:
[snip]
unsigned NumberFromUpperLetter(char const x) {
assert(isupper(x));

switch (x)
{
case 'A': return 1; case 'B': return 2; case 'C': return 3;
case 'D': return 4; case 'E': return 5; case 'F': return 6;
case 'G': return 7; case 'H': return 8; case 'I': return 9;
case 'J': return 10; case 'K': return 11; case 'L': return 12;
case 'M': return 13; case 'N': return 14; case 'O': return 15;
case 'P': return 16; case 'Q': return 17; case 'R': return 18;
case 'S': return 19; case 'T': return 20; case 'U': return 21;
case 'V': return 22; case 'W': return 23; case 'X': return 24;
case 'Y': return 25; case 'Z': return 26;
}
}

A possibly minor point: there is no return statement executed in
the case that x is not one of 'A'-'Z'.

Foully overlong and tricky to write code, IMO. Try:

unsigned NumberFromUpperLetter(char const x) {
static const char UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";

static const char *UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int ch;
char *p;

ch = toupper((unsigned char)x);
if (p = strchr(UC, ch)) return p - &UC[0];
else return 0;
} /* untested */

Note the absence of any foul assert calls. All non-letters return
zero. By changing the function name and the string UC you can
search and convert any collection of chars. Works regardless of
the char set in effect.
 
M

Martin Wells

pete:

(In the context of a local variable within a function)
static const char *UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";

In the original example, there was a little bit of merit in declaring
the array as static:

static char const letters[] = ...

The "little bit of merit" to which I allude is that, if we'd instead
chosen not to define it as static, then the final executable might
store the string on a stack -- which is what we don't want in terms of
efficiency.

However, pete, I don't see why you'd bother making "UC" static.

Using "static" as an optimisation for local variables is usually only
done for arrays and such because of their size.

Of course, it could be argued that we shouldn't be using "static" at
all for this purpose because it's the *compiler's* job to make things
work well, but nonetheless I don't see why you'd go to the bother of
making a simple pointer static.

Martin
 
I

Ian Collins

Martin said:
pete:

(In the context of a local variable within a function)
static const char *UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";

In the original example, there was a little bit of merit in declaring
the array as static:

static char const letters[] = ...

The "little bit of merit" to which I allude is that, if we'd instead
chosen not to define it as static, then the final executable might
store the string on a stack -- which is what we don't want in terms of
efficiency.

However, pete, I don't see why you'd bother making "UC" static.

Using "static" as an optimisation for local variables is usually only
done for arrays and such because of their size.
It probably makes no difference in the case of a string literal.
 
P

pete

Martin said:
pete:

(In the context of a local variable within a function)
static const char *UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";

In the original example, there was a little bit of merit in declaring
the array as static:

static char const letters[] = ...

The "little bit of merit" to which I allude is that, if we'd instead
chosen not to define it as static, then the final executable might
store the string on a stack -- which is what we don't want in terms of
efficiency.

However, pete, I don't see why you'd bother making "UC" static.

You're right, I didn't pay proper attention to the code.
What I did was to make UC into a pointer.
CBFalconer made a typo and declared UC as a (static const char).

Maybe a little better might be:

const char *const UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
P

pete

Martin said:
pete:

(In the context of a local variable within a function)
static const char *UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";

In the original example, there was a little bit of merit in declaring
the array as static:

static char const letters[] = ...

The "little bit of merit" to which I allude is that, if we'd instead
chosen not to define it as static, then the final executable might
store the string on a stack -- which is what we don't want in terms of
efficiency.

I don't consider things like "the stack" and "the heap"
on this newsgroup.
The pointer declaration, defines two objects:
1 the pointer,
2 and the object refered to by the string literal.
The object refered to by the string literal, has static duration.
However, pete, I don't see why you'd bother making "UC" static.

Using "static" as an optimisation for local variables is usually only
done for arrays and such because of their size.

Of course, it could be argued that we shouldn't be using "static" at
all for this purpose because it's the *compiler's* job to make things
work well, but nonetheless I don't see why you'd go to the bother of
making a simple pointer static.

If we consider the choice as being between
static const char *UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
and
const char *UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
then the merit of the first,
is that the initialization occurs only once,
and the merit of the second is that it doesn't
define an extra object with static duration.
It doesn't really make much difference to me.

I like
static char const letters[] = ...
just fine.

A definition like
static char const letters[] = {'\0'};
defines only one object.

I've debated whether or not a definition like
static char const letters[] = "";
defines two objects. I think it doesn't.

The standard says that two definitions like
the ones shown above here for the letters array, are identical;
The question is: Just exactly how identical are they?
 
M

Martin Wells

pete:
I don't consider things like "the stack" and "the heap"
on this newsgroup.


Indeed the Standard doesn't mention them. If we're writing code which
we expect to perform efficiently though, then I think we have to pay a
little attention to how 99% (if not 100%) of implementations actually
get things done. Isn't that what led to the popularity of "*p++"? Even
with that said though, and I think you've implied, there's no
guarantee that static local data won't use a stack, or that automatic
local data will. I wouldn't be surprised at all if a compiler made
identical machine code for:

static char const letters[] = ...

and:

char const letters[] = ...

If we consider the choice as being between
static const char *UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
and
const char *UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
then the merit of the first,
is that the initialization occurs only once,
and the merit of the second is that it doesn't
define an extra object with static duration.


Actually, rather than any initialisation taking place at all, I
wouldn't expect either of them to result in the formation of a
variable in which to store the address of the string literal -- but
rather for it to work something like a #define.

I've debated whether or not a definition like
static char const letters[] = "";
defines two objects. I think it doesn't.

From what I can see, that should create an array of char's of length
1, and the single element should be a null character. Quite identical
to:

static char const letters[1] = "";

and:

static char const letters[1] = {'\0'};

Martin
 
M

Martin Wells

I've debated whether or not a definition like
static char const letters[] = "";
defines two objects. I think it doesn't.
From what I can see, that should create an array of char's of length

1, and the single element should be a null character. Quite identical
to:

static char const letters[1] = "";

and:

static char const letters[1] = {'\0'};


I messed up my editing there. That shuda read:
From what I can see, that should create an array of char's of length
1, and the single element should be a null character. Quite identical
to:

static char const letters[1] = "";


and:


static char const letters[1] = {'\0'};
 
P

pete

Martin said:
pete:


Indeed the Standard doesn't mention them. If we're writing code which
we expect to perform efficiently though, then I think we have to pay a
little attention to how 99% (if not 100%) of implementations actually
get things done.

What I mostly discuss on this newgroup,
is the meaning of the C code.
I'm more interested what the code can do on the DS9K
than I am in what it does on a Windows box.
Isn't that what led to the popularity of "*p++"?

I read about it in K&R.
It says that the notational convenience is considerable
and that the idiom should be mastered,
if for no other reason
than that it is frequently seen in C programs.
Even
with that said though, and I think you've implied, there's no
guarantee that static local data won't use a stack, or that automatic
local data will. I wouldn't be surprised at all if a compiler made
identical machine code for:

static char const letters[] = ...

and:

char const letters[] = ...
If we consider the choice as being between
static const char *UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
and
const char *UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
then the merit of the first,
is that the initialization occurs only once,
and the merit of the second is that it doesn't
define an extra object with static duration.

Actually, rather than any initialisation taking place at all, I
wouldn't expect either of them to result in the formation of a
variable in which to store the address of the string literal -- but
rather for it to work something like a #define.

Like I said, I'm more interested in the meaning of the code.
I can microoptimise along with the best of them;
I don't need to discuss that here.

The most obvious difference in the meaning of those
two declarations, is that the address of UC
can only be returned from a function if UC is declared static.
Likewise for the address of letters in your above two examples.
I've debated whether or not a definition like
static char const letters[] = "";
defines two objects. I think it doesn't.
From what I can see, that should create an array of char's of length
1, and the single element should be a null character. Quite identical
to:

static char const letters[1] = "";

and:

static char const letters[1] = {'\0'};

Whether or not the "" string literal refers to an object
in the array initialisation is entirely academic,
because if it does,
then it refers to an anonymous object whose address
can't be known by the program.
 
C

CBFalconer

Ian said:
Martin said:
pete:

(In the context of a local variable within a function)
static const char *UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";

In the original example, there was a little bit of merit in
declaring the array as static:

static char const letters[] = ...

The "little bit of merit" to which I allude is that, if we'd
instead chosen not to define it as static, then the final
executable might store the string on a stack -- which is what
we don't want in terms of efficiency.

However, pete, I don't see why you'd bother making "UC" static.

Using "static" as an optimisation for local variables is usually
only done for arrays and such because of their size.

It probably makes no difference in the case of a string literal.

I originally created the code using the array (not a pointer). The
idea was that a static array is stored fully initialized in the
code file, and is simply read into place. The const prevents
changing that array after initialization. This operation does not
have the heavy overhead that a non-static array would induce.
These facts are not universal, but often apply.
 
C

CBFalconer

pete said:
.... snip ...

You're right, I didn't pay proper attention to the code.
What I did was to make UC into a pointer.
CBFalconer made a typo and declared UC as a (static const char).

No typo. See the discussion I just posted.
 
R

Richard Heathfield

CBFalconer said:
No typo. See the discussion I just posted.

Sure looked like a typo to me. You may have meant to create an array,
but what you actually created was a char, and then you initialised it
illegally.
 
C

CBFalconer

Richard said:
CBFalconer said:

Sure looked like a typo to me. You may have meant to create an
array, but what you actually created was a char, and then you
initialised it illegally.

I disagree. Here is a copy and paste from my original message:

static const char UC = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";

Woops - now I see the missing []. Abject apologies. At least I
marked the code as untested.
 
A

Army1987

char string[32767];
C89 does not require an implementation to allow more than 32 KB
of auto variables.
It is not an auto variable.
Whoops... snipped too much. Sorry for that. (I'd better check in
the *original* code before making such comments, next time. I was
mis-remembering having seen it declared in main.)
<pedantry level="somewhat high">
If it is not declared as static and it has file scope, it has
external linkage. You aren't allowed to use the identifier
'string ' with external linkage. See 7.1.3.
</pedantry>
(fx:blush) Ok, I'll stop it...
 
P

pete

Army1987 said:
char string[32767];
C89 does not require an implementation to allow more than 32 KB
of auto variables.

This thread, as you have quoted it here,
makes it seem as though the person who wrote that sentence,
thinks that 32767 excedes some translation limit in C89,
which it doesn't.

And it also makes it seem as though the translation
limit applies only to objects with automatic duration,
which as far as I can tell from the standard, it doesn't.

ISO/IEC 9899: 1990
5.2.4.1 Translation limits

— 32767 bytes in an object (in a hosted environment only)
 
A

Army1987

I find such informal (ab)use of big-O notation often leads to nothing
but confusion when its semantics start being discussed, and downright
misleading for people who are not very familiar with big-O. Formally
speaking, the "runtime" of our function actually lies in each of O(1),
O(n), O(n^2), O(2^n), O(n^n), and (infinitely) many more distinct
classes of functions. Informal usage of "O(f(n))" is almost always
meant to correspond to the lesser-known Theta(f(n)) function class.
Not really. One would usually say that randomly shuffling an array
of N elements needs O(N log N) bits of entropy, but lg(N!) is not
Theta(N log N). Of course one usually tries to avoid ridiculous
overestimates when tighter ones are available, one doesn't claim
linear search to require O(busy_beaver(ackermann(n, n))) time when
we could say O(n), but in other cases one just finds a reasonable
upper bound.

(And virtually all the use of the big-O notation for runtime of
algorithms are abuse of notation. Does anybody care how long does
it take to sort an array of one googolplex members? If not, one
should a fortiori not care about the asymptotic behavior, which is
unrelated to the behavior of a function for the first few values
of N, even if by 'few' we mean busy_beaver(Graham's number).)
 
P

pete

Martin said:
pete:


Indeed the Standard doesn't mention them. If we're writing code which
we expect to perform efficiently though, then I think we have to pay a
little attention to how 99% (if not 100%) of implementations actually
get things done.

The most important skill that you can learn and develop
from following this newsgroup, is how to write C code
that means exactly what you think it means.
 
M

Martin Wells

pete:
The most important skill that you can learn and develop
from following this newsgroup, is how to write C code
that means exactly what you think it means.

If intelligibility of the code to the reader was the only concern,
then my code would look different. I have other concerns:

1) Execution speed
2) Resource consumption
3) Portability
4) Reliability

If you focus too much on making it understandable to chimpanzee, then
it will suffer in other areas.

Martin
 
E

Eric Sosman

Martin Wells wrote On 08/27/07 17:11,:
pete:




If intelligibility of the code to the reader was the only concern,
then my code would look different. I have other concerns:

1) Execution speed
2) Resource consumption
3) Portability
4) Reliability

If you focus too much on making it understandable to chimpanzee, then
it will suffer in other areas.

If you focus too much on *anything* it will suffer in
other areas -- that's what "too much" means.

Considering your list of concerns, what can we infer
from the fact that speed is uppermost and reliability last?
 
O

Old Wolf

In answer to the first recommendation, I have delegated the error
checking elsewhere so that it's simply not possible for an error to
occur in the function.

I invite you to save this message, and read it
again for your amusement once you have a few
years of professional programming under your belt :)
 
P

pete

Martin said:
pete:


If intelligibility of the code to the reader was the only concern,

That has absolutely nothing to do with what I just wrote.

I'm talking about you learning the language well enough
so that you know the exact meaning
of what you yourself are writing.
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,815
Latest member
treekmostly22

Latest Threads

Top