Arguments Exercise

From COMP15212 Wiki
Revision as of 10:22, 9 August 2019 by gravatar W81054ch [userbureaucratinterface-adminsysopPHRhYmxlIGNsYXNzPSJ0d3BvcHVwIj48dHI+PHRkIGNsYXNzPSJ0d3BvcHVwLWVudHJ5dGl0bGUiPkdyb3Vwczo8L3RkPjx0ZD51c2VyPGJyIC8+YnVyZWF1Y3JhdDxiciAvPmludGVyZmFjZS1hZG1pbjxiciAvPnN5c29wPGJyIC8+PC90ZD48L3RyPjwvdGFibGU+] (talk | contribs) (1 revision imported)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
On path: Exercises 0: Exercises • 1: Pointer Exercise • 2: Arguments Exercise • 3: Malloc Exercise • 4: Structs Exercise • 5: Processes Exercise • 6: Shared memory Exercise • 7: Pipes Exercise • 8: Exceptions Exercise • 9: Synchronisation Exercise • 10: Files Exercise • 11: Threads Exercise • 12: Unix proc Exercise
Depends on Pointers

Download exercise files

The purposes of this exercise are:

  • to illustrate how arguments are passed into processes in Unix
  • to reinforce understanding of pointers and arrays (and strings)

Be happy with basic addressing principles and syntax first.

When C code is started, we inherit two values from the environment.

int main(int argc, char *argv[]) { ... }
  • int argc — Argument count
  • char *argv[] — Argument contents

These are passed from the shell and they allow the user to give arguments to the program. The command line is divided into argument strings by the shell, and are passed to the program in the form of C strings.

argc is easy to explain: it is the number of words (i.e. textual words … strings) in the invocation line.

Try a statement like:

printf("Number of arguments: %d\n", argc);

…and invoke as

  • ./arguments” — Number of arguments: 1
  • ./arguments snap crackle pop!” — Number of arguments: 4

argv is harder to explain and, again, benefits from a figure.

Initial arguments

*argv[] is fairly confusing! It is an array of char * (pointers to characters). Arrays are (inherently) specified by a pointer (to the zero-th element) so argv will occupy as many bytes as a pointer uses on your machine (e.g. 4 on a 32-bit machine, 8 on a 64-bit machine; try it with sizeof(argv)). The size of the array is, of course, argc.

Each element of the array is really a string but a string is itself an array of indefinite size (hence the saying “How long is a piece of string?”!) so the elements of the array are all pointers themselves.

Strings are made of chars – another C basic data type. They comprise contiguous bytes (chars) at increasing addresses until a zero character ('\0') string terminator is encountered.

If you want to print a string using printf() you can do it like this:

printf("First argument string is: %s\n", argv[0]);

Where the second printf() argument (i.e. argv[0]) is substituted for the %s. You can print other arguments too, if they are there; however if you go beyond argc in the array the pointers will be undefined and you are likely to crash.

A string is, itself, an array of chars (bytes); its size is not specified directly, instead the convention is that adjacent addresses are used until the contents of a char is found to be 0x00. There is an alternative way of expressing this in value C, as '\0', and this is clearer in this context.

Refer to the figure - perhaps before drawing one of your own?

All this can be decoded by the application (such as gcc) to find out what you wanted it to do. You can do it in your own applications.

You have the tools you need to refine your picture of what is happening here and are encouraged to experiment. In the course of experimenting you will probably make some mistakes and some will result in run time problems such as “Segmentation fault”! For now just regard that as a hint that something went wrong; there will be more on this, later.

Because we’re really kind, there’s a template (arguments.c) to get you started.

Puzzle

What expression could be used to calculate the number of bytes needed for the argv[] array?

Answer

argc * sizeof(argv);

  • argv is an array, but an “array” in C is a pointer (to an area of memory reserved elsewhere).
  • sizeof(argv) therefore returns the number of bytes used for a pointer in the running system.
  • The strings are also defined by pointers and all pointers will be the same length.
  • argc

If you are a ‘purist’ you could measure the length of a pointer-to-a-string instead, and multiply that. This is not the length of the string(s) (argument(s)) which will be passed – you cannot know those yet and they will probably be different anyway – it is the size of a pointer, still. You may end up with something like this:

argc * sizeof(&"any string");

  • the & gets a reference (pointer) to the string. This is arguably a more ‘correct’ way to do it; it’s all a bit ugly!