0

I am fairly new to C/C++ and I am learning command line arguments. I am trying to sort my command line arguments using strcpy, however it is giving me bad output. e.g.


i/p : i am


o/p : ami i

Can anyone help me on what am I doing wrong here ? Please note: I am only running this program for only argc=3 and I am only running this code for the inputs (which will be sorted) as listed in the example above. I have just removed the loops for debugging.

#include "iostream"
#include "cstdlib"
#include "cstring"
using namespace std;

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

    char temp[100];

    //sorting my command line arguments
    if(strcmp(argv[1],argv[2])>0)
    {
        strcpy(temp,argv[1]);
        strcpy(argv[1],argv[2]);
        strcpy(argv[2],temp);
    }

    cout<<argv[1]<<endl;
    cout<<argv[2]<<endl;

    return 0;
}
Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
siddyi
  • 23
  • 1
  • 7
  • The sizes of the commandline arguments do not change automatically so you can't copy them around like that (unless they all happen to be the same length). – Galik Sep 14 '17 at 02:55
  • @CroCo I am first comparing the Strings and on the basis of that I am swapping/sorting. – siddyi Sep 14 '17 at 02:57
  • @Galik then how can I sort the arguments of variable lengths? – siddyi Sep 14 '17 at 02:58
  • "fairly new to C/C++". You might start by picking one of the two. In C++, this is trivial. `std::vector args(argc, argc+argv); if (args[1] – MSalters Sep 14 '17 at 09:00

1 Answers1

1

Consider your memory layout. When you run $ ./a.out i am, it will look something like this when the program starts:

a   .   o  u  t  \0 i  \0 a  m  \0
^                   ^     ^
argv[0]          argv[1]  argv[2]

The write to argv[1] in your swapping procedure will change it to this:

a   .   o  u  t  \0 a  m  \0 m  \0
^                   ^     ^
argv[0]          argv[1]  argv[2]

Then the write to argv[2] will change it again to this:

a   .   o  u  t  \0 a  m  i  \0 \0
^                   ^     ^
argv[0]          argv[1]  argv[2]

So when you print out argv[1], it will read until the null byte, giving you ami. argv[2] will read from a different starting point, giving you i.

As Galik points out, this is because argv[1] and argv[2] aren't some sort of auto-resizing buffers. They're just pointers into memory. I should note at this point that the exact layout is not formally defined by the language; you could get all sorts of different unpredictable behaviour depending on the platform that you're using.

To fix this issue, you should create an array of pointers to the strings that you're sorting and swap the pointers rather than the strings' values. That will both be faster (requiring fewer bytes to be copied) and safer (fewer ways to accidentally overflow buffers, as will happen in your current code if one of your inputs is longer than 100 characters).

user3553031
  • 5,990
  • 1
  • 20
  • 40
  • Thanks, this definitely cleared things up. Edit: Don't understand why this answer was downvoted. I have accepted your answer btw. – siddyi Sep 14 '17 at 03:11