accessing and storing character arguements from command line

D

Dawn Minnis

Hey guys

If I have a program (see codeSnippet1) that I compile to be called test.o
Then run it as test.o n n 2 3 4
I want the code to be able to strip out the two characters at the start
(always going to be 2) and store them as characters. But I can't seem to
get it to work because it is a pointer to a vector of characters.

However, if I only run with integer arguements and use codeSnippet2 it works
fine and they convert nicely to integers.

So therefore, I want to ammend my nice little loop to start converting to
integers from x=2 onwards. Which I can do fine. But how do I get the two
characters that are actual characters to be stored as characters. It
doesn't seem to be straightforward - or am I missing something stupidly
obvious?



codeSnippet1
int main(int argc, char *argv[])
{
int x;
char a, b;

/*Need these two lines to work ie get the first two arguements stored as
single characters for use elsewhere*/
a = argv[0];
b = argv[1];
/**************************/

}

codeSnippet2
int main(int argc, char *argv[])
{
int x;
int params[10];
for(x=0; x<argc; x++)
{
params[x] = atoi(argv[x]);
}
}
 
D

David Resnick

Dawn said:
Hey guys

If I have a program (see codeSnippet1) that I compile to be called test.o
Then run it as test.o n n 2 3 4
I want the code to be able to strip out the two characters at the start
(always going to be 2) and store them as characters. But I can't seem to
get it to work because it is a pointer to a vector of characters.

However, if I only run with integer arguements and use codeSnippet2 it works
fine and they convert nicely to integers.

So therefore, I want to ammend my nice little loop to start converting to
integers from x=2 onwards. Which I can do fine. But how do I get the two
characters that are actual characters to be stored as characters. It
doesn't seem to be straightforward - or am I missing something stupidly
obvious?



codeSnippet1
int main(int argc, char *argv[])
{
int x;
char a, b;

/*Need these two lines to work ie get the first two arguements stored as
single characters for use elsewhere*/
a = argv[0];
b = argv[1];
/**************************/

}

a = *argv[1];
b = *argv[2];

argv is a char **, so argv[1] is a char *. If you want the char pointed
to by argv[1] you need to dereference it again... BTW, argv[0] is the
program name if such is available.

-David
 
K

Kiru Sengal

Dawn said:
Hey guys

If I have a program (see codeSnippet1) that I compile to be called test.o
Then run it as test.o n n 2 3 4
I want the code to be able to strip out the two characters at the start
(always going to be 2) and store them as characters.
\

But how do I get the two
characters that are actual characters to be stored as characters. It
doesn't seem to be straightforward - or am I missing something stupidly
obvious?

You're missing the fact that main is passed a pointer to pointer to
char
(or you can think of it as an array of pointers to char).
codeSnippet1
int main(int argc, char *argv[])

The *argv[] parameter shows that main is receiving an array of pointers
to char (since arrays are really passed as pointers, this becomes a
pointer to a pointer to char - **argv is equivalent)
{
int x;
char a, b;

/*Need these two lines to work ie get the first two arguements stored as
single characters for use elsewhere*/
a = argv[0];
b = argv[1];

With once subscript attached to argv, you are only dereferencing by one
level.
a is being assigned the first element in the array (which is a pointer
to the first string). b is being assigned the second element in the
array (which is a pointer to the second string). The command line
interpreter considers each word (word being a sequence of
non-whitespace characters) entered at the command line as a separate
string, where the program name is the first string (pointed to by
argv[0]).

I presume you want to work with the characters of the second string
(which is the first string after the program name). To do this, use
this type of subscripting: argv[1] , which is character i of string
1 (remember numbering starts at 0).

So something like this would work if the "first two characters" are NOT
separated by whitespace (which is what I assumed you wanted in the
above paragraph):

a = argv[1][0]; /* character 0 of string 1 */
b = argv[1][1]; /* character 1 of string 1 */



This would work if the first two characters are separated by
whitespace:

a = argv[1][0]; /* character 0 of string 1 */
b = argv[2][0]; /* character 0 of string 2 */



Although I wouldn't do this in a serious program because the user might
not provide the expected input at the command-line (user might enter
more than 1 character before whitespace). You are better dealing with
entire strings, which will allow you to do more error checking.


Remember, string 0 is the name of the program and is pointed to by
argv[0], so I don't think you want to play with argv[0] -pointer to
string 0- or argv[0][x] -character x of string 0-.
 
M

Michael Mair

Dawn said:
Hey guys

If I have a program (see codeSnippet1) that I compile to be called test.o
Then run it as test.o n n 2 3 4

<OT>
It is probably not a brilliant idea to call a program *.o as often
".o" marks object files which are created by compiling a translation
unit and several of which may be linked together to obtain the final
program
I want the code to be able to strip out the two characters at the start
(always going to be 2) and store them as characters. But I can't seem to
get it to work because it is a pointer to a vector of characters.

You do not need to "strip out" the characters. You probably mean
'n' and 'n' which are argv[1][0] and argv[2][0] in your example.
The first two characters could also be 't' and 'e' (you do not
express that clearly).
If something is a char **, you obviously have to "get rid" of
two levels of indirection, so you either want
char mycharacter, **pp = argv;
pp++; /* advance to &argv[1] */
mycharacter = **pp;
or
char mycharacter, *p = argv[1];
mycharacter = *p;
or
char mycharacter = *(argv[1]); /* gratuituous parens for clarifying */
or
char mycharacter = argv[1][0];
However, if I only run with integer arguements and use codeSnippet2 it works
fine and they convert nicely to integers.

You are converting strings to integers.
This is different from extracting one character from a string.
So therefore, I want to ammend my nice little loop to start converting to
integers from x=2 onwards. Which I can do fine. But how do I get the two
characters that are actual characters to be stored as characters. It
doesn't seem to be straightforward - or am I missing something stupidly
obvious?



codeSnippet1
int main(int argc, char *argv[])
{
int x;
char a, b;

/*Need these two lines to work ie get the first two arguements stored as
single characters for use elsewhere*/
a = argv[0];
b = argv[1];

Check for argc > 2 first. Then:
You probably want
a = *argv[1];
b = *argv[2];
argv[0] (if existing) is the name of the program.
/**************************/

}

codeSnippet2
int main(int argc, char *argv[])
{
int x;
int params[10];
for(x=0; x<argc; x++)
{
params[x] = atoi(argv[x]);

This does not make sense.
Please read up on argv in your C book.
You want to have:

if (argc >= 11)
for (x=0; x<10; x++)
params[x] = atoi(argv[x+1]);


Cheers
Michael
 
D

Dawn Minnis

Thank you

Lots of food for thought there.

I must have about 7 or 8 C programming books surrounding me but I still get
confused by referencing and dereferencing pointers.

Sorry about the confusion over the first element being the filename - I did
actually know that, but I wrote the code out of my head because getting the
code would have meant booting up my Linux machine and thats just too tedious
for this time of night for one bit of code.
The *argv[] parameter shows that main is receiving an array of pointers
to char (since arrays are really passed as pointers, this becomes a
pointer to a pointer to char - **argv is equivalent)

So just to clarify, even thought I have written char *argv[] it still
means a double pointer? My supervisor kept writing char **argv[] but I
thought that just overcomplicated things so I thought writing char *argv[]
lessened the level of abstraction used.

Maybe I'm away off in a world of my own again. I have a cold. Be gentle
with me.

Dawn
 
M

Michael Mair

Dawn said:
Thank you

Lots of food for thought there.

I must have about 7 or 8 C programming books surrounding me but I still get
confused by referencing and dereferencing pointers.

Sorry about the confusion over the first element being the filename - I did
actually know that, but I wrote the code out of my head because getting the
code would have meant booting up my Linux machine and thats just too tedious
for this time of night for one bit of code.

But having three people to "repair" an error that is not there
is better?

The *argv[] parameter shows that main is receiving an array of pointers
to char (since arrays are really passed as pointers, this becomes a
pointer to a pointer to char - **argv is equivalent)

So just to clarify, even thought I have written char *argv[] it still
means a double pointer? My supervisor kept writing char **argv[] but I
thought that just overcomplicated things so I thought writing char *argv[]
lessened the level of abstraction used.

Your supervisor may have written char **argv -- certainly not
char **argv[] as this is equivalent to char ***argv in a
function parameter list.
You can think of it like that:
Arrays are never passed by value in C. Instead, the address of
the first element is passed to a function requiring a
T array[]
parameter (where T is some type). T *array also contains the
address of an object of type T -- which obviously can be the
first element of an array. The array subscripting works the
same in both cases.
Note: T array[][] does not work as a replacement for T **array.
Working out the reason is left as an exercise :)

Maybe I'm away off in a world of my own again. I have a cold. Be gentle
with me.

Welcome to the fun world of C.


Cheers
Michael
 
D

Dawn Minnis

Sorry about the confusion over the first element being the filename - I
But having three people to "repair" an error that is not there
is better?

actually, upon reflection, I didn't even notice I was doing it until it was
pointed out to me in this line:
params[x] = atoi(argv[x+1]);

Thanks for that. Now I can see that even thought I read, listened,
understood etc, I still went ahead and abandoned all rational thinking in
favour of stupid/cold-infected coding.
Your supervisor may have written char **argv -- certainly not
char **argv[] as this is equivalent to char ***argv in a
function parameter list.

Would love to concede to you on that one but afraid not. But in fairness,
he does have a tendancy to say one thing and then write another. Or
describe row-major as column-major. I think his brain is actually too
intelligent for the rest of his body to keep up.
Welcome to the fun world of C.

PAH !!! *shoots sarcastic look across the web* :-D
 
K

Kenneth Bull

Dawn said:
But having three people to "repair" an error that is not there
is better?

actually, upon reflection, I didn't even notice I was doing it until it was
pointed out to me in this line:
params[x] = atoi(argv[x+1]);

Thanks for that. Now I can see that even thought I read, listened,
understood etc, I still went ahead and abandoned all rational thinking in
favour of stupid/cold-infected coding.
Your supervisor may have written char **argv -- certainly not
char **argv[] as this is equivalent to char ***argv in a
function parameter list.

Would love to concede to you on that one but afraid not. But in fairness,
he does have a tendancy to say one thing and then write another. Or
describe row-major as column-major. I think his brain is actually too
intelligent for the rest of his body to keep up.
Welcome to the fun world of C.

PAH !!! *shoots sarcastic look across the web* :-D


Long ago my opinion of this world changed from thinking it was a
meritocracy to thinking it was based mostly on other factors like
luck, timing, randmoness of the universe, politics, and a little merit
too. How your supervisor got to become a supervisor is a prime example
(especially when I know genius programmers in every country who can't
seem to find jobs).
 
C

Chris Williams

Dawn said:
I must have about 7 or 8 C programming books surrounding me but I still get
confused by referencing and dereferencing pointers.

A pointer is just an address. If you have ten cubby holes numbered 100
to 109, then at any point you will either want to know the number of
the cubby hole or you will want what is actually in it. The only tricky
part is that sometimes you have to write down and store the address of
one cubby hole in another one.
So just to clarify, even thought I have written char *argv[] it still
means a double pointer?

There are only cubby hole numbers and cubby hole contents in C,
regardless of what symbols you might be using.

char** stringArray1; //an array of strings
char* stringArray2[]; //an array of strings
char stringArray3[][]; //an array of strings

In general though, I would recommend the top one for main(). What the
"imaginary" difference is between a pointer and an array is that an
array you (as the programmer) know exists and know has a set length:

char tempBuffer[100]; /*temporary buffer with a definite max length*/

While a pointer is just a way of saying, "Well I know that there's some
data over that-a-way" but you really aren't certain of the
length--probably because the length will be determined by the code
itself, not you when coding.

char* tempBuffer; /* buffer that we will allocate some random amount
of bytes to */

So when you first receive your command line arguments from main(), you
will still have no idea how many parameters the user passed in nor how
long any of those are. So as a way of pointing that out to yourself you
are better off to use two *s instead of two []s.

int main(int argc, char** argv) { /* accept any number of random
thingies from user */
return 0;
}

Note:

char* string1 = "hello"; /* set text to print out */
char string2[] = "hello"; /* generic string that we might edit later
*/

This is a case you need to be careful about. C can treat these two
cases differently, with the first one pointing to a fixed string that
might be stored in a place you aren't allowed to write to, while as the
second will always be created in a place you can fiddle about with
freely.
But if you stick to the basic idea that * just means something you
"kind of" know about, while [] is for things you are very certain about
then you should be able to remember this case. The pointer one is off
in some controlled space while as the array is over with the you and
rest of your variables.

-Chris
 
D

Dave Thompson

Dawn said:
I must have about 7 or 8 C programming books surrounding me but I still get
confused by referencing and dereferencing pointers.

A pointer is just an address. If you have ten cubby holes numbered 100
to 109, then at any point you will either want to know the number of
the cubby hole or you will want what is actually in it. The only tricky
part is that sometimes you have to write down and store the address of
one cubby hole in another one.
So just to clarify, even thought I have written char *argv[] it still
means a double pointer?
Yes.

There are only cubby hole numbers and cubby hole contents in C,
regardless of what symbols you might be using.
Sort of. With the caveat that different cubbyholes have different
'shapes' -- and thus certain cubbyhole numbers can only be used to
point to (and store or fetch) certain kinds of contents.
char** stringArray1; //an array of strings
char* stringArray2[]; //an array of strings
char stringArray3[][]; //an array of strings

In general though, I would recommend the top one for main(). What the
"imaginary" difference is between a pointer and an array is that an
array you (as the programmer) know exists and know has a set length:
No. Arrays in C are really arrays not just pre-set pointers as they
were in B and BCPL; in all but a few cases they _convert_ to a
pointer, which we informally call decay. The first two are equivalent
_for a function parameter_ because a parameter whose type is array is
'rewritten' as a pointer -- at the top level only; they are not
equivalent for a variable. The third is not the same ever, and is
outright illegal in C99 -- you now cannot even declare an array of
incomplete type. See FAQ section 6 at the usual places and
http://www.eskimo.com/~scs/C-faq/top.html .
char tempBuffer[100]; /*temporary buffer with a definite max length*/

While a pointer is just a way of saying, "Well I know that there's some
data over that-a-way" but you really aren't certain of the
length--probably because the length will be determined by the code
itself, not you when coding.
Length not known in advance is one reason; "I want to control the
lifetime" (less than static but more than automatic) is another and "I
want to access different things in different circumstances" a third.

Aside: I would say the length is determined by the code at execution
time, or by execution of the code; even a staticly declared length is
still 'determined by the code'.
char* tempBuffer; /* buffer that we will allocate some random amount
of bytes to */
Not truly random, except in very rare cases, but variable and perhaps
even random-seeming. said:
So when you first receive your command line arguments from main(), you
will still have no idea how many parameters the user passed in nor how
long any of those are. So as a way of pointing that out to yourself you
are better off to use two *s instead of two []s.

int main(int argc, char** argv) { /* accept any number of random
thingies from user */
return 0;
}
Arguable. Either char** or char*[] is the same to the compiler in this
context. Some people prefer to see that it is really a pointer (which
is used to access an array); some people prefer to see that its
'purpose' is to access the array. Six of one ....
Note:

char* string1 = "hello"; /* set text to print out */
char string2[] = "hello"; /* generic string that we might edit later
*/

This is a case you need to be careful about. C can treat these two
cases differently, with the first one pointing to a fixed string that
might be stored in a place you aren't allowed to write to, while as the
second will always be created in a place you can fiddle about with
freely.

Right. More precisely, it violates the standard to write into the
first (literal) string no matter how the compiler stores it. It is
legal to modify the second -- but only within its allocated length,
which for the example given means you can't _extend_ it.
But if you stick to the basic idea that * just means something you
"kind of" know about, while [] is for things you are very certain about
then you should be able to remember this case. The pointer one is off
in some controlled space while as the array is over with the you and
rest of your variables.

-Chris

- David.Thompson1 at worldnet.att.net
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top