Reading a data file

B

blmblm

I merged your code into mine. It appears I muffed something in line 31.

gcc NL_pxm-array.c
_pxm-array.c: In function 'main':
_pxm-array.c:31:5: error: 'for' loop initial declarations are only
allowed in C99 mode
_pxm-array.c:31:5: note: use option -std=c99 or -std=gnu99 to compile
your code

So - follow the instructions. Add the option -std=c99 to your compiler
command line.
_pxm-array.c:32:13: warning: assignment makes pointer from integer
without a cast [enabled by default]

This implies that the compiler thinks that the call to strtok() returns
an integer, which is not the case. Why would it think that? Because
strtok() is declared in <string.h>, and your code doesn't include that
header. In C90, if you used an undeclared identifier as if it were the
name of a function, it get implicitly declared as a function returning
'int'. C99 has more reasonable behavior: it's a constraint violation to
attempt calling an undeclared function.

Ah, that explains ....

I was going to strongly recommend that the OP make a habit of
compiling with flags to enable optional warnings ("-Wall -pedantic"
is what I usually use, that being a reasonable compromise for
me between "all possible warnings" and "too much to type" [*]),
in which case gcc would have produced the warning message

qq.c:32: warning: implicit declaration of function 'strtok'

which is at least a clue about the real problem.

In the course of confirming that my advice wasn't going to be total
nonsense, I observed that just "-std=c99" produces the warning about
implicit declaration. Which now makes sense!

Be that as it may, I still vote for compiling with at least a minimal
set of "show me more warnings" flags -- not infrequently (as in this
case) the extra warnings are clues about behavior that otherwise could
be puzzling.

[*] Yes, yes, makefiles, scripts, aliases .... Sometimes it's simpler
to just go with what one is willing to type. IMO.
 
G

glen herrmannsfeldt

(snip)
The first widely used version of C was the one described by Kernighan
and Ritchie in "The C Programming Language", and that version is called
K&R C. It was not, however, a single version, but a different versions
for each compiler. The first standard for the C programming language was
an ANSI (US) standard that was approved in 1989; the language defined by
that standard is often called C89. Essentially the same document was
approved as an ISO (international) standard in 1990 -
(snip)
A major revision of the standard occurred in 1999, which was fully
implemented only by a small number of compilers, but parts of C99 are
widely supported. Another update occurred in 2011, but it has not had
time to be widely adopted yet. The languages described by those versions
of the standard are usually called C99 and C11, respectively. I
personally prefer to call it C2011, to avoid Y2K issues, but I seem to
be the only one.

Seems to me that some went too far with Y2K. There are many cases where
the year modulo 100 is close enough. (There was a story about someone
at 104 years old being sent a kindergarten application, but that should
be rare.)

With the first standard in 1990, C has a ways to go before the
year modulo 100 isn't good enough.

Fortran started out (first IBM document published) in 1956, and the
first standard in 1966. It will be interesting to see if it survives
for 100 years.

-- glen
 
M

Malcolm McLean

In C90, declarations are allowed only at file scope, or at the start of
a block. When Bjarne Stroustrup designed C++, he thought it would be a
good idea to allow declarations in a wider variety of places. One of
those places is in the first part of a for() statement. The C committee
agreed that this was a good idea, and put it into C99. I agree with
them, but you'll find other people who don't. Some are even stricter
than the C90 standard - they won't declare variables in inner blocks of
a function, only in the outermost block.
You not infrequently need the counter outside of the loop.

for(i=0;i<N;i++)
if(!array.field)
break;

if(i < N)
processnullvalue(&array);
else
nullvaluenotfound();
 
J

James Kuyper

In C90, declarations are allowed only at file scope, or at the start of
a block. When Bjarne Stroustrup designed C++, he thought it would be a
good idea to allow declarations in a wider variety of places. One of
those places is in the first part of a for() statement. The C committee
agreed that this was a good idea, and put it into C99. I agree with
them, but you'll find other people who don't. Some are even stricter
than the C90 standard - they won't declare variables in inner blocks of
a function, only in the outermost block.
You not infrequently need the counter outside of the loop.

for(i=0;i<N;i++)
if(!array.field)
break;

if(i < N)
processnullvalue(&array);
else
nullvaluenotfound();


I've written code like that many times, but I have to disagree with your
description of it as "not infrequent". For every loop like that which
I've written, I've written dozens of other loops where the loop variable
was used exclusively in the loop, where it would have been a logic error
to make any reference to that variable outside the loop. I like having
the compiler remind me when I've written illogical code - I can't count
on catching all such errors myself.

And please don't bring up the hoary old argument about some idiots
assuming that, because the compiler can catch some errors, it must be
capable of catching all errors, and therefore not bothering to do their
own search for errors. Such idiots are quite capable of coming up with
other reasons for not bothering to search. Giving the compiler less
information so it won't be able to detect such problems will merely
leave such problems undetected in their code - it won't force such
idiots to actually search for their errors.

Having the option of declaring a loop variable in the for() statement
doesn't disable the ability to declare it outside the statement, and
therefore doesn't count as a valid argument against allowing such
declarations.
 
G

glen herrmannsfeldt

(snip, someone wrote)
You not infrequently need the counter outside of the loop.
for(i=0;i<N;i++)
if(!array.field)
break;
if(i < N)
processnullvalue(&array);
else
nullvaluenotfound();

I've written code like that many times, but I have to disagree
with your description of it as "not infrequent".

How much is "frequent" and how much "not infrequent"?
For every loop like that which I've written, I've written dozens
of other loops where the loop variable was used exclusively in
the loop, where it would have been a logic error to make any
reference to that variable outside the loop. I like having
the compiler remind me when I've written illogical code - I
can't count on catching all such errors myself.
(snip)

Having the option of declaring a loop variable in the for() statement
doesn't disable the ability to declare it outside the statement, and
therefore doesn't count as a valid argument against allowing such
declarations.

Maybe not in C, but I believe it isn't allowed in Java, and likely
for the reason you mention above. It is too easy to have undetected
logic errors when you allow both. You can, of course, use a
different variable. If you want the compiler to help detect them,
then you can't allow both.

-- glen
 
J

James Kuyper

(snip, someone wrote)
You not infrequently need the counter outside of the loop.
for(i=0;i<N;i++)
if(!array.field)
break;
if(i < N)
processnullvalue(&array);
else
nullvaluenotfound();

I've written code like that many times, but I have to disagree
with your description of it as "not infrequent".

How much is "frequent" and how much "not infrequent"?


I've no hard statistics, but as implied below, I think that less than
10% of my own loops look like that; possibly less than 5%. Of course,
what counts as "frequent", "infrequent", or "not infrequent" depends
upon the context. In this context, "not frequent" would have to be
common enough to justify not allowing declaration of the variable in the
first part of a for() statement. In my opinion, 10% is way too low to
justify disallowing that; 95% might be high enough.
My opinion would be quite different if allowing the loop variable to be
declared there would have the consequence of disallowing it from being
declared elsewhere - but that's not the case here.
Maybe not in C, but I believe it isn't allowed in Java, and likely
for the reason you mention above. It is too easy to have undetected
logic errors when you allow both. You can, of course, use a
different variable. If you want the compiler to help detect them,
then you can't allow both.

I'm not very familiar with Java, but
<http://en.wikipedia.org/wiki/Java_syntax#for_loop> doesn't say anything
to suggest a difference from C in that respect. What's missing from that
description?
 
E

Eric Sosman

James Kuyper said:
[...]
Having the option of declaring a loop variable in the for() statement
doesn't disable the ability to declare it outside the statement, and
therefore doesn't count as a valid argument against allowing such
declarations.

Maybe not in C, but I believe it isn't allowed in Java, [...]

<off-topic> Your beliefs about Java are at odds with
the facts. </off-topic>
 
B

blmblm

James Kuyper said:
[...]
Having the option of declaring a loop variable in the for() statement
doesn't disable the ability to declare it outside the statement, and
therefore doesn't count as a valid argument against allowing such
declarations.

Maybe not in C, but I believe it isn't allowed in Java, [...]

<off-topic> Your beliefs about Java are at odds with
the facts. </off-topic>

Quite. (I was all set to reply to the preceding post, but you sort
of beat me to it. But maybe saying a bit more, especially since
you've helpfully marked it "OT" .... ) Example:

public class QQ {
public static void main(String[] args) {
int i;
for (i = 0; i < 10; ++i) System.out.println(i);
System.out.println("ending i "+i);
}
}

I was a little surprised that this compiled, since normally Java
won't let you declare a local variable without assigning it a value.
(That may be what Glen was thinking of?) But apparently the actual
rule is that the compiler has to be able to figure out that every
variable gets assigned a value before used, and in this case I
guess it can figure that out.
 
G

glen herrmannsfeldt

(snip, I wrote)
I'm not very familiar with Java, but
<http://en.wikipedia.org/wiki/Java_syntax#for_loop> doesn't say anything
to suggest a difference from C in that respect. What's missing from that
description?

public class forloop {
public static void main(String[] args) {
int i;
for(int i=0;i<10;i++) System.exit(i);
}
}

forloop.java:4: i is already defined in main(java.lang.String[])
for(int i=0;i<10;i++) System.exit(i);
^
1 error

I don't know where it is in the language reference, but the
compiler doesn't like it...

-- glen
 
G

glen herrmannsfeldt

Eric Sosman <[email protected]> wrote:

(snip, I wrote)
Maybe not in C, but I believe it isn't allowed in Java, [...]
<off-topic> Your beliefs about Java are at odds with
the facts. </off-topic>
Quite. (I was all set to reply to the preceding post, but you sort
of beat me to it. But maybe saying a bit more, especially since
you've helpfully marked it "OT" .... ) Example:

While you have to be careful, I usually consider comparisons of
features with other languages a reasonable point of discussion.
public class QQ {
public static void main(String[] args) {
int i;
for (i = 0; i < 10; ++i) System.out.println(i);
System.out.println("ending i "+i);
}
}
I was a little surprised that this compiled, since normally Java
won't let you declare a local variable without assigning it a value.
(That may be what Glen was thinking of?)
No.

But apparently the actual rule is that the compiler has to be
able to figure out that every variable gets assigned a value
before used, and in this case I guess it can figure that out.

Now, put int in the for statement, leaving int i outside, and
it will fail to compile.

-- glen
 
E

Eric Sosman

(snip, I wrote)
I'm not very familiar with Java, but
<http://en.wikipedia.org/wiki/Java_syntax#for_loop> doesn't say anything
to suggest a difference from C in that respect. What's missing from that
description?

public class forloop {
public static void main(String[] args) {
int i;
for(int i=0;i<10;i++) System.exit(i);
}
}

forloop.java:4: i is already defined in main(java.lang.String[])
for(int i=0;i<10;i++) System.exit(i);
^
1 error

I don't know where it is in the language reference, but the
compiler doesn't like it...

<off-topic> It will if you s/(int/(/. </off-topic>
 
J

James Kuyper

On 07/22/2013 05:27 PM, glen herrmannsfeldt wrote:
....
public class forloop {
public static void main(String[] args) {
int i;
for(int i=0;i<10;i++) System.exit(i);
}
}

forloop.java:4: i is already defined in main(java.lang.String[])
for(int i=0;i<10;i++) System.exit(i);
^
1 error

I don't know where it is in the language reference, but the
compiler doesn't like it...


That's not what I was referring to. I was saying that allowing

// Example 1
for(int i=0; i<N; i++) { /* Loop body */}

does not mean that you have to prohibit

// Example 2
int i;
for(i=0; i<N; i++) { /* Loop body with early exit */}
if(i < N)
{
// Deal with early exit.
}

Therefore, the need to occasionally write code like Example 2 does not
count as an argument against allowing Example 1.
 
B

blmblm

Eric Sosman <[email protected]> wrote:

(snip, I wrote)
Maybe not in C, but I believe it isn't allowed in Java, [...]
<off-topic> Your beliefs about Java are at odds with
the facts. </off-topic>
Quite. (I was all set to reply to the preceding post, but you sort
of beat me to it. But maybe saying a bit more, especially since
you've helpfully marked it "OT" .... ) Example:

While you have to be careful, I usually consider comparisons of
features with other languages a reasonable point of discussion.
public class QQ {
public static void main(String[] args) {
int i;
for (i = 0; i < 10; ++i) System.out.println(i);
System.out.println("ending i "+i);
}
}
I was a little surprised that this compiled, since normally Java
won't let you declare a local variable without assigning it a value.
(That may be what Glen was thinking of?)
No.

But apparently the actual rule is that the compiler has to be
able to figure out that every variable gets assigned a value
before used, and in this case I guess it can figure that out.

Now, put int in the for statement, leaving int i outside, and
it will fail to compile.

True, while the equivalent(?) C (below) does. However, apparently
gcc at least creates two distinct variables i, one valid inside
the scope of the loop and one valid outside. Now *that* strikes
me as asking for trouble. That the Java compiler just won't let
you have the two declarations seems not-bad to me. ?

#include <stdio.h>
int main(void) {
int i=0;
for (int i = 0; i < 10; ++i) { printf("%d\n",i); }
printf("%d\n",i);
return 0;
}
 
G

glen herrmannsfeldt

(snip, I wrote)
public class forloop {
public static void main(String[] args) {
int i;
for(int i=0;i<10;i++) System.exit(i);
}
}
forloop.java:4: i is already defined in main(java.lang.String[])
for(int i=0;i<10;i++) System.exit(i);
(snip)

That's not what I was referring to. I was saying that allowing
// Example 1
for(int i=0; i<N; i++) { /* Loop body */}
does not mean that you have to prohibit

OK, I missed what you meant.
// Example 2
int i;
for(i=0; i<N; i++) { /* Loop body with early exit */}
if(i < N)
{
// Deal with early exit.
}
Therefore, the need to occasionally write code like Example 2
does not count as an argument against allowing Example 1.

There might be some langauges that allow a new scope nesting level,
which doesn't help avoid the problem.

-- glen
 
K

Keith Thompson

True, while the equivalent(?) C (below) does. However, apparently
gcc at least creates two distinct variables i, one valid inside
the scope of the loop and one valid outside. Now *that* strikes
me as asking for trouble. That the Java compiler just won't let
you have the two declarations seems not-bad to me. ?

#include <stdio.h>
int main(void) {
int i=0;
for (int i = 0; i < 10; ++i) { printf("%d\n",i); }
printf("%d\n",i);
return 0;
}

The two "i" variables are declared in different scopes. It's
fundamentally no different than this:

#include <stdio.h>
int main(void) {
int i = 0;
printf("i = %d\n", i);
{
int i = 1;
printf("i = %d\n", i);
}
printf("i = %d\n", i);
}

which prints:

i = 0
i = 1
i = 0

In general, an identifier declared in an inner scope hides the same
identifier declared in an outer scope.

I suppose you could have a rule forbidding that, but it would break
existing code.
 
T

Tim Rentsch

glen herrmannsfeldt said:
It is too easy to have undetected logic errors when you allow
[a particular variable name to used for local variables both in
an outer block and in an inner block (eg, a for loop) within
the scope of the outer block's variable]. If you want the
compiler to help detect them, then you can't allow [such
variable shadowing].

The last statement is obviously false.
 
M

Malcolm McLean

I've no hard statistics, but as implied below, I think that less than
10% of my own loops look like that; possibly less than 5%. Of course,
what counts as "frequent", "infrequent", or "not infrequent" depends
upon the context. In this context, "not frequent" would have to be
common enough to justify not allowing declaration of the variable in the
first part of a for() statement. In my opinion, 10% is way too low to
justify disallowing that; 95% might be high enough.
"Not infrequent" means "often enough to be worth considering providing
nice syntax / structures for", as opposed to simply making possible.

If we allow for(int i=0;i<N;i++) it's only a good move if virtually
every for loop follows this style. So now you could have an advantage,
for(i=0;i<N;i++) tells us that i will be used outside of the loop body.
However you'd need the compiler to enforce that by warning if it
wasn't the case, which would break too much legacy code.

But consider this:

/* count the number of space characters before the quote */
int count_pre_quote_spaces(char *str)
{
int i;
int N;
int answer = 0;

for(i=0;str;i++)
if(str == '\'')
break;
if(!str)
return -1;
N = i;
for(int i=0; i<N;i++)
if(str == ' ')
answer++;
return answer;
}

what do you reckon?
 
J

Jorgen Grahn

Jorgen Grahn said:
The file can be opened with the fopen() function:

FILE *input = fopen( "mydata.dat", "r" );

I'd prefer to read from stdin, and/or from a file whose name was
provided in argv. [snip]

I might agree with those sentiments, but my comments were
concerned only with answering OP's question. He wasn't
asking for a lesson in programming style, and I didn't feel
a need to give one -- just to answer his question in the
most direct and straightforward way I could. Anything more
would serve to dilute the answer, and thereby lessen its
value.

Sure. You (and the OP, I hope) can see my posting as an addendum
to your solution; something to consider when the fixed-filename
version is already working.

/Jorgen
 
J

James Kuyper

"Not infrequent" means "often enough to be worth considering providing
nice syntax / structures for", as opposed to simply making possible.

But there is already perfectly good syntax for that, and allowing
declarations in the first part of a for() statement does nothing to
interfere with that.
If we allow for(int i=0;i<N;i++) it's only a good move if virtually
every for loop follows this style. ...

That makes no sense to me. Do you normally argue that, just because
something is allowed, it should be done whenever possible? If so, I'd
like to point out that you're allowed to send me $1000.

It should be used when it expresses what your code needs to do, and it
should not be used when it doesn't. It's no different in that regard
than ++i: if ++i means what you want to say, use ++i; if what you
actually want to say is i+1, don't use ++i.

The general rule I follow is to declare every identifier with the
smallest scope that allows it to do what that identifier needs to do,
(without using an extra set of curly brackets for the sole purpose of
giving it a tighter scope). That minimizes the opportunities for
different variables to conflict with each other.

Taking advantage of the fact that we are allowed to declare a variable
in the first part of a for() statement is something that should be done
only when declaring it in that position gives it that the right scope.
... So now you could have an advantage,
for(i=0;i<N;i++) tells us that i will be used outside of the loop body.
However you'd need the compiler to enforce that by warning if it
wasn't the case, which would break too much legacy code.

Such a warning should be optional, and turned off by default, and I
wouldn't bother turning it on. But the standard allows compilers to warn
about anything they want to, such as the fact that you failed to use
obscene words as variable names - only mandatory diagnostics are worth
talking about in the context of portable code.
But consider this:

/* count the number of space characters before the quote */
int count_pre_quote_spaces(char *str)
{
int i;
int N;
int answer = 0;

for(i=0;str;i++)
if(str == '\'')
break;
if(!str)
return -1;
N = i;
for(int i=0; i<N;i++)
if(str == ' ')
answer++;
return answer;
}

what do you reckon?


I reckon that the C language allows an inner scope declaration to hide
an outer scope declaration, which is useful, because it makes it easier
to move code from one context to another without accidentally breaking
it - but that it is rarely, if ever, a good idea to deliberately write
code that depends upon that fact.
 
L

Lowell Gilbert

James Kuyper said:
That makes no sense to me. Do you normally argue that, just because
something is allowed, it should be done whenever possible? If so, I'd
like to point out that you're allowed to send me $1000.

Not to put words in his mouth, but I think there's a reasonable point to
be made that if you could be sure that (a) *not* declaring the loop variable
in the for statement reliably implied that said variable *would* be used
outside of the loop, that would be a more valuable piece of information
to a reader of the code than that (b) declaring it in the loop means
it's only used in the loop. In my opinion, (b) has value, so the two
ideas are not in conflict.

Yes, (a) can't be added to the language, but if a compiler provided a(n
optional) warning to detect it, I can imagine it being a thing some
reasonable people would want to turn on.
It should be used when it expresses what your code needs to do, and it
should not be used when it doesn't. It's no different in that regard
than ++i: if ++i means what you want to say, use ++i; if what you
actually want to say is i+1, don't use ++i.

The general rule I follow is to declare every identifier with the
smallest scope that allows it to do what that identifier needs to do,
(without using an extra set of curly brackets for the sole purpose of
giving it a tighter scope). That minimizes the opportunities for
different variables to conflict with each other.

Taking advantage of the fact that we are allowed to declare a variable
in the first part of a for() statement is something that should be done
only when declaring it in that position gives it that the right scope.

This sounds to be fully in agreement with what Malcolm McLean actually
said; the only difference is that he'd like to enforce it more strongly
in this particular case.
Such a warning should be optional, and turned off by default, and I
wouldn't bother turning it on. But the standard allows compilers to warn
about anything they want to, such as the fact that you failed to use
obscene words as variable names - only mandatory diagnostics are worth
talking about in the context of portable code.

The code is portable (and standards-compliant) anyway, and nobody's
suggesting adding the must-declare-inside-the-"for"-if-possible to the
language. As far as I can see, the only issue left is whether including
it as an optional feature would benefit a compiler's quality of
implementation. Is there really anything else at question here?
 

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,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top