No. of 'a' in a text file

K

Keith Thompson

James Kanze said:
Every coding guideline I've ever seen has forbidden defining
more than one variable per statement. It's just bad programming
practice. Other than that, it's mostly a matter of taste. I
find it cleaner to separate the type from what is being defined.

How do you manage that for arrays?

[...]
And the Unix way is exit(2).

It is?

<OT>
On Unix-like systems, EXIT_FAILURE is typically defined as 1. exit(0)
denotes success, and exit(1) commonly indicates some generic failure.
I know of no widespread convention for exit codes other than 0 and 1;
they tend to be defined individually for each command. One command,
curl, documents 76 distinct error codes.
</OT>

The C standard's exit(0), exit(EXIT_SUCCESS), and exit(EXIT_FAILURE)
are quite compatible with Unix conventions.
 
K

Keith Thompson

James Kanze said:
[...]
And when you're not doing that ungood thing, writing FILE* f makes sense.
There I disagree. If you're going to have declarations of any
significant complexity, you need to understand why C declaration are
the way they are (declaration follows use).

Except that declaration follows use went out of C the day
typedef's were introduced. And struct's, and all the rest. C's
declaration syntax is an experiment which failed. The basic
idea, applied to the very earliest C, seems interesting (and as
an experiment, was certainly worth doing), but it doesn't scale
properly once users start defining types.
With that understanding,
"FILE *f" just makes more sense.
FILE *f; /* *f is a FILE */
int a[10] /* a[10] is an int (or would be if it existed */

And what do you do once typedefs and user defined struct's enter
into the picture:

FILE is a typedef.
typedef int* Toto ;

I wouldn't declare a typedef for a pointer type unless I wanted to
make it opaque (so code using the type doesn't know it's a pointer).

But if I did, the above would still ollow the declaration-follows-use
model: t is a Toto.
struct MyStruct s ;

And s is a "struct Mystruct".
or from an actual program I wrote (about 20 years ago):

struct T
{
// ...
struct V* (*f[ 8 ])( struct V* ) ;
} ;
struct T a[] = {...} ;
, use:
s = (*p->f[j])( s ) ;

Any relationship between use and definition seems very tenuous,
at best.


Perhaps, but I think the underlying principle is still there. I'm too
lazy to wade through that declaration -- and I'm not *really* trying
to defend C's declaration syntax.
There is an argument based on grouping: at the very highest
level, a declaration breaks down into a declaration specifier
and a declarator; the * is part of the declarator. But on the
whole, I think it's just a lot cleaner to think in terms of the
resulting types: conceptually, I'm not declaring *p to be an
int, I'm declaring p to be an int*.

Which breaks down for

int a[10];

which, if C *didn't* use declaration-follows-use, would probably be:

int[10] a; /* not C 8/
You have to, if you're going to work in C or in C++:). The
declaration syntax is a disaster, but it has to be learned and
lived with. I use Type*, rather than Type *, because that's
what is most frequent in C++, but I don't have any illusions
that one or the other miraculously make the declaration syntax
readable to a beginner.

My preference for "type *obj" rather than "type* obj" is probably
largely based on the fact that that's what I've always been exposed
to. If I had been exposed to "type* obj", I'd likely be making the
same arguments you are. But my preference is also based in part on
having the spacing reflect the way it's actually defined by the syntax
and parsed by the compiler. De gustibus yadda yadda.
 
J

James Kanze

[...]
or from an actual program I wrote (about 20 years ago):
struct T
{
// ...
struct V* (*f[ 8 ])( struct V* ) ;
} ;
struct T a[] = {...} ;
, use:
s = (*p->f[j])( s ) ;
Any relationship between use and definition seems very tenuous,
at best.

Perhaps, but I think the underlying principle is still there.

The underlying principle remains at the base of the original
concept. The problem is that as the type system has become more
complex, the underlying principle simply doesn't work any more.
It was an interesting experiment, one definitly worth doing, if
only to see what the repercussions were, but it turns out that
what the experiment proved was that it wasn't a good idea.
I'm too
lazy to wade through that declaration -- and I'm not *really* trying
to defend C's declaration syntax.

My only point is that the use doesn't look anything like the
declaration. As long as you stick to the basic types, pointers
and arrays (which is all there was in the earliest versions of
C), it does, and the declaration syntax actually works fairly
well. As soon as you start throwing in typedef's, struct's and
what have you, it stops working. And the declaration doesn't
follow use.
Which breaks down for
int a[10];

And for a lot of other cases. I know.
which, if C *didn't* use declaration-follows-use, would probably be:
int[10] a; /* not C 8/

Java went that way. It turns out (based on my experience with
Java), that it doesn't really work much better.

If C hadn't started with declaration-follows-use, the syntax
might have been something like:

array [10] int : a ;

or even:

var a: array[10] of int ;

[...]
My preference for "type *obj" rather than "type* obj" is probably
largely based on the fact that that's what I've always been exposed
to. If I had been exposed to "type* obj", I'd likely be making the
same arguments you are.

Probably. I know that I was exposed to the "type* obj" format
very early in my days of C---I forget from where---and have used
it ever since, even before learning C++. (I remember at the
time that there was some discussion about the issue, and that
one collegue adopted the solution "type * obj"; no need to take
sides.) But typically, C programmers use "type *obj", and C++
programmers "type* obj", because Kernighan and Richie use "type
*obj" and Stroustrup uses "type* obj".

Logically, I think that there is a valid argument for separating
the type from the name of what is being declared. But it is
very much weakened, in the case of C/C++, by the fact that you
can't do it systematically; you can't do it for arrays, for
example (and what makes a function declaration a function, and
not a scalar, is the (), which also follows). So it's really
six of one, and half dozen of another. I've gotten very much
into the habit of "type* obj", but it's something where I'll
conform to whatever the local conventions are; the difference
isn't important enough to warrent trying to change them.
 
J

James Kanze

How do you manage that for arrays?

std::vector< int > v ; // :)

Seriously, I do it when I can, but when the language doesn't
allow it, obviously, I do have to write code which the compiler
can understand. As a general rule, I like to keep the type
separate from the name of what is being defined. As a general
rule, I like to make declarations distinctive from expression
statements. Neither are always possible.
[...]
And the Unix way is exit(2).
<OT>
On Unix-like systems, EXIT_FAILURE is typically defined as 1. exit(0)
denotes success, and exit(1) commonly indicates some generic failure.
I know of no widespread convention for exit codes other than 0 and 1;
they tend to be defined individually for each command. One command,
curl, documents 76 distinct error codes.
</OT>

Try "man grep":).
The C standard's exit(0), exit(EXIT_SUCCESS), and exit(EXIT_FAILURE)
are quite compatible with Unix conventions.

With one of the Unix conventions:). Back when I was regularly
implementing such things, I got in the habit of using 2 for real
errors, because a certain number of programs (e.g. grep) used 1
for special non-error conditions. So I've gradually developped
the habit of using 2 for most errors.

The only more or less enforced convention is, of course, 0 if
there is no error. A number of programs do use 1 for special
non-error or half-error conditions (grep not finding anything),
and 2 for real errors. And of course, anything greater than 127
should be avoided, as it normally indicates that the program was
killed from the outside. I've gotten into the habit of
distinguishing even more: 1 is a "half-error", 2 a real error, 3
a fatal error (the program stopped immediately on detecting it);
internally, I also use 4, but that will trigger a call to abort,
so the invoking code won't see it. In my production code, these
are mapped to the system defined error return codes, with all
but 0 mapping to EXIT_FAILURE by default, but with the Unix and
Windows mappings just passing them through. It allows
propagating extra information on systems which support it.

Still, 99% of my programming is under Unix, so I sometimes slip,
and just write the error codes directly. Even though I know
that they don't work everywhere.
 
J

James Kanze

On Apr 23, 5:04 pm, "Default User" <[email protected]> wrote:

[...]
It seems to me that there's this difference: although the OP
crossposted, every reply up to that point had included only C code.
When there was a post full of C++, it jumped out immediately reading
it in clc. So I'd assume that if I'd been reading it in clc++ then all
the posts full of C would similarly have jumped out at me, and I'd
either have killed the thread (if my newsreader had that function) or
been alerted to the fact that it had probably been crossposted.

All of the postings up to that point had also been legal C++.
Most well written C is. Not idiomatic, of course, but legal, so
it jumps out less.
 
P

Peter 'Shaggy' Haywood

/* I wrote the following program to calculate no. of 'a' in the file
c:/1.txt but it fails to give appropriate result. What is wrong with
it? */

Several things.
#include"stdio.h"

That's wrong. It should be:

#include <stdio.h>

I usually include the following too, so I can use the macro EXIT_FAILURE
where needed:

#include said:
int main(void)
{
FILE *f;

Very poor style, lack of indentation.

I smell a problem here. No doubt you will need an int instead of a char.
long int a=0;
f=fopen("c:/1.txt","r");

Always test the return value of fopen, ALWAYS! Since you have not done
so, you have no way of knowing whether the file could be successfully
opened or not and whether you have a valid FILE pointer or not.

if(!f)
{
fprintf(stderr, "Error opening file: \"%s\"\n", "c:/1.txt");
return EXIT_FAILURE;
}
while(ch=getc(f)!=EOF)

Here you have a couple of problems. One of them is the one I sniffed out
above. Since ch is a char, it may not be able to represent EOF (a negative
integer) or may produce a false EOF equality. As I said, ch should be an
int.
The second problem is that != has higher precedence than =, so the
expression is evaluated as ch = (getc(f) != EOF). Thus ch gets set to 0 if
getc(f) returns EOF and 1 otherwise. You need to parenthesise the ch =
getc(f) subexpression.

while((ch = getc(f)) != EOF)
{
switch(ch)
{
case 'a': a++;break;
}
}

Inconsistant indentation.
printf("No. of 'a' = %d\n",a);

And here we have another serious problem. a is a long, but you are
telling printf() to expect an int. You need to look up the printf()
function in your C manual. The conversion specifier for a long is %ld.

printf("No. of 'a' = %ld\n",a);
 
M

Michal Nazarewicz

#include <stdio.h>


I smell a problem here. No doubt you will need an int instead of a char.

You can also assume that there will be non-negative number of letters
'a' in the file, so instead of 'long int' one can use:

unsigned long a = 0;
if(!f)
{
fprintf(stderr, "Error opening file: \"%s\"\n", "c:/1.txt");
return EXIT_FAILURE;
}

while((ch = getc(f)) != EOF)

printf("No. of 'a' = %ld\n",a);

And here call would change to:

printf("No. of 'a' = %lu\n",a);
 
A

Army1987

Bill Pursell said:
In the following, "that ungood thing" refers to multiple
declarations in a single line:
And when you're not doing that ungood thing, writing FILE* f makes
sense.

There I disagree. If you're going to have declarations of any
significant complexity, you need to understand why C declaration are
the way they are (declaration follows use). With that understanding,
"FILE *f" just makes more sense.

FILE *f; /* *f is a FILE */
int a[10] /* a[10] is an int (or would be if it existed */

When I look to the declaration section of a block to see
what type f is, I'm interested in seeing what type f is. I don't
want to see what *f is. In other words, I'd rather derive
information about *f from information about f rather
than the other way around.
But in simple cases like "FILE *f" / "FILE* f", it isn't all that big
a deal. Declaring it as "FILE* f" implies that f is a FILE* -- which
happens to be true in this case, but the principle doens't extend to
other forms of declarations. As long as you can keep it straight,
I'll still *prefer* to keep the "*" next to the identifier, but I can
cope with other styles.

In working code, what percentage of declarations are not the
"simple case"? Declarations of function pointers obviously
require special treatment, as do
complex array types, but "T * x" is probably valid 95% of the time.
And the non-simple cases could perhaps be made clearer: eg

typedef int (*int_int_fcn)(int);

int_int_fcn * h;
int (**f)(int);


....hmmm, perhaps this is a bad example...or perhaps you are,
as usual, correct. The declaration of h was supposed to be
clearer than the declaration of f, but I would argue that this is
not the case.

Agreed, but C declarations work assuming the other way round.
According to Wikipedia, "Ritchie's idea was to declare identifiers in
contexts resembling their use".

If I had written C, maybe I would have done something such as
&FILE f;
#define NULL (&void)0;
or similar. (Just an idea, I've not thought about how I would have made more
complex declarations.
 
M

Marcus Kwok

In comp.lang.c++ James Kanze said:
Probably. I know that I was exposed to the "type* obj" format
very early in my days of C---I forget from where---and have used
it ever since, even before learning C++. (I remember at the
time that there was some discussion about the issue, and that
one collegue adopted the solution "type * obj"; no need to take
sides.) But typically, C programmers use "type *obj", and C++
programmers "type* obj", because Kernighan and Richie use "type
*obj" and Stroustrup uses "type* obj".

This whole subthread can be summarized by this entry in Stroustrup's
FAQ:

Is "int* p;" right or is "int *p;" right?
http://www.research.att.com/~bs/bs_faq2.html#whitespace
 
K

Keith Thompson

Richard Heathfield said:
Marcus Kwok said:



I note in passing that Stroustrup recommends in his discourse that we
should "always initialize variables". Perhaps he isn't such a bad chap
after all. :)

I also note that he refers to C in the past tense.

I'd probably ignite a whole new flame war if I tried to make some
point about "a*b + c" vs. "a * b+c", so I won't. :cool:}
 
R

Richard Heathfield

[followups set to clc]

Keith Thompson said:
I also note that he refers to C in the past tense.

Well, that's just holy-warring - what else would you expect? But his
comment on initialisation is presumably his considered technical
opinion as an accomplished programmer. I'm not saying he's /right/ -
any more than he's right about C. I'm just saying that, far more than
any of us here, he has earned the right for his opinions to be given
serious consideration.
I'd probably ignite a whole new flame war if I tried to make some
point about "a*b + c" vs. "a * b+c", so I won't. :cool:}

If you want significant whitespace, you may find that this meets your
needs: <http://compsoc.dur.ac.uk/whitespace/> :)
 

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,780
Messages
2,569,611
Members
45,269
Latest member
vinaykumar_nevatia23

Latest Threads

Top