parsing practice

B

Bill Cunningham

This simple little program takes from stdin and writes to stdout. No
other streams are involved. Why am I segmentation faulting? I am guessing it
has something to do with the argc==0 part of the program but I don't know
how I should change it.
All characters on each line should begin with an '+' otherwise the
characters aren't printed or in this case an error is triggered.

Bill#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
if (argc == 0) {
fprintf(stderr, "parsing usage error\n");
return 1;
}
if (*argv[1] == '+') {
puts("good + found\n");
return 0;
} else {
if (*argv[1] != '+') {
fputs("error + not found\n", stderr);
return 1;
}
return 0;

}
return 0;
}
 
I

Ike Naar

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

int main(int argc, char *argv[])
{
if (argc == 0) {
fprintf(stderr, "parsing usage error\n");
return 1;
}

For the next line to work, argc should be at least 2;
nonzero is not good enough.
if (*argv[1] == '+') {
puts("good + found\n");
return 0;
} else {
if (*argv[1] != '+') {
fputs("error + not found\n", stderr);
return 1;
}
return 0;

}
return 0;
}
 
B

Bill Cunningham

For the next line to work, argc should be at least 2;
nonzero is not good enough.

I'm not quite understanding here. "Nonzero is not good enough." If there
are no argc's I want the program to terminate with the "usage error" error.
As long as it is nonzero I am happy. I'm stuck on this one.

Bill
 
I

Ian Collins

I'm not quite understanding here. "Nonzero is not good enough." If there
are no argc's I want the program to terminate with the "usage error" error.
As long as it is nonzero I am happy. I'm stuck on this one.

What happens if argc == 1?
 
D

Dave Hansen

    I'm not quite understanding here. "Nonzero is not good enough." If there
are no argc's I want the program to terminate with the "usage error" error.
As long as it is nonzero I am happy. I'm stuck on this one.

It's how array indexing works.

If argc is zero, you cannot access any elements of argv.

If argc is 1, you may only access argv[0].

If you want to access argv[1], argc must be at least 2.

Note: argv[0] is often the string that invoked the program itself. I
don't think you'll ever see argc==0.

Regards,

-=Dave
 
I

Ike Naar

I'm not quite understanding here. "Nonzero is not good enough." If there
are no argc's I want the program to terminate with the "usage error" error.
As long as it is nonzero I am happy. I'm stuck on this one.

If argc = 1, argv[0] is a valid string but argv[1] = NULL.
You wouldn't want to dereference argv[1] in that case.
 
J

James Harris

    I'm not quite understanding here. "Nonzero is not good enough." If there
are no argc's I want the program to terminate with the "usage error" error.
As long as it is nonzero I am happy. I'm stuck on this one.

Try an experiment to find how your program is started:

int main(int argc, char *argv[]) {
printf("argc = %d\n", argc);
}

Try running this with a varying number of arguments to see how argc is
calculated. Then you can add a loop to print the argv values. This
should help you see how the arg values are used - which should resolve
your original problem.

James
 
N

Nick

Bill Cunningham said:
This simple little program takes from stdin and writes to stdout.

No it doesn't. It never touches stdin.

It uses the parameters passed in argv, but that's nothing at all to do
with "taking from stdin".
 
J

James Harris

    I'm not quite understanding here. "Nonzero is not good enough." If there
are no argc's I want the program to terminate with the "usage error" error.
As long as it is nonzero I am happy. I'm stuck on this one.

Try an experiment to find how your program is started:

int main(int argc, char *argv[]) {
  printf("argc = %d\n", argc);

}

Try running this with a varying number of arguments to see how argc is
calculated. Then you can add a loop to print the argv values. This
should help you see how the arg values are used - which should resolve
your original problem.

An additional point: if you write the above code to print the args
keep it handy as you will be able to use it to find out

- how arguments are delimited
- how argv[0] appears when the command is
- in the path and found implicitly
- explicitly specified
- what happens if you put an argument in quotes
- what happens when you use backslashes before spaces
- what happens when you put backslashes elswehere
- what happens when you use wild cards in arguments
- etc

When run in the appropriate environment it will also show any
differences between the way Unix and Windows handle command line
arguments.

Seeing what's going on is an aid to understanding.

James
 
N

Nick Keighley

    This simple little program takes from stdin and writes to stdout. No
other streams are involved. Why am I segmentation faulting? I am guessing [...]

<snip>

why? Why are you guessing? Why don't you debug the program? Use a
debugger or put in printf()s or use assert()s
 
B

Bill Cunningham

If argc = 1, argv[0] is a valid string but argv[1] = NULL.
You wouldn't want to dereference argv[1] in that case.

That's another thing I tried without really understanding what I was
doing and it worked. When I tried argv[1] without the dereference I got an
error somethng like "pointer to int..." something. So I put in the *argv[1]
and it worked. Except for the seg. fault.

Bill
 
B

Bill Cunningham

[snip]
According to section 5.1.2.2.1 of the C standard:
- argc must be non-negative
- argv[argc] must be a null pointer
- if argc is greater than zero, then argv[0] is NOT an argument,
it's the name of the program, or an empty string if the program
name is not available.
- if argc is greater than one, argv[1] through argv[argc-1]
will be your program parameters.

In other words, argc is "count of items in argv", NOT "count of
arguments".

Oh I see.

And since the zeroeth element of argc is always
reserved for the program name (whether it's available or not),
if argc is non-zero, argc = "number of arguments + 1".

(The standard doesn't mention under what conditions argc
is 0. I've never seen argc==0 in my life. I suppose
a compiler that doesn't support arguments could set it
to 0 to indicate that arguments aren't supported.)

In practice, if there are no arguments, argc will usually be 1.

If argc is 1, your first "if" will fail, and your second
"if" will cause an ILLEGAL MEMORY ACCESS at runtime.

Hence the first "if" should read:

if (argc < 2) {
fprintf(stderr, "parsing usage error\n");
return 1;
}

Insisting that argc be at least 2 is the only way to insure
that referencing "argv[1]" is legal.

--
Cheers,
Robbie Hatley
lonewolf at well dot com
www dot well dot com slant tilde lonewolf slant
 
B

Bill Cunningham

No it doesn't. It never touches stdin.

It uses the parameters passed in argv, but that's nothing at all to do
with "taking from stdin".

It takes input from the keyboard. I thought that was stdin.

Bill
 
N

Nick

Bill Cunningham said:
It takes input from the keyboard. I thought that was stdin.

No, it takes input from the command line.

I can create a shell that launches it with a suitable input string and
make it that this is run whenever I log onto the computer. No keyboard
input in sight.
 
A

Andrew Poelstra

No, it takes input from the command line.

I can create a shell that launches it with a suitable input string and
make it that this is run whenever I log onto the computer. No keyboard
input in sight.

To be fair, you can do this with stdin as well.
 
K

Kenny McCormack

To be fair, you can do this with stdin as well.

How do you know that? Perhaps Nick doesn't know how to do that.

Really, for a group that prides itself on
anal-retentive-to-the-max-don't-claim-anything-as-true-that-isn't-100%-true-in-all-possible-cases-in-all-possible-universes,
the claim made above is really far-fetched.
 
I

Ike Naar

If argc = 1, argv[0] is a valid string but argv[1] = NULL.
You wouldn't want to dereference argv[1] in that case.

That's another thing I tried without really understanding what I was
doing and it worked. When I tried argv[1] without the dereference I got an
error somethng like "pointer to int..." something. So I put in the *argv[1]
and it worked. Except for the seg. fault.

The point is not that you should try argv[1] without the dereference.
You _should_ use *argv[1], (that is, with the dereference), but first
you should check whether it is safe to dereference argv[1], and that is
only the case if argc is at least two; if argc equals zero, argv[1] is
indeterminate and cannot be dereferenced; if argc equals one, argv[1]
is NULL and cannot be dereferenced. If argc is at least two, argv[1]
points to a valid string and can be dereferenced.

In your program, you exit early if argc equals 0. That is good.
If argc is nonzero, you continue, and then dereference argv[1].
But all you know is that argc is nonzero; if argc equals 1 (which
is a nonzero value) you dereference argv[1] anyway, and that is wrong.

So, what you should do is the following:
- check whether argc is at most 1 (equals 0 or equals 1), if so, exit early.
- otherwise, continue, and since argc is now at least 2,
it is safe to dereference argv[1].
 
K

Kenny McCormack

True. Nevertheless, using command line arguments is /not/ "taking from
stdin".

It could be/could have been. What do you suppose the shell reads from
when you are typing a command?
 
R

Rui Maciel

Bill said:
This simple little program takes from stdin and writes to stdout. No
other streams are involved. Why am I segmentation faulting? I am guessing
it has something to do with the argc==0 part of the program but I don't
know how I should change it.
All characters on each line should begin with an '+' otherwise the
characters aren't printed or in this case an error is triggered.

Bill#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
if (argc == 0)

argc is guaranteed to be greater than zero, as argv indicates the number of parameters
which were passed. As argv[0] is used to point to the program's name, it will always be at
least 1. Therefore, this test is always false...

{
fprintf(stderr, "parsing usage error\n");
return 1;
}

....and the previous code will never run.

As the previous sanity check failed, then in this next LoC, if you haven't passed any
argument to your program then your program will attempt to access memory which isn't
allowed to access. Hence, when you run your compiled program without ever passing any
arguments to it, and therefore will not have any memory reserved to argv[1], you will get a
segmentation faul.

if (*argv[1] == '+') {
puts("good + found\n");
return 0;
} else {
if (*argv[1] != '+') {
fputs("error + not found\n", stderr);
return 1;
}
return 0;

}
return 0;
}


Hope this helps,
Rui Maciel
 

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,779
Messages
2,569,606
Members
45,239
Latest member
Alex Young

Latest Threads

Top