C++ Primer ex 7.16 - arguments to main

A

arnuld

i am not able to figure out the error:

/* C++ Primer - 4/e
*
* exercise 7.16
* STATEMENT:
* write a programme that accepts the arguments to main. print
* the values passed to main.
*
*/


#include <iostream>

int main( int argc, char **argv )
{
std::cout << "These arguments were passed to 'main()' :\t";

/* an int vale can be printed easily */
std::cout << argc << "\t";

/* to prinit array of strings, we need to consider 2 pointers:
one to the 1st character in string literal presented in the array and 2nd
to the 1st element of the array itself.

to print the string literals we will use pointer to a pointer to char
and to move around in the array we will use a pointer to char.
*/
char *pchar = 0;
pchar **p_string = **argv;
char *p_index = *argv;

while( *p_string++ != '\0' )
{
while( **p_index != '\0' )
{
std::cout << **p_index++;
}
std::cout << "\t";
}

return 0;
}


/* OUTPUT
~/programming/cpp $ g++ -ansi -pedantic -Wall -Wextra ex_07-16.cpp
ex_07-16.cpp: In function 'int main(int, char**)':
ex_07-16.cpp:28: error: 'p_string' was not declared in this scope
ex_07-16.cpp:33: error: invalid type argument of 'unary *'
ex_07-16.cpp:35: error: invalid type argument of 'unary *'
~/programming/cpp $

*/
 
V

Victor Bazarov

arnuld said:
i am not able to figure out the error:

/* C++ Primer - 4/e
*
* exercise 7.16
* STATEMENT:
* write a programme that accepts the arguments to main. print
* the values passed to main.
*
*/


#include <iostream>

int main( int argc, char **argv )
{
std::cout << "These arguments were passed to 'main()' :\t";

/* an int vale can be printed easily */
std::cout << argc << "\t";

/* to prinit array of strings, we need to consider 2 pointers:
one to the 1st character in string literal presented in the array and
2nd to the 1st element of the array itself.

to print the string literals we will use pointer to a pointer to
char and to move around in the array we will use a pointer to char.
*/
char *pchar = 0;

'pchar' is a variable name.
pchar **p_string = **argv;

Here you're trying to use 'pchar' as if it is a type. BTW, you don't
really need to assign 'argv' to another variable *unless* you need it
for something else later. Just use 'argv' where you wanted to use
'p_string'.

But, really, why do you need all this pointer arithmetic exposed when
you can just use indexing?
char *p_index = *argv;

while( *p_string++ != '\0' )
{
while( **p_index != '\0' )
{
std::cout << **p_index++;
}
std::cout << "\t";
}

return 0;
}


/* OUTPUT
~/programming/cpp $ g++ -ansi -pedantic -Wall -Wextra ex_07-16.cpp
ex_07-16.cpp: In function 'int main(int, char**)':
ex_07-16.cpp:28: error: 'p_string' was not declared in this scope
ex_07-16.cpp:33: error: invalid type argument of 'unary *'
ex_07-16.cpp:35: error: invalid type argument of 'unary *'
~/programming/cpp $

*/

V
 
A

arnuld

'pchar' is a variable name.


Here you're trying to use 'pchar' as if it is a type. BTW, you don't
really need to assign 'argv' to another variable *unless* you need it
for something else later. Just use 'argv' where you wanted to use
'p_string'.

But, really, why do you need all this pointer arithmetic exposed when
you can just use indexing?

i don't know how to use indexing for an array of arrays, especiall when
the size of inner array is unknown. i do know about pointer, though not
much.

i changed the variable definitions to these ones:

typedef char* pchar;
typedef pchar* ppchar;
ppchar p_string = **argv;
pchar p_index = *argv;


still no luck
 
V

Victor Bazarov

arnuld said:
i don't know how to use indexing for an array of arrays,

It's not an array of arrays. It's an array of pointers. When you
index in an array of pointers, you get a pointer, which you can also
index to get the element.
especiall
when the size of inner array is unknown. i do know about pointer,
though not much.

You need to learn more, or so it seems.
i changed the variable definitions to these ones:

typedef char* pchar;
typedef pchar* ppchar;
ppchar p_string = **argv;

Why are you dereferencing 'argv' here? 'argv' has the same type as
'p_string'. If you want to copy its value, just copy its value, do
not trying to copy what 'argv' points to...
pchar p_index = *argv;

Not sure what you need this for.
still no luck

I strongly recommend you against trying to comprehend pointers unless
you really need to. Memorize the idiom:

std::vector<std::string> args(argv, argv + argc);

and use 'args' instead.

Unless you've programmed in Assembly (and understand how addressing
works in the computer), pointers are not an easy concept to grasp,
methinks. The book should be able to explain what a value of the
pointer is, what happens when you write "*ptr", how those operators
chain (and so on). I suspect you either are not paying attention
or the book is not good enough. The latter is more likely. Keep
in mind that if the book is less than really good, you need to be
very attentive trying to understand what it's trying to explain to
you, not just skim the surface.

V
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

i am not able to figure out the error:

/* C++ Primer - 4/e
*
* exercise 7.16
* STATEMENT:
* write a programme that accepts the arguments to main. print
* the values passed to main.
*
*/


#include <iostream>

int main( int argc, char **argv )
{

I usually write this as

int main (int argc, char* argv[])

That is, argv is an array of pointers to char, or argv is an array of
pointers to NULL-terminated C-strings, where each string is an argument
passed to the program, and argc is the number of elements in the array.
In fact argc is short for "argument count" and argv is "argument values".

This reduces the problem to a loop over an array and printing C-strings.
 
F

Frank Birbacher

Hi!
i don't know how to use indexing for an array of arrays, especiall when
the size of inner array is unknown. i do know about pointer, though not
much.

Think of "a[x]" as "*(a+x)", where "a" is an array/pointer (they are to
the most extend interchangably).

int main(const int argc, char* argv[])
{
//now think of "argv" as a "char**"
typedef char* String;
//or "argv" as "String*"/String array

//assume argc>=3 :
argv[0]; //name of the program
argv[1]; //first argument to the program
argv[2]; //second argument
argv[3]; //third argument
}

HTH,
Frank
 
A

arnuld

It's not an array of arrays. It's an array of pointers. When you
index in an array of pointers, you get a pointer, which you can also
index to get the element.

i meant, arrays of strinig literals and array sof string literals are
themselves arrays of char terminated with NULL. so it is an array of
arrays of char.

that is what *exactly* i meant and understand about "argv".
You need to learn more, or so it seems.

you are right. it seems like i am no literate about very basic aspects.
Why are you dereferencing 'argv' here? 'argv' has the same type as
'p_string'. If you want to copy its value, just copy its value, do not
trying to copy what 'argv' points to...

i want to point p_string to poin to the argv's 1st element of the 1st
element. i mean, the 1st element of the array of char (and array of char
is the string literal, the 1st element of argv. henc ei want to point to
the 1st charachter of the 1st string literal)

Not sure what you need this for.

it will loop through the argv to know the end of argv.

I strongly recommend you against trying to comprehend pointers unless
you really need to. Memorize the idiom:

std::vector<std::string> args(argv, argv + argc);

it is a vector of library strings but what
"args(argv, argv + argc)" means ?
and use 'args' instead.

where, in "int main(..... )"

Unless you've programmed in Assembly (and understand how addressing
works in the computer), pointers are not an easy concept to grasp,
methinks. The book should be able to explain what a value of the
pointer is, what happens when you write "*ptr", how those operators
chain (and so on). I suspect you either are not paying attention or the
book is not good enough. The latter is more likely. Keep in mind that
if the book is less than really good, you need to be very attentive
trying to understand what it's trying to explain to you, not just skim
the surface.


that is C++ Primer 4/e and like Accelerated C++, it keeps one away from
pointers and arrays. there is a chpater about arrays and pointers but it
does not explain much except that "int* pi = &i" is a pointer to an int
and "*pi" gives the valie of "i" and "pi" has its own address, it s
acompound variable, a new object different from "i" but it points to "i"
and hold the machine address of "i". the chaining-concept is not
discussed. it always advises to not to use pointers and arrays hence
avoids them ( i think for a good reason ). it says pointers are source of
potential bugs, use references (and FAQ agrees with it).


BTW, the things you have talked about in this post give me a feeling like
i got when i looked through some pages of K&R2 .
 
A

arnuld

I usually write this as

int main (int argc, char* argv[])

That is, argv is an array of pointers to char, or argv is an array of
pointers to NULL-terminated C-strings, where each string is an argument
passed to the program, and argc is the number of elements in the array.
In fact argc is short for "argument count" and argv is "argument
values".

This reduces the problem to a loop over an array and printing C-strings.

ok, here it is in 2 versions, one with indexing and one with pointers,
both fall under an infinite-loop :(


#include <iostream>

int main( int argc, char *argv[] )
{
std::cout << "These arguments were passed to 'main()'" << std::endl;


/* an int value can be printed easily */ std::cout << argc << std::endl;

int i = 0;

while( i < argc )
{
std::cout << argv << "\n";
}

return 0;
}


------- pointer version ------------------- #include <iostream>

int main( int argc, char *argv[] )
{
std::cout << "These arguments were passed to 'main()'" << std::endl;


/* an int value can be printed easily */
std::cout << argc << std::endl;

char *pchar = argv[0];

while( *pchar != '\0' )
{
std::cout << *pchar << "\n";
}

return 0;
}
 
V

Victor Bazarov

arnuld said:
I usually write this as

int main (int argc, char* argv[])

That is, argv is an array of pointers to char, or argv is an array of
pointers to NULL-terminated C-strings, where each string is an
argument passed to the program, and argc is the number of elements
in the array. In fact argc is short for "argument count" and argv is
"argument values".

This reduces the problem to a loop over an array and printing
C-strings.

ok, here it is in 2 versions, one with indexing and one with pointers,
both fall under an infinite-loop :(


#include <iostream>

int main( int argc, char *argv[] )
{
std::cout << "These arguments were passed to 'main()'" << std::endl;


/* an int value can be printed easily */ std::cout << argc <<
std::endl;

int i = 0;

while( i < argc )
{
std::cout << argv << "\n";


Are you hoping the compiler will increment 'i' for you?
}

return 0;
}


------- pointer version ------------------- #include <iostream>

int main( int argc, char *argv[] )
{
std::cout << "These arguments were passed to 'main()'" << std::endl;


/* an int value can be printed easily */
std::cout << argc << std::endl;

char *pchar = argv[0];

while( *pchar != '\0' )
{
std::cout << *pchar << "\n";

Even if you increment 'pchar' here (which is needed, of course,
because the compiler cannot figure out what you want it to do
unless you actually tell it), you will just print out all the
characters of the first argument to your program, one character
on each line. All other arguments will be left out.
}

return 0;
}

Here is the solution with pointers:

while (*argv)
std::cout << *argv++ << std::endl;

And if you need to keep the value of 'argv' intact, copy it into
another pointer to pointer to char:

char **pstr = argv;
while (*pstr)
std::cout << *pstr++ << std::endl;

V
 
F

Frank Birbacher

Hi!
it is a vector of library strings but what
"args(argv, argv + argc)" means ?

"args" is the variable name, the one defined here. "args" has type
"vector<string>". The following is a call to a constructor of the
vector. This is used to directly initialize the vector. The constructor
takes two arguments "argv" and "argv+argc".

A vector has a constructor that takes two iterators. I think this is
called range constructor. This means the two iterators delimit a range
of value which then get copied into the vector.

Two things kick in here:
1. "argv" may be of "array type" (that is "char* argv[]"). But arrays
can implicitly without notice be interpreted as/converted to pointers.
As such "argv" is a pointer to the first element in the array. And
therefore "argv+argc" is a pointer one behind the last element. This is
called "past-the-end"-pointer.

2. Iterators are a generic concept modelled after pointers, because
pointers are useful somehow. This is why every pointer is a valid
iterator. There are different iterator models, but a pointer fits the
most refined iterator model: a random access iterator. Well, a pointer
is an iterator.

So now the vector gets two pointers (according to 1) and treats them as
iterators (according to 2). It now has a "list" of "strings" (char*)
which it shall copy into itself.

Now the std::string comes into play. It accepts a "char*" to construct a
std::string. So the vector is repeatedly calling this sting constructor
to copy all "char*" into respective "std::string"s.

Voila, you end up with all program arguments copied into a vector
(array) of strings (std::string). This can now be used for comfortable
handling.
BTW, the things you have talked about in this post give me a feeling like
i got when i looked through some pages of K&R2 .


:) Is it that bad?!

Frank
 
V

Victor Bazarov

arnuld said:
i meant, arrays of strinig literals and array sof string literals are
themselves arrays of char terminated with NULL. so it is an array of
arrays of char.

That's incorrect.
that is what *exactly* i meant and understand about "argv".

It's an array of pointers. That's how it's declared. That's how you
should treat it.

Where the arrays are located does not matter. What matters is what
you get to work with. You have an array of pointers.

Here is a brief illustration of the difference:

char array_of_arrays[][5] = { "abc", "def", "ghi" };
char *array_of_pointers[] = { array_of_arrays[0],
array_of_arrays[1],
array_of_arrays[2] };
[..]
BTW, the things you have talked about in this post give me a feeling
like i got when i looked through some pages of K&R2 .

If you need to understand pointers, go a few paragraphs/pages/chapters
back in the book you're using and start over. Pay attention this time.

V
 
J

Jerry Coffin

[ ... ]
And if you need to keep the value of 'argv' intact, copy it into
another pointer to pointer to char:

char **pstr = argv;
while (*pstr)
std::cout << *pstr++ << std::endl;

....or don't modify it to start with:

std::copy(argv, argv+argc,
std::eek:stream_iterator<char *>(std::cout, "\n"));
 
A

arnuld

...or don't modify it to start with:

std::copy(argv, argv+argc,
std::eek:stream_iterator<char *>(std::cout, "\n"));

does not work:

#include <iostream>
#include <numeric>

int main( int argc, char *argv[] )
{
std::cout << "These arguments were passed to 'main()'"
<< std::endl;


/* an int value can be printed easily */
std::cout << argc << std::endl;

char **pchar = argv;

while( *pchar++ )
{
std::copy( argv, argv + argc,
std::eek:stream_iterator<char*>(std::cout, "\n") );
}

return 0;
}

/* OUTPUT
~/programming/cpp $ ./a.out 1 ok
These arguments were passed to 'main()' 3
/home/arnuld/programming/cpp/a.out
1
ok
/home/arnuld/programming/cpp/a.out
1
ok
/home/arnuld/programming/cpp/a.out
1
ok
~/programming/cpp $

*/
 
R

red floyd

arnuld said:
...or don't modify it to start with:

std::copy(argv, argv+argc,
std::eek:stream_iterator<char *>(std::cout, "\n"));

does not work:

#include <iostream>
#include <numeric>

int main( int argc, char *argv[] )
{
std::cout << "These arguments were passed to 'main()'"
<< std::endl;


/* an int value can be printed easily */
std::cout << argc << std::endl;

char **pchar = argv;

while( *pchar++ )
{
std::copy( argv, argv + argc,
std::eek:stream_iterator<char*>(std::cout, "\n") );
}

return 0;
}

Delete the loop.

#include <iostream>
#include <ostream>
#include <iterator>
#include <algorithm>

int main(int argc, char *argv[])
{
std::cout << argc << std::endl;
std::copy(argv, argv + argc,
std::eek:stream_iterator<char*>(std::cout, "\n"));
return 0;
}
 
A

arnuld

Delete the loop.

#include <iostream>
#include <ostream>
#include <iterator>
#include <algorithm>

int main(int argc, char *argv[])
{
std::cout << argc << std::endl;
std::copy(argv, argv + argc,
std::eek:stream_iterator<char*>(std::cout, "\n"));
return 0;
}

#include <iostream>
#include <ostream>
#include <iterator>
#include <algorithm>

int main( int argc, char *argv[] )
{
std::cout << "These arguments were passed to 'main()'" << std::endl;

std::cout << argc << std::endl;
std::copy( argv, argv + argc,
std::eek:stream_iterator<char*>(std::cout,"\n") );

return 0;
}

==== OUTPUT ========
/home/arnuld/programming/cpp $ g++ -ansi -pedantic -Wall -Wextra
ex_07-16.cpp /home/arnuld/programming/cpp $ ./a.out 1 2 These arguments
were passed to 'main()' 3
/home/arnuld/programming/cpp/a.out
1
2
/home/arnuld/programming/cpp $ ./a.out 1 ok These arguments were passed to
'main()' 3
/home/arnuld/programming/cpp/a.out
1
ok
/home/arnuld/programming/cpp $


#1) why is that number 3 in output ?

#2) ostream header is for std::eek:stream_iterator, algorithm header is for
std:copy algorithm. what exactly is iterator header for ?

#3) why the programme runs fine with only these 2 headers: iostream and
numeric (if it runs fine without all other header of #2, then hy we need
them) ?
 
B

BobR

arnuld said:
#include <iostream>
#include <ostream>
#include <iterator>
#include <algorithm>

int main( int argc, char *argv[] ){
std::cout << "These arguments were passed to 'main()'" << std::endl;

std::cout << argc << std::endl;
std::copy( argv, argv + argc,
std::eek:stream_iterator<char*>(std::cout,"\n") );

return 0;
}

==== OUTPUT ========
/home/arnuld/programming/cpp $ g++ -ansi -pedantic -Wall -Wextra
ex_07-16.cpp /home/arnuld/programming/cpp $ ./a.out 1 2 These arguments
were passed to 'main()' 3
/home/arnuld/programming/cpp/a.out
1
2
/home/arnuld/programming/cpp $ ./a.out 1 ok These arguments were passed to
'main()' 3
/home/arnuld/programming/cpp/a.out
1
ok
/home/arnuld/programming/cpp $


#1) why is that number 3 in output ?

The program name (and sometimes path) is usually passed to the program as
argv[0].

[0] /home/arnuld/programming/cpp/a.out
[1] 1
[2] ok

That makes 3 arguments.
#2) ostream header is for std::eek:stream_iterator, algorithm header is for
std:copy algorithm. what exactly is iterator header for ?

<iostream> is not required (at this time) to include <ostream>. GCC does
include it, but, it's good practice to specifically include any headers
needed by your code. It was included for 'std::endl'.
<iterator> for 'std::eek:stream_iterator'.
#3) why the programme runs fine with only these 2 headers: iostream and
numeric (if it runs fine without all other header of #2, then hy we need
them) ?

Some headers pull in other headers. To be portable, don't depend on it.
 

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

Similar Threads

Print with command-line arguments 0
Command Line Arguments 0
C++ Primer ex 7.5 18
C++ Primer ex 8.3 21
C++ Primer ex 7.12 2
C++ Primer ex 5.18 5
C++ Primer ex 4.30 10
C++ Primer ex 4.16 2

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top