Dear Brian,
Let me try (-> Im a beginner at C++ too, so don't be angry if I make a mistake somewhere ) to explain you this. I am also building a little app that takes strings from the command line, so I thought it would be interesting answering your question.
First of all, I will not run the code you posted like this, because it is dodgy as f*ck. The loop is infinite, and you read in the memory with invalid pointers.
The way the command line arguments work is as follows:
The array argv is an array of "pointers to char". In your case this means you have 5 pointers to char stored from argv[0] to argv[4]. Since argc is the number of your arguments including your program name, argv[argc] or argv[5], is the next element after your pointers, and it is set to 0. This means that if you accidentally read beyond the scope of your array, you will get a null pointer instead of some random value, which is better, since trying to read on address 0x00000000 will trow an error instead of provide you with random data.
If you then want to iterate your strings you could use the following statement:
Code:
int i = 0;
while( argv[i] != 0 )
{
cout << argv[i++] << endl;
}
Note the use of 0 instead of '\0'. Pointers are integers (the mathematical term, integer, not the data type). Further, the integer 0 has a special meaning in C++ so it can be assigned to almost every type. '\0' is a character literal. Types are pretty strict in C++ and comparing a pointer with '\0', it will never stick.
Each of our "pointers to char" now actually point not to a char, but to an array of characters. You could loop through the name of your program by using this loop to loop through the array:
Code:
int i = 0;
while( argv[0][i] != '\0' )
{
cout << argv[0][i++];
}
This time we can check for our character literal '\0' (-> note that is is not the same as "\0" which would be a string literal). Well C++ sure is complicated...
Of course you can nest two loops to combine the two examples above:
Code:
#include <iostream>
#include <cstdlib> // for std::system
using namespace std;
int main(int argc, char* argv[])
{
cout << endl;
int i = 0;
int j = 0;
while( argv[i] != 0 )
{
cout << "Argument " << i << " equals: ";
j = 0;
while( argv[i][j] != '\0' )
{
cout << argv[i][j++];
}
++i;
cout << endl;
}
system( "cmd.exe /K" ); //This will keep the command prompt open, so you can read the output
return 0;
}
Of course easiest would be to just let std::cout handle the pointers, then you only need the first loop.
Lets further have a look at this line you wrote:
Code:
cout << (i+1) << ": " << *argv[i] << " and string: " << argv[i++] << endl;
It's very dodgy as well. First of all, if I'm not mistaken, operator << works from right to left. This means that your i++ near the right already happened before the other outputs, so *argv[i] will never use i=0.
Further, char* are not only pointers to char. They are also C-style strings. They often behave differently than other pointers. If you send a pointer to a function asking for one, normally that function will use the object or type pointed to and read it's value. In the case of char*, functions accepting this type will keep reading the memory until they find a '\0'. Namely they assume that you are not pointing to just one character, but to a string. Therefor, you don't have to dereference it, otherwise you just get the first character of your string. If you send it to the operator (basic_ostream::operator<<) as a pointer, it will treat it as a string, and output it entirely.
Also this line doesn't work as expected:
Code:
cout << "sizeof char* argv[]= " << (sizeof argv) << endl;
argv is a pointer to the first "pointer to char" on our array, so on a x32 system this is 4 bytes, and on a x64 system this will be 8 bytes...
If you would like to calculate the size of a C-style string, you could use the following function, as indicated in Horton's book at page 168:
Code:
#include <cstring>
size_t strlen( const char *str );
where the type size_t is referring to the maximum size a pointer can point to. In reality you can interpret the result of this function like an int, which holds the number of characters (well actually bytes) in you string, without the '\0'. Normally bytes and characters will be the same, unless you use unicode or other wide character sets. Then all that rests us is to sum the sizes of our strings, and we know how much place in total our command line takes... For a change with a for loop:
Code:
#include <iostream>
#include <cstring>
#include <cstdlib> // for std::system
using namespace std;
int main(int argc, char* argv[])
{
int count = 4*argc; //The size taken up by the pointers to char...
for( int i=0; i < argc; ++i )
{
count += strlen( argv[i] ) + 1; //+1 for our '\0' ending
}
cout << "the size of all our strings is: " << count << " KB" << endl;
system( "cmd.exe /K" ); //This will keep the command prompt open, so you can read the output
return 0;
}
So, I hope this gets you going... It was an interesting day for me answering your question. I hope you learn as much from it...
Greetz
ufo