Redirecting input from file

B

Ben Bacarisse

Here is my code as of now, as well as an input file and my output. I
am aware that I've got more error proofing to do, but this is what I
have right now.

You have not taken some of the advice already given but, what the
hell, lets have another go...
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
/* Variable Declarations */

No need for comments like this. If the reader needs it, they will get
lost very soon. If they don't who is it for?
const int arraylength = 5000;
const int exiterrorcode = -1;

C already has name for this: EXIT_FAILURE. It is standard and already
defined (I know here you got your version from and it is not the worst
thing in the course notes, but it is still much worse than using
EXIT_FAILURE).
int count = 0;
int condition = 1;
float* precipvals = (float*)NULL;
float* precip3hrs = (float*)NULL;
long* date = (long*)NULL;

None of the casts in the program are required (the same is true, I
think, for all the casts in your course notes as well) and they just
serve to confuse the reader.
FILE *fpin;
FILE *fpout;

fpin = fopen(argv[1],"r");
fpout = fopen(argv[2],"w");

if(fpin == NULL || fpout == NULL) {
printf("Insufficient arguments\n");
exit(exiterrorcode);
}

It is too late by this time. You could write this:

fpin = argc > 1 ? fopen(argv[1], "r") : NULL);
fpout = argc > 2 ? fopen(argv[2], "w") : NULL);

and then your test will work but, really, you should report unopenable
files as distinct from not enough arguments.
/* Array Allocation */
precipvals = (float*)malloc(sizeof(float) * arraylength);
precip3hrs = (float*)malloc(sizeof(float) * arraylength);
date = (long*)malloc(sizeof(long) *
arraylength);

the form: 'date = malloc(arraylength * sizeof *date);' has so much
going for it, I can't see why it not morewidely used!

....and you know you need to test the results.
/* Calculation Section */
while(condition != EOF) {
condition = fscanf(fpin,"%ld,%f", &date[count],
&precipvals[count]);

condition will never get to EOF if there is an error in the input
format. fscanf can return 1 or 0 and will continue to do so for ever
if the input is malformed. It is much better to test for everything
be hunky-dory:

while (count < array_length &&
fscanf(fpin, "%ld,%f", &date[count], &precipvals[count]) == 2) {

Note I have also checked count (first). You must not read data into
storage that does not exist.
if(count == 0) {
precip3hrs[count] = precipvals[count];
}
if(count == 1) {
precip3hrs[count] = precipvals[count] + precip3hrs[count-1];
}
if(count > 1) {
precip3hrs[count] = precipvals[count] + precipvals[count-1] +
precipvals[count-2];
}
count++;
}

Personally, I would read the data, and then do the partial sums.
/* Output section */
for(count = 0; count < arraylength; count++) {
if(!(precipvals[count] == 0 && precip3hrs[count] == 0)) {
if(count == 0) {
printf("One hour precipitation: %2.2f Three hour precipitation
%2.2f\n",precipvals[count],precip3hrs[count]);
}
if(count == 1) {
printf("One hour precipitation: %2.2f Three hour precipitation
%2.2f\n",precipvals[count],precip3hrs[count]);
}
if(count > 1) {
printf("One hour precipitation: %2.2f Three hour precipitation
%2.2f\n",precipvals[count],precip3hrs[count]);
}
}
}

I can't see the point of all those tests. You do the same thing in
every case. If you *do* want to do thing differently for different
counts, I'd put the special cases outside the loop and run the loop
from count = 2.
/* Write to file */
for(count = 0; count < arraylength; count++) {
if(!(precipvals[count] == 0 && precip3hrs[count] == 0)) {
if(count == 0) {
fprintf(fpout,"One hour precipitation: %2.2f Three hour
precipitation %2.2f\n",precipvals[count],precip3hrs[count]);
}
if(count == 1) {
fprintf(fpout, "One hour precipitation: %2.2f Three hour
precipitation %2.2f\n",precipvals[count],precip3hrs[count]);
}
if(count > 1) {
fprintf(fpout, "One hour precipitation: %2.2f Three hour
precipitation %2.2f\n",precipvals[count],precip3hrs[count]);
}
}
}
Ditto.

fclose(fpin);
fclose(fpout);

/* Deallocation */
free(precipvals);
precipvals = (float*)NULL;
free(precip3hrs);
precip3hrs = (float*)NULL;
date = (long*)NULL;
free(date);

That must be a typo. Surely you want to free(date) then set it to
NULL? Personally, I would just write:

free(precipvals);
free(precip3hrs);
free(date);
 
D

dmoran21

Here is my code as of now, as well as an input file and my output. I
am aware that I've got more error proofing to do, but this is what I
have right now.

You have not taken some of the advice already given but, what the
hell, lets have another go...
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
/* Variable Declarations */

No need for comments like this. If the reader needs it, they will get
lost very soon. If they don't who is it for?
const int arraylength = 5000;
const int exiterrorcode = -1;

C already has name for this: EXIT_FAILURE. It is standard and already
defined (I know here you got your version from and it is not the worst
thing in the course notes, but it is still much worse than using
EXIT_FAILURE).
int count = 0;
int condition = 1;
float* precipvals = (float*)NULL;
float* precip3hrs = (float*)NULL;
long* date = (long*)NULL;

None of the casts in the program are required (the same is true, I
think, for all the casts in your course notes as well) and they just
serve to confuse the reader.
FILE *fpin;
FILE *fpout;
fpin = fopen(argv[1],"r");
fpout = fopen(argv[2],"w");
if(fpin == NULL || fpout == NULL) {
printf("Insufficient arguments\n");
exit(exiterrorcode);
}

It is too late by this time. You could write this:

fpin = argc > 1 ? fopen(argv[1], "r") : NULL);
fpout = argc > 2 ? fopen(argv[2], "w") : NULL);

and then your test will work but, really, you should report unopenable
files as distinct from not enough arguments.
/* Array Allocation */
precipvals = (float*)malloc(sizeof(float) * arraylength);
precip3hrs = (float*)malloc(sizeof(float) * arraylength);
date = (long*)malloc(sizeof(long) *
arraylength);

the form: 'date = malloc(arraylength * sizeof *date);' has so much
going for it, I can't see why it not morewidely used!

...and you know you need to test the results.
/* Calculation Section */
while(condition != EOF) {
condition = fscanf(fpin,"%ld,%f", &date[count],
&precipvals[count]);

condition will never get to EOF if there is an error in the input
format. fscanf can return 1 or 0 and will continue to do so for ever
if the input is malformed. It is much better to test for everything
be hunky-dory:

while (count < array_length &&
fscanf(fpin, "%ld,%f", &date[count], &precipvals[count]) == 2) {

Note I have also checked count (first). You must not read data into
storage that does not exist.
if(count == 0) {
precip3hrs[count] = precipvals[count];
}
if(count == 1) {
precip3hrs[count] = precipvals[count] + precip3hrs[count-1];
}
if(count > 1) {
precip3hrs[count] = precipvals[count] + precipvals[count-1] +
precipvals[count-2];
}
count++;
}

Personally, I would read the data, and then do the partial sums.


/* Output section */
for(count = 0; count < arraylength; count++) {
if(!(precipvals[count] == 0 && precip3hrs[count] == 0)) {
if(count == 0) {
printf("One hour precipitation: %2.2f Three hour precipitation
%2.2f\n",precipvals[count],precip3hrs[count]);
}
if(count == 1) {
printf("One hour precipitation: %2.2f Three hour precipitation
%2.2f\n",precipvals[count],precip3hrs[count]);
}
if(count > 1) {
printf("One hour precipitation: %2.2f Three hour precipitation
%2.2f\n",precipvals[count],precip3hrs[count]);
}
}
}

I can't see the point of all those tests. You do the same thing in
every case. If you *do* want to do thing differently for different
counts, I'd put the special cases outside the loop and run the loop
from count = 2.


/* Write to file */
for(count = 0; count < arraylength; count++) {
if(!(precipvals[count] == 0 && precip3hrs[count] == 0)) {
if(count == 0) {
fprintf(fpout,"One hour precipitation: %2.2f Three hour
precipitation %2.2f\n",precipvals[count],precip3hrs[count]);
}
if(count == 1) {
fprintf(fpout, "One hour precipitation: %2.2f Three hour
precipitation %2.2f\n",precipvals[count],precip3hrs[count]);
}
if(count > 1) {
fprintf(fpout, "One hour precipitation: %2.2f Three hour
precipitation %2.2f\n",precipvals[count],precip3hrs[count]);
}
}
}
Ditto.
fclose(fpin);
fclose(fpout);

/* Deallocation */
free(precipvals);
precipvals = (float*)NULL;
free(precip3hrs);
precip3hrs = (float*)NULL;
date = (long*)NULL;
free(date);

That must be a typo. Surely you want to free(date) then set it to
NULL? Personally, I would just write:

free(precipvals);
free(precip3hrs);
free(date);

Most of these I caught before I read your post. Thanks.

Dave
 
D

dmoran21

For some reason, my boss told me that when she reversed these two
lines, it wouldn't compile. It looked strange to me when I first saw
it, but I just went with it.

Dave
 
B

Ben Pfaff

For some reason, my boss told me that when she reversed these two
lines, it wouldn't compile. It looked strange to me when I first saw
it, but I just went with it.

free(NULL) is a no-op, and that's what these lines as quoted are
doing. You should either reverse the order or drop the call to
free entirely. And I'd recommend asking your boss for
clarification; perhaps you misunderstood or she did not
communicate well.
 
R

Richard Heathfield

(e-mail address removed) said:
For some reason, my boss told me that when she reversed these two
lines, it wouldn't compile. It looked strange to me when I first saw
it, but I just went with it.

It sounds like your boss needs to put the mouse down, and step away from
the keyboard. Programming by trial-and-error is never going to work.

Whilst it's legal to pass a null pointer to free(), it's also utterly
pointless.

If

free(date);
date = NULL;

doesn't compile, then there'll be a good reason for it, and the compiler
will issue a sensible message explaining that reason. I suggest you
read the message, and act on it.

Incidentally, the cast is pointless, so remove it. C ***GUARANTEES***
that you can assign a void * to an object pointer and back without loss
of information, and an automatic conversion is supplied.

If you're not getting that automatic conversion, you're not using a C
compiler.
 
B

Ben Pfaff

Richard Heathfield said:
(e-mail address removed) said:
Incidentally, the cast is pointless, so remove it. C ***GUARANTEES***
that you can assign a void * to an object pointer and back without loss
of information, and an automatic conversion is supplied.

If you're not getting that automatic conversion, you're not using a C
compiler.

The usual reason that posters say this kind of thing in
comp.lang.c is because the conversion of interest is implicitly
allowed in C but not in C++. This case is a little difference:
this particular conversion is allowed in both C and C++. It
makes me wonder what language the OP is using, or alternatively
what C or C++ implementation diagnoses assigning NULL to an
object of type "long *".
 
D

dmoran21

It sounds like your boss needs to put the mouse down, and step away from
the keyboard. Programming by trial-and-error is never going to work.

Mind you, neither of us are programmers. We both took one introductory
class each and that was it. She's a civil engineer and I'm a
meteorologist and a mathematician.
Whilst it's legal to pass a null pointer to free(), it's also utterly
pointless.

If

free(date);
date = NULL;

doesn't compile, then there'll be a good reason for it, and the compiler
will issue a sensible message explaining that reason. I suggest you
read the message, and act on it.

We have asked many other more experienced C programmers and none of
them could figure out why we got the error message that we got nor did
they say that we shouldn't do it this way. This was the first issue
that I brought up when I looked at the code for the first time.

If you're not getting that automatic conversion, you're not using a C
compiler.

I don't think we are; we're using g++, which I am told is the only
thing we have. I tried to use cc, but it doesn't seem to be on the
system.
 
B

Ben Pfaff

We have asked many other more experienced C programmers and none of
them could figure out why we got the error message that we got nor did
they say that we shouldn't do it this way. This was the first issue
that I brought up when I looked at the code for the first time.

What was the actual error message? I don't recall seeing it
mentioned in this thread.
 
R

Richard Heathfield

(e-mail address removed) said:
Mind you, neither of us are programmers. We both took one introductory
class each and that was it. She's a civil engineer and I'm a
meteorologist and a mathematician.


We have asked many other more experienced C programmers and none of
them could figure out why we got the error message that we got nor did
they say that we shouldn't do it this way. This was the first issue
that I brought up when I looked at the code for the first time.

Okay, here's what I suggest:

1) remove ALL casts from your program.
2) add all the error checking you can think of.
3) don't "code around" the compiler; code to the problem.
4) post your best-shot code here, with those casts GONE and those error
checks ADDED (I already did this for you once, and I don't plan to do
it again), together with enough information about the data to allow us
to construct sample data for ourselves (or just provide sample data, if
it's in text format).

You'd be astounded at how much C experience is available in comp.lang.c
- and you're not doing anything terribly difficult. This is taking way
longer than it should to fix, because you're not taking our suggestions
on board, so we keep finding the same old problems over and over. Until
those are dealt with, you're going to struggle to find the other
problems.
I don't think we are; we're using g++, which I am told is the only
thing we have. I tried to use cc, but it doesn't seem to be on the
system.

gcc should be there.
 
D

Default User

We have asked many other more experienced C programmers and none of
them could figure out why we got the error message that we got nor did
they say that we shouldn't do it this way. This was the first issue
that I brought up when I looked at the code for the first time.

Well, for us to help we would need to see the entire program
(preferablly reduced to minimum program that still displays the
problem), along with an exact copy of the compiler messages.
I don't think we are; we're using g++, which I am told is the only
thing we have. I tried to use cc, but it doesn't seem to be on the
system.

What compiler ARE you using. Most C++ toolsets come with a C compiler
as well. It's probably there if you know how to invoke it.

If you really are using C++, you should post in comp.lang.c++.



Brian
 
F

Flash Gordon

(e-mail address removed) wrote, On 05/07/07 21:41:

We have asked many other more experienced C programmers and none of
them could figure out why we got the error message that we got nor did
they say that we shouldn't do it this way. This was the first issue
that I brought up when I looked at the code for the first time.

The most likely reason for this is you did not show them your real code.
I don't think we are; we're using g++, which I am told is the only
thing we have.

g++ is a C++ compiler. Either use a C compiler or ask in a C++ group.
The languages are significantly different.
> I tried to use cc, but it doesn't seem to be on the
system.

Try gcc. If that does not work, ask somewhere your OS is topical how to
get a C compiler installed.
 
W

William Pursell

Here is my code as of now, as well as an input file and my output. I
am aware that I've got more error proofing to do, but this is what I
have right now.

I'm just going to address one point:
fpin = fopen(argv[1],"r");
fpout = fopen(argv[2],"w");

if(fpin == NULL || fpout == NULL) {
printf("Insufficient arguments\n");
exit(exiterrorcode);
}

Others have pointed out that you need to verify that
argv[1] and argv[2] are not NULL before you call fopen,
and that's important but not the point I'm addressing.

If fopen() fails, you shouldn't make up your own error
message. The system provides you with a text string
describing why fopen failed. eg:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int
main( int argc, char **argv)
{
FILE *ifp;
char *name;
int status = EXIT_SUCCESS;

if( argc > 1 )
ifp = fopen( name = argv[ 1 ], "r" );
else
ifp = stdin;

if( ifp == NULL ) {
fprintf( stderr, "Unable to open %s: %s\n",
name, strerror( errno ));
status = EXIT_FAILURE;
}
/* fclose() omitted for simplicity. */
return status;
}

Sample output:
$ ./a.out foo; ./a.out foo2; ./a.out /dev/hda
Unable to open foo: Permission denied
Unable to open foo2: No such file or directory
Unable to open /dev/hda: No medium found


You can also simplify things a little and replace the fprintf()
with the simpler call:
perror( name );

Note that an implementation is not required to set
errno when fopen fails, and on such implementations
the error message will be obfuscated, but this
works well for many implementations. If necessary,
you could code it as:

fprintf( stderr, "Unable to open %s%s%s\n",name,
#ifdef BRAIN_DAMAGED_IMPLEMENTATION
"last system error: "
#else
": "
#endif
, strerror( errno )
);
 
D

Default User

Richard said:
Default User said:





I think they're using g++.


I guess my reading skills are off today. I blame in on taking vacation
(holiday for you) the first part of the week. Today's effectively
Monday for me, although one followed immediatedly by Friday (which
ain't all bad).




Brian
 
J

Joe Wright

Mind you, neither of us are programmers. We both took one introductory
class each and that was it. She's a civil engineer and I'm a
meteorologist and a mathematician.


We have asked many other more experienced C programmers and none of
them could figure out why we got the error message that we got nor did
they say that we shouldn't do it this way. This was the first issue
that I brought up when I looked at the code for the first time.



I don't think we are; we're using g++, which I am told is the only
thing we have. I tried to use cc, but it doesn't seem to be on the
system.
If your project is of more than casual interest to you and your boss,
consider inviting a C programming consultant to spend an hour or two
with you. It won't break the bank.

If you have g++ (a C++ compiler) you might have gcc as well. Try 'gcc
--version' and see what happens. gcc is the C compiler of the GNU family.

Try 'info info' and see what happens. A whole new world might open to you.
 
C

CBFalconer

.... snip ...


I don't think we are; we're using g++, which I am told is the only
thing we have. I tried to use cc, but it doesn't seem to be on the
system.

Try gcc. Use "-ansi -pedantic -W -Wall" with it. If you don't
have it it is available free.

Please don't strip attributions for material you quote.
Attributions are those initial lines of the form "whozit wrote:".
 
D

Default User

William Pursell wrote:

Others have pointed out that you need to verify that
argv[1] and argv[2] are not NULL before you call fopen,
and that's important but not the point I'm addressing.

If fopen() fails, you shouldn't make up your own error
message. The system provides you with a text string
describing why fopen failed.

This is not required by the standard, and in fact some implementations
do not set errno in this case.




Brian
 
D

Default User

David said:
I'd have to look tomorrow when I get to the office.

Please don't strip the attribution lines, the part at the top of the
message that indicates who said what.




Brian
 

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

Latest Threads

Top