Trouble understanding command line arguments.

Question!

I have recently started learning c# and was reading about the filesystemwatcher class when I got confused by the command line arguments.

From here: https://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2

I copied the c# and I was confused when I read over the code, as it said if the arguments were not equal to 2 do not continue basically. I thought that there would only be on argument, the directory path? When I printed out args[0] and args[1] it printed watcher.exe and the directory, however I thought that the directory was an argument of the watcher.exe and not that watcher.exe was an argument itself? When I looked at this example ( https://msdn.microsoft.com/en-gb/library/aa288457(v=vs.71).aspx ) it does not show the cmdline2 being printed when the arguments are printed, would be great if someone knows why.

Also as a side question, I did try to writeline args[2] which crashed the application of course. I thought I would test of the debugger in VS 2015, but I could not find out how to debug my code when I needed to pass parameters to the application? All I see is a start button with no options for parameters.

By : Goldn123


Answers

The reason why this is happening is because the args[] array of arguments is structured in a peculiar way, due to reasons that have to do with nothing but tradition. (A tradition which started with the main() function in Unix C, I believe.) Everyone is familiar with it, so everyone thinks of it as normal, but if you are seeing this for the first time, it is understandable that you are confused.

Here is the format of args[]:

args[0] = the pathname of the executable file from which the current process started.
args[1] = the first argument passed to the program.
args[2] = the second argument passed to the program.
and so on.

So, the length of args will always be greater than or equal to 1, because there will always be an executable file from which the current process started.

Then of course it becomes tricky, because if you want to make sure that your program was passed 1 and only 1 argument, you have to do if( args.Length == 2 ). That's the source of your confusion.

Unfortunately, people consider this kind of thing so "normal" that they don't even bother documenting the sorcery that is going on.

Amendment

To make matters worse, Microsoft is trying to "correct" this unfortunate situation with C#, but they are not being consistent:

In "Main() and Command-Line Arguments (C# Programming Guide)" (https://msdn.microsoft.com/en-us/library/acy3edy3.aspx) they say:

Unlike C and C++, the name of the program is not treated as the first command-line argument.

But then in the documentation of System.Environment.GetCommandLineArgs(), (https://msdn.microsoft.com/en-us/library/system.environment.getcommandlineargs(v=vs.110).aspx) they say:

The first element is the executable file name, and the following zero or more elements contain the remaining command-line arguments.

(Keep in mind that when we say "the first element" we mean the element at index zero.)

So, the argument at index zero may and may not be the executable; it depends on whether the array of arguments that you have in your hands is the one that was passed to your Main() function, or whether you obtained it by invoking System.Environment.GetCommandLineArgs().

Nice? I know, tell me about it.



You're first argument is the path to the executable. -> c://.../watcher.exe. The second is the directory to watch.

It's crashing when you print args[2] because there isn't a 3rd argument. If you wanted to add one in VS2015, you would click on the solution->properties->debug. You can set the command line arguments here under "Command line arguments." You should also be able to debug just by clicking on a line and adding breakpoints.

By : Ryan


I would do a little pre-processing before drawing the numbers to get a list of possible ranges. So let's assume we have a Range structure like so:

/// <summary> A possible range of values. </summary>
public struct Range
{
    /// <summary> Min value, inclusive. </summary>
    public readonly double Min;
    /// <summary> Max value, inclusive. </summary>
    public readonly double Max;
    public Range(double min, double max) { Min = min; Max = max; }
    /// <summary> Range length, distance between Min and Max. </summary>
    public double Length { get { return Max - Min; } }
}

And another structure RangeList which holds several ranges together. Range list also contains a cumulative length array of successive length sums of your Ranges, like so:

/// <summary> All possible ranges grouped together. </summary>
public struct RangeList
{
    /// <summary> Possible range. </summary>
    public readonly Range[] Ranges;
    /// <summary> Sum of each range length. </summary>
    public readonly double Length;
    /// <summary> Cumulative lengths values of each ranges. </summary>
    public readonly double[] CumulLengths;
    public RangeList(Range[] ranges)
    {
        Ranges = ranges;
        Length = 0;
        CumulLengths = new double[ranges.Length];
        for (var i = 0; i < ranges.Length; ++i)
        {
            Length += ranges[i].Length;
            CumulLengths[i] = Length;
        }
    }
}

We can then write easily a function that creates a RangeList from a given list of excluded ranges:

    /// <summary> Get possible ranges to draw from, considering exclusions. </summary>
    public static RangeList GetRangeList(Range range, params Range[] exclusions)
    {
        var ranges = new List<Range>();
        ranges.Add(range);
        if (exclusions != null)
        {
            foreach (var exclusion in exclusions)
            { // progressively eat latest range added to the list, cutting exclusions.
                var lastRange = ranges[ranges.Count - 1];
                if (exclusion.Min < lastRange.Max)
                {
                    ranges[ranges.Count - 1] = new Range(lastRange.Min, exclusion.Min);
                    if (exclusion.Max < lastRange.Max)
                    {
                        ranges.Add(new Range(exclusion.Max, lastRange.Max));
                    }
                }
            }
        }
        return new RangeList(ranges.ToArray());
    }

This method relies on several assumptions, including that not all space is excluded, exclusions are not overlapping, and exclusions are given in ascending order. It is then straight-forward to draw a number from the possible ranges:

    /// <summary> Assume exclusions are also given in ranges. </summary>
    public static double RangeWithExclusions(this Random random, Range range, params Range[] exclusions)
    {
        var rangeList = GetRangeList(range, exclusions);
        var rnd = random.NextDouble() * rangeList.Length;
        var rangeIndex = Array.BinarySearch(rangeList.CumulLengths, rnd);
        if (rangeIndex < 0)
        { // 'unlucky', we didn't hit a length exactly
            rangeIndex = ~rangeIndex;
        }
        var previousLength = rangeIndex > 0 ? rangeList.CumulLengths[rangeIndex - 1] : 0;
        var rndRange = rangeList.Ranges[rangeIndex]; // result range of our random draw
        return rndRange.Min + (rnd - previousLength); // scale rnd back into range space
    }

The following NUnit test demonstrate how to use the solution:

[TestFixture]
public class TestRandom
{
    [Test]
    public void Tests()
    {
        var random = new Random();
        double rnd;
        rnd = random.RangeWithExclusions(new Range(0, 1));
        Assert.IsTrue(rnd >= 0 && rnd <= 1);
        rnd = random.RangeWithExclusions(new Range(-100, 1));
        Assert.IsTrue(rnd >= -100 && rnd <= 1);
        rnd = random.RangeWithExclusions(new Range(0, 1), new Range(0.1, 0.9));
        Assert.IsTrue(rnd >= 0 && rnd <= 1 && (rnd <= 0.1 || rnd >= 0.9));
        rnd = random.RangeWithExclusions(new Range(0, 1), new Range(0, 0.9));
        Assert.IsTrue(rnd >= 0 && rnd <= 1 && (rnd >= 0.9));
        rnd = random.RangeWithExclusions(new Range(0, 1), new Range(0.2, 0.4), new Range(0.6, 0.8));
        Assert.IsTrue(rnd >= 0 && rnd <= 1 && (rnd <= 0.2 || rnd >= 0.4) && (rnd <= 0.6 || rnd >= 0.8));
    }
}

Hope this helps

By : pstrato


This video can help you solving your question :)
By: admin