starting into H&S

F

Frank

You are just posting code at random.  Why did you change strtol to
strtod when you are expecting an integer value?

Thanks, again, for your meticulous reading of source that I thought
was closer to done than was the case. I think this version hits the
criticisms you made:

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

int main(int argc, char *argv[])
{
int n;
FILE *fin, *fout;
char *path_exp, *exp_suffix = ".exp";
const char *path;
int c, nc;
char d;


if (argc != 3)
{
fprintf(stderr, "usage: \n");
fprintf(stderr, "%s <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}
path=argv[2];
errno = 0;
n = atoi(argv[1]);
if (n < 0 || n > 999 )
{
fprintf(stderr, "%s: give me a natural number"
" less than 1000\n", argv[0]);
return EXIT_FAILURE;
}
// if detab
if (n == 0)
{
fprintf(stderr, "this will detab your file\n");
fprintf(stderr, "If that's what you want, enter zero again\n");
fprintf(stderr, "To abort, enter anything else\n");
d = getchar();
if (d == '0')
fprintf(stderr, "detabbing %s \n", argv[2]);
else
{
fprintf(stderr, "Aborting");
return EXIT_FAILURE;
}
}
// Process path and open file
nc = strlen (path);
c = strlen (exp_suffix);
path_exp = malloc(c + nc + 1);
if (!path_exp)
{
fprintf(stderr, "malloc error: %s\n", __func__);
return EXIT_FAILURE;
}
strcat(strcpy(path_exp, path), exp_suffix);
fin = fopen(path, "r");
if (!fin)
{
fprintf(stderr, "%s %s\n", "fopen failed to open", path );
return EXIT_FAILURE;
}
// main control



// print some values and exit
printf(" argv1 is %d\n" , n);
printf(" argv2 is %s\n" , path);

fout = fopen(path_exp, "w");
if (!fout)
{
fprintf(stderr, "%s \n", "fout failed");
return EXIT_FAILURE;
}
fclose(fin);
fclose(fout);
free(path_exp);
return EXIT_SUCCESS;
}

// gcc hh1.c -Wall -o indent.exe

I think the fclose situation looks common-sensical now. I guess I
don't know the circumstances where fout is going to fail, given that
fin succeeded. On my platform, if this little program returns
EXIT_FAILURE, then files it opened up are going to live for about a
millisecond.
You are just posting code at random. Why did you change strtol to
strtod when you are expecting an integer value?

Anything but. I had strol, and on pg 412 H&S, they give this entire
family. Since there had to be one of them for just plain int, I
deduced that it had to be strtod, following the format specifier for
printing an int.

K&R §B5 has
int atoi(const char * s)
is equivalent to
(int) strtol(s, (char **)NULL, 10)

Only yesterday did I get rid of endp and put NULL in its place, which,
apparently, should have been casted. This is not random. When I try
something new, it has about a 70-30 chance of being right. This aspect
of learning is, from my perspective, stochastic.
 
F

Frank

You are just posting code at random.  Why did you change strtol to
strtod when you are expecting an integer value?

Thanks, again, for your meticulous reading of source that I thought
was closer to done than was the case. I think this version hits the
criticisms you made:

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

int main(int argc, char *argv[])
{
int n;
FILE *fin, *fout;
char *path_exp, *exp_suffix = ".exp";
const char *path;
int c, nc;
char d;


if (argc != 3)
{
fprintf(stderr, "usage: \n");
fprintf(stderr, "%s <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}
path=argv[2];
errno = 0;
n = atoi(argv[1]);
if (n < 0 || n > 999 )
{
fprintf(stderr, "%s: give me a natural number"
" less than 1000\n", argv[0]);
return EXIT_FAILURE;
}
// if detab
if (n == 0)
{
fprintf(stderr, "this will detab your file\n");
fprintf(stderr, "If that's what you want, enter zero again\n");
fprintf(stderr, "To abort, enter anything else\n");
d = getchar();
if (d == '0')
fprintf(stderr, "detabbing %s \n", argv[2]);
else
{
fprintf(stderr, "Aborting");
return EXIT_FAILURE;
}
}
// Process path and open file
nc = strlen (path);
c = strlen (exp_suffix);
path_exp = malloc(c + nc + 1);
if (!path_exp)
{
fprintf(stderr, "malloc error: %s\n", __func__);
return EXIT_FAILURE;
}
strcat(strcpy(path_exp, path), exp_suffix);
fin = fopen(path, "r");
if (!fin)
{
fprintf(stderr, "%s %s\n", "fopen failed to open", path );
return EXIT_FAILURE;
}
// main control



// print some values and exit
printf(" argv1 is %d\n" , n);
printf(" argv2 is %s\n" , path);

fout = fopen(path_exp, "w");
if (!fout)
{
fprintf(stderr, "%s \n", "fout failed");
return EXIT_FAILURE;
}
fclose(fin);
fclose(fout);
free(path_exp);
return EXIT_SUCCESS;
}

// gcc hh1.c -Wall -o indent.exe

I think the fclose situation looks common-sensical now. I guess I
don't know the circumstances where fout is going to fail, given that
fin succeeded. On my platform, if this little program returns
EXIT_FAILURE, then files it opened up are going to live for about a
millisecond.
You are just posting code at random. Why did you change strtol to
strtod when you are expecting an integer value?

Anything but. I had strol, and on pg 412 H&S, they give this entire
family. Since there had to be one of them for just plain int, I
deduced that it had to be strtod, following the format specifier for
printing an int.

K&R §B5 has
int atoi(const char * s)
is equivalent to
(int) strtol(s, (char **)NULL, 10)

Only yesterday did I get rid of endp and put NULL in its place, which,
apparently, should have been casted. This is not random. When I try
something new, it has about a 70-30 chance of being right. This aspect
of learning is, from my perspective, stochastic.
 
F

Frank

So, specifically, would this be a good way to go:
  if (n < 0 || n > 999 || path == 0 || *path == 0)
    {
      fprintf(stderr, "%s: path fai\
      \led\n", argv[0]);
      fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
      return EXIT_FAILURE;
    }

This is wrong if it the output from some form of indent program.  The
string has spaces in it along with an invalid escape sequence: \l.

Ok. I've got a different question though. What I have now is a bare
bones and increasingly robust way to get a filename from the command
line. Now I want to parse it. It comes into my program as argv[2],
whose value is, by this time, guaranteed to be a legal filename for C.

So need to worry about cases like someone naming a file %.&{ So the
space has been malloced and everything's kosher. I am the user of
this program, and my files all have at most one period in them. Is
that the way C does it too?

All my files have a suffix. Typical ones for this app are gg1.c . I
want the suffix to remain the same, but I want to append _1 to what
precedes the period, so this would be gg1_1.c .

so we have

const char *path;
const char *left;
const char *right;
const char *period = '.';
const char *left_suffix = "_1";

The control would process a char at a time. Hmmm.

I guess my question is how to make this control work so as to include
as many legal varieties of filename as I can do, without making it too
tough on myself. ??
 
F

Frank

So, specifically, would this be a good way to go:
  if (n < 0 || n > 999 || path == 0 || *path == 0)
    {
      fprintf(stderr, "%s: path fai\
      \led\n", argv[0]);
      fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
      return EXIT_FAILURE;
    }

This is wrong if it the output from some form of indent program.  The
string has spaces in it along with an invalid escape sequence: \l.

Ok. I've got a different question though. What I have now is a bare
bones and increasingly robust way to get a filename from the command
line. Now I want to parse it. It comes into my program as argv[2],
whose value is, by this time, guaranteed to be a legal filename for C.

So need to worry about cases like someone naming a file %.&{ So the
space has been malloced and everything's kosher. I am the user of
this program, and my files all have at most one period in them. Is
that the way C does it too?

All my files have a suffix. Typical ones for this app are gg1.c . I
want the suffix to remain the same, but I want to append _1 to what
precedes the period, so this would be gg1_1.c .

so we have

const char *path;
const char *left;
const char *right;
const char *period = '.';
const char *left_suffix = "_1";

The control would process a char at a time. Hmmm.

I guess my question is how to make this control work so as to include
as many legal varieties of filename as I can do, without making it too
tough on myself. ??
 
K

Keith Thompson

Frank said:
So, specifically, would this be a good way to go:
  if (n < 0 || n > 999 || path == 0 || *path == 0)
    {
      fprintf(stderr, "%s: path fai\
      \led\n", argv[0]);
      fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
      return EXIT_FAILURE;
    }

This is wrong if it the output from some form of indent program.  The
string has spaces in it along with an invalid escape sequence: \l.

Ok. I've got a different question though. What I have now is a bare
bones and increasingly robust way to get a filename from the command
line. Now I want to parse it. It comes into my program as argv[2],
whose value is, by this time, guaranteed to be a legal filename for C.

So need to worry about cases like someone naming a file %.&{ So the
space has been malloced and everything's kosher. I am the user of
this program, and my files all have at most one period in them. Is
that the way C does it too?
[...]

The C language has no concept of what constitutes a legal file name
(other than that, due to the fact that fopen's argument points to a
string, it can't contain a null character).

There are plenty of systems on which ".%.&{." is a perfectly legal
file name.
All my files have a suffix. Typical ones for this app are gg1.c . I
want the suffix to remain the same, but I want to append _1 to what
precedes the period, so this would be gg1_1.c .

On the other hand, there's no portable way to construct a legal file
name given an existing legal file name.

If your program is creating output based on a specified file, it may
be best just write the output to stdout and let the user redirect it.
 
B

Barry Schwarz

You are just posting code at random.  Why did you change strtol to
strtod when you are expecting an integer value?

Thanks, again, for your meticulous reading of source that I thought
was closer to done than was the case. I think this version hits the
criticisms you made:

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

int main(int argc, char *argv[])
{
int n;
FILE *fin, *fout;
char *path_exp, *exp_suffix = ".exp";
const char *path;
int c, nc;
char d;


if (argc != 3)
{
fprintf(stderr, "usage: \n");
fprintf(stderr, "%s <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}
path=argv[2];
errno = 0;
n = atoi(argv[1]);

Why are you regressing back to less effective code that was commented
on weeks ago.
if (n < 0 || n > 999 )
{
fprintf(stderr, "%s: give me a natural number"
" less than 1000\n", argv[0]);
return EXIT_FAILURE;
}
// if detab
if (n == 0)
{
fprintf(stderr, "this will detab your file\n");
fprintf(stderr, "If that's what you want, enter zero again\n");
fprintf(stderr, "To abort, enter anything else\n");
d = getchar();
if (d == '0')
fprintf(stderr, "detabbing %s \n", argv[2]);
else
{
fprintf(stderr, "Aborting");
return EXIT_FAILURE;
}
}
// Process path and open file
nc = strlen (path);
c = strlen (exp_suffix);
path_exp = malloc(c + nc + 1);
if (!path_exp)
{
fprintf(stderr, "malloc error: %s\n", __func__);
return EXIT_FAILURE;
}
strcat(strcpy(path_exp, path), exp_suffix);
fin = fopen(path, "r");

And you omitted the call to free.
if (!fin)
{
fprintf(stderr, "%s %s\n", "fopen failed to open", path );
return EXIT_FAILURE;
}
// main control



// print some values and exit
printf(" argv1 is %d\n" , n);
printf(" argv2 is %s\n" , path);

fout = fopen(path_exp, "w");
if (!fout)
{
fprintf(stderr, "%s \n", "fout failed");

You omitted the call to fclose for fin.
return EXIT_FAILURE;
}
fclose(fin);
fclose(fout);
free(path_exp);
return EXIT_SUCCESS;
}

// gcc hh1.c -Wall -o indent.exe

I think the fclose situation looks common-sensical now. I guess I
don't know the circumstances where fout is going to fail, given that
fin succeeded. On my platform, if this little program returns

fout will fail to open if the disk is full, if it is write protected,
if you don't have write access to the path., etc.
EXIT_FAILURE, then files it opened up are going to live for about a
millisecond.

The files will outlive the program since fclose does not attempt to
delete them. fin will be unchanged since you opened it in read mode.
fout will be empty because this code does not yet generate the output.
Anything but. I had strol, and on pg 412 H&S, they give this entire
family. Since there had to be one of them for just plain int, I
deduced that it had to be strtod, following the format specifier for
printing an int.

Any chance you are related to Bill Cunningham? You didn't deduce; you
assumed. If you can't be bothered to look up what a standard function
does, many of us will not be bothered to respond.
K&R §B5 has
int atoi(const char * s)
is equivalent to
(int) strtol(s, (char **)NULL, 10)

Only yesterday did I get rid of endp and put NULL in its place, which,
apparently, should have been casted. This is not random. When I try

Since there was a prototype in scope for strtol, the cast was not
necessary. And the comment was intended to lead you to the decision
that after including &endp as an argument you should have checked it
to determine if strtol succeeded. Even with NULL, strtol is superior
to atoi based on behavior at the extremes, which I'd bet H&S discuss
somewhere.
something new, it has about a 70-30 chance of being right. This aspect
of learning is, from my perspective, stochastic.

There is little evidence you are learning. You post too rapidly to
read, let alone absorb, the comments you receive. You undo
corrections in subsequent posts. More than anything else, you seem to
be following the "10,000 monkeys typing the works of Shakespeare"
approach to programming.
 
F

Frank

There is little evidence you are learning. You post too rapidly to
read, let alone absorb, the comments you receive. You undo
corrections in subsequent posts. More than anything else, you seem to
be following the "10,000 monkeys typing the works of Shakespeare"
approach to programming.

I'm learning that your criticisms are as shrill and overbearing as the
critic.
 n = atoi(argv[1]);

Why are you regressing back to less effective code that was commented
on weeks ago.

I wasn't around weeks ago.
And you omitted the call to free.

No I didn't. I free these 12 bytes on the way to EXIT_SUCCESS.
Freeing them when the next call is going to terminate execution is
like handing a pillow to someone in freefall.
Any chance you are related to Bill Cunningham?  

Any chance you're related to Michael Mair?
You didn't deduce; you
assumed.  If you can't be bothered to look up what a standard function
does, many of us will not be bothered to respond.

I *was* looking at it in a much different form than I'm used to
seeing.
There is little evidence you are learning. You post too rapidly to
read, let alone absorb, the comments you receive. You undo
corrections in subsequent posts. More than anything else, you seem to
be following the "10,000 monkeys typing the works of Shakespeare"
approach to programming.

I hope the rest is silence for you.
 
D

Dik T. Winter

> On Aug 25, 12:32 am, (e-mail address removed) (Ike Naar) wrote:
>
>
> Thx Ike. Gosh, you'd think gcc.exe could say "you're missing a right
> curly brace."

It is not always easy to say whether it is the curly brace that is missing.
Something else might be wrong too.
 
B

Barry Schwarz

snip
this is my version

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

#define uc unsigned char

int main(int argc, char *argv[])
{ unsigned long quanti;
int n;
FILE *fin, *fout;
char *path_exp, *exp_suffix = ".exp";
char tmp[1024], *cp, *path;
int nc;

if(argv==0||argc!=3)

Can the first expression ever evaluate to true? If it does, what do
you know about the second expression?
{exitKo: ;
fprintf(stderr, "usage: \n");
fprintf(stderr, "%s <num> <filename>\n", argv[0]);

fprintf(stderr, "> ThisProgName <num> <filename>\n");

In what way do you think this is better than the original code?
Program names have been known to change over the life of the project.
So have path names.
 
B

Barry Schwarz

Barry Schwarz said:
"Frank" <[email protected]> ha scritto nel messaggio
I'd like the program control to go through stderr, then ffprintf to
stderr "do you really want to erase the tabs completely (Y/N)?", then
pop me back to command line.

it is possible to write a function that gets from stdin the answer
of question of kind (Yes/No or Si/No)

// 1==si 0==no (oppure qualunque altra cosa diversa da " s " o " S ")
int ChiediSiNo(void)
{char tmp[256], *p;

if( getStdI(tmp, 128) == -1 )

Why not follow an existing convention and check for EOF instead of -1?

if (unsigned)-1 == UINT_MAX than it is possible to assign
-1 for error
all other unsigned numbers for the strlen of the string get in tmp

Your original post implied getStdI returned an int, not an unsigned
value.
return 0;

Is "no" the correct response when an I/O error occurs or the response
is missing?
p=tmp;
while(Isspace_m((unsigned char)*p)) ++p;
if( (*p=='s'||*p=='S') &&
(p[1]==0||Isspace_m((unsigned char)p[1])

So "no" is the desired response when the user enters "Si"?

yes the question should be "S/N" or "s/n"

The intended point was

As a matter of good (tm) user interface, if you are going to
perform a validity check on the entire input string instead of just
the first character, any unacceptable value should cause the question
to be reissued rather than assume one of the responses.

If you are going to check only the first letter, you should
check for each acceptable one rather than assume one of the responses.
In this case there is no point in checking the subsequent characters.
but with some change can be ok wit Si/No S/N too
if( (*p=='s'||*p=='S') &&
(p[1]==0||Isspace_m((unsigned char)p[1]))
) return 1;
if( (*p=='s'||*p=='S') && (p[1]=='i'||p[1]=='I')&&
(p[2]==0||Isspace_m((unsigned char)p[2]))
) return 1;
return 0;
 
M

Morris Keesan

Can the first expression ever evaluate to true? If it does, what do
you know about the second expression?
{exitKo: ;
fprintf(stderr, "usage: \n");
fprintf(stderr, "%s <num> <filename>\n", argv[0]);

fprintf(stderr, "> ThisProgName <num> <filename>\n");

In what way do you think this is better than the original code?
Program names have been known to change over the life of the project.
So have path names.

If he thinks that argv could be NULL, then the second form is better,
because it avoids dereferencing a potentially NULL pointer. If I were
writing code where I thought (arg == 0) could be true, I would probably
code this as something like

fprintf(stderr,
"usage: \n%s <num> <filename>\n", argv ? argv[0] :
"ThisProgName");

(I have no clue why the '>' is before "ThisProgName" in his version)
 
J

jameskuyper

Morris said:
....
If he thinks that argv could be NULL, then the second form is better,
because it avoids dereferencing a potentially NULL pointer.

argv can't be NULL, which is the name of a macro. The argv can be
null, which is an adjective applicable to, among other things,
pointers.

If argc is 3, and argv is null, he's not using a conforming
implementation of C, in which case you can't be sure whether or not
the if() statement actually does anything to avoid dereferencing the
null pointer.
... If I were
writing code where I thought (arg == 0) could be true,

argc is allowed to be 0 (5.1.2.2.1p2), in which case the standard
doesn't impose any requriements on argv.
 
K

Keith Thompson

jameskuyper said:
argv can't be NULL, which is the name of a macro. The argv can be
null, which is an adjective applicable to, among other things,
pointers.

If argc is 3, and argv is null, he's not using a conforming
implementation of C, in which case you can't be sure whether or not
the if() statement actually does anything to avoid dereferencing the
null pointer.

argc can't be 3; argc is the name of a parameter, and 3 is a decimal
constant.

Of course I'm not serious, but it's not uncommon to use various forms
of the verb "be" to refer to equality. Saying that "argv is NULL"
merely means that the expression ``argv == NULL'' is true.

But yes, saying argv is null rather than NULL would be clearer.
 
M

Morris Keesan

argv can't be NULL, which is the name of a macro. The argv can be
null, which is an adjective applicable to, among other things,
pointers.

Sheesh. "If he thinks that argv could be equal to NULL, ..."
If argc is 3, and argv is null

This is irrelevant, because in the context of the cited code,
if (argv == 0) then we don't know anything about the value of argc.
argc is allowed to be 0 (5.1.2.2.1p2), in which case the standard
doesn't impose any requriements on argv.

.... but my typo here was an accidentally omitted 'v', not a 'c', i.e.
"... where I thought (argv == 0) could be true"
 
J

jameskuyper

Richard said:
jameskuyper said:

argc is allowed to be 0 (5.1.2.2.1p2), in which case the standard
doesn't impose any requriements on argv.

"argv[argc] shall be a null pointer", so there is at least a
requirement on argv[0].

You're right, I didn't think about that one properly. Therefore, I
don't see any way for argv to be null.
 
J

jameskuyper

Morris said:
Sheesh. "If he thinks that argv could be equal to NULL, ..."

Why correct it that way? Changing NULL to null is simpler.
This is irrelevant, because in the context of the cited code,
if (argv == 0) then we don't know anything about the value of argc.

Yes, I made it more complicated than it needed to be. Change my
statement to:

"If argv is null, he's not using a conforming implementation of
C, ..."
 
N

Nick Keighley

argv can't be NULL, which is the name of a macro. The argv can be
null, which is an adjective applicable to, among other things,
pointers.

why can't argv be NULL. It can certainly be equal to NULL.
I think you have your pedantry level set too high
 
J

James Kuyper

Nick said:
why can't argv be NULL. It can certainly be equal to NULL.

Being NULL and comparing equal to NULL are two different things. Keep in
mind that NULL could expand into an integer expression with a value of
0, in which case it cannot actually be equal to a pointer; it can
compare equal to a pointer only because of the special rules that C has
for null pointer constants, not because it's actually meaningful to
compare a pointer with an integer for equality.

You could write

#define argv NULL

in which case it would be valid to say "argv is NULL". However, that
would tend to interfere slightly :) with the conventional uses of argv.
I think you have your pedantry level set too high

I don't think yours is set high enough. Shall we agree to disagree on that?
 
B

Ben Bacarisse

Richard Heathfield said:
Joe Wright said:


Dead in the water.

What, even in comp.lang.c?

The case is (quite reasonably) that since "argv[argc] shall be null a
pointer" (5.1.2.2.1p2) argv can't, itself, be == NULL. Let's reason
unreasonably for while...

The evaluation of argv is undefined when argv == NULL, so what
prevents the DS9000's C implementation from defining NULL == NULL
for all i? This will make argv[argc] == NULL even when argv == NULL.

I.e. you can't guarantee that

#include <stdlib.h>
int main(int argc, char **argv)
{
return argv != NULL ? EXIT_SUCCESS : EXIT_FAILURE;
}

returns EXIT_SUCCESS on all conforming implementations. You can't
portably assume that argv can be NULL (i.e. there are many
implementations on which it can't be), but you can't portably assume
that it won't ever be.

I rather hope there is something wrong with this line of reasoning,
but I can't see it at the moment.

If you want the DS9000 to be more devious, only NULL[0] might be ==
NULL, or you might also use the permission from 6.6p10 to allow
argv[argc] to be an implementation-defined form of constant expression
so that, in main, argv[argc] is a null pointer constant!
 
K

Keith Thompson

James Kuyper said:
Being NULL and comparing equal to NULL are two different things. Keep
in mind that NULL could expand into an integer expression with a value
of 0, in which case it cannot actually be equal to a pointer; it can
compare equal to a pointer only because of the special rules that C
has for null pointer constants, not because it's actually meaningful
to compare a pointer with an integer for equality.

What does "equal to a pointer" mean other than as defined by the "=="
operator?

[...]
 

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,774
Messages
2,569,598
Members
45,148
Latest member
ElizbethDa
Top