Wrox Programmer Forums

Need to download code?

View our list of code downloads.

Go Back   Wrox Programmer Forums > C# and C > C++ and Visual C++ > BOOK: Ivor Horton's Beginning Visual C++ 2005
Password Reminder
Register
Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read
BOOK: Ivor Horton's Beginning Visual C++ 2005
This is the forum to discuss the Wrox book Ivor Horton's Beginning Visual C++ 2005 by Ivor Horton; ISBN: 9780764571978
Welcome to the p2p.wrox.com Forums.

You are currently viewing the BOOK: Ivor Horton's Beginning Visual C++ 2005 section of the Wrox Programmer to Programmer discussions. This is a community of tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developersí questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
Reply
 
Thread Tools Display Modes
  #1 (permalink)  
Old February 27th, 2007, 12:44 PM
Authorized User
 
Join Date: Dec 2006
Location: , , .
Posts: 34
Thanks: 0
Thanked 0 Times in 0 Posts
Default char* argv in main() - counting and termination

Should command line arguments have a null termination at the end?

Ivor Horton's Beginning C++ says they will, but my test of the code in his book shows that the null is not there.

Interestingly, in viewing the hex editor while debugging, I see that there is a "0" between each char array. For example, if my command line is such:

"c:\myProgram.exe help me debug this"

then the char* array arguments, (char* argv[]) shows like this in the hex editor:
c:\myProgram.exe0help0me0debug0this0

But none of these zeros are detectable in my loop, which looks for the 0 value to end looping. I can't use "while(argv[i] != '\0')" to test for the 0 at the end.

corn-fused in Indiana,
Brian

code here:
Code:
#include <iostream>
using std::cout;
using std::endl;
int main(int argc, char* argv[])
{
  cout << endl;
  int i = 0;
  while(argv[i] != '\0')
    cout << (i+1) << ": " << *argv[i] << " and string: " << argv[i++] << endl;
  cout << "argc = " << argc << endl;
  cout << "sizeof char* argv[]= " << (sizeof argv) << endl;
  return 0;
}

Sincerely,
Brian
__________________
Sincerely,
Brian
Reply With Quote
  #2 (permalink)  
Old March 14th, 2007, 04:33 PM
ufo ufo is offline
Authorized User
 
Join Date: Apr 2006
Location: , , .
Posts: 24
Thanks: 0
Thanked 0 Times in 0 Posts
Default

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
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
Using ARGV in Perl Freedolen Perl 18 October 18th, 2012 06:36 PM
zombie to exist after termination of main prog. anilchowdhury Need help with your homework? 0 February 22nd, 2008 01:56 PM
Big challenge here! How to convert char* to char^? samiswt Visual C++ 2005 1 November 30th, 2007 08:09 PM
char* argv to main - counting and termination proslambano C++ Programming 1 March 4th, 2007 12:22 AM
Invalid conversion from 'char*' to 'char' deuxmio C++ Programming 3 December 8th, 2006 06:56 AM



All times are GMT -4. The time now is 01:11 PM.


Powered by vBulletin® Version 3.7.0
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.