Exercises:Arguments: Difference between revisions
pc>Yuron No edit summary |
W81054ch [PHRhYmxlIGNsYXNzPSJ0d3BvcHVwIj48dHI+PHRkIGNsYXNzPSJ0d3BvcHVwLWVudHJ5dGl0bGUiPkdyb3Vwczo8L3RkPjx0ZD51c2VyPGJyIC8+YnVyZWF1Y3JhdDxiciAvPmludGVyZmFjZS1hZG1pbjxiciAvPnN5c29wPGJyIC8+PC90ZD48L3RyPjwvdGFibGU+] (talk | contribs) m (1 revision imported) |
||
(2 intermediate revisions by 2 users not shown) | |||
Line 12: | Line 12: | ||
---- | ---- | ||
<blockquote> | <blockquote> | ||
Be happy with [[Exercises:C_Addresses|basic addressing principles and | Be happy with [[Exercises:C_Addresses|basic addressing principles and syntax]] first. | ||
syntax]] first. | |||
</blockquote> | </blockquote> | ||
When C code is started, we inherit two values from the environment. | When C code is started, we inherit two values from the environment. | ||
Line 23: | Line 22: | ||
* <code>char *argv[]</code> — Argument contents | * <code>char *argv[]</code> — Argument contents | ||
These are passed from the [ | These are passed from the [[shell]] and they allow the user to give arguments to the program. The command line is divided into | ||
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 <strong>C strings</strong>. | ||
argument strings by the shell, and are passed to the program in the | |||
form of <strong>C strings</strong>. | |||
<code>argc</code> is easy to explain: it is the number of words (i.e. textual | <code>argc</code> is easy to explain: it is the number of words (i.e. textual words … <em>strings</em>) in the invocation line. | ||
words … <em>strings</em>) in the invocation line. | |||
Try a statement like: | Try a statement like: | ||
Line 44: | Line 40: | ||
[[Image:initial_arguments.png|link=|alt=Initial arguments]] | [[Image:initial_arguments.png|link=|alt=Initial arguments]] | ||
<code>*argv[]</code> is fairly confusing! It is an array of <code>char *</code> (pointers | <code>*argv[]</code> is fairly confusing! It is an array of <code>char *</code> (pointers to characters). Arrays are (inherently) specified by a pointer (to the zero-th element) so <code>argv</code> 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 <code>sizeof(argv)</code>). The size of the array is, of | ||
to characters). Arrays are (inherently) specified by a pointer (to | |||
the zero-th element) so <code>argv</code> 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 <code>sizeof(argv)</code>). The size of the array is, of | |||
course, <code>argc</code>. | course, <code>argc</code>. | ||
Each element of the array is really a <em>string</em> but a string is itself | Each element of the array is really a <em>string</em> but a string is itself an array of indefinite size (hence the saying “How long is a piece of string?”!) so the <em>elements</em> of the array are all pointers themselves. | ||
an array of indefinite size (hence the saying “How long is a | |||
piece of string?”!) so the <em>elements</em> of the array are all | |||
pointers themselves. | |||
Strings are made of <code>char</code>s – another C basic data type. They | Strings are made of <code>char</code>s – another C basic data type. They comprise contiguous bytes (<code>char</code>s) at increasing addresses until a zero character (<code>'\0'</code>) string terminator is encountered. | ||
comprise contiguous bytes (<code>char</code>s) at increasing addresses until a | |||
zero character (<code>'\0'</code>) string terminator is encountered. | |||
If you want to print a string using <code>printf()</code> you can do it like this: | If you want to print a string using <code>printf()</code> you can do it like this: | ||
Line 65: | Line 52: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Where the second <code>printf()</code> argument (i.e. <code>argv[0]</code>) is substituted | Where the second <code>printf()</code> argument (i.e. <code>argv[0]</code>) is substituted for the <code>%s</code>. You can print other arguments too, if they are there; however if you go beyond <code>argc</code> in the array the pointers will be undefined and you are likely to crash. | ||
for the <code>%s</code>. You can print other arguments too, if they are there; | |||
however if you go beyond <code>argc</code> in the array the pointers will be | |||
undefined and you are likely to crash. | |||
A string is, itself, an array of <code>char</code>s (bytes); its size is not | A string is, itself, an array of <code>char</code>s (bytes); its size is not specified directly, instead the convention is that adjacent addresses are used until the contents of a <code>char</code> is found to be <code>0x00</code>. There is an alternative way of expressing this in value C, as <code>'\0'</code>, and this is clearer in this context. | ||
specified directly, instead the convention is that adjacent addresses | |||
are used until the contents of a <code>char</code> is found to be <code>0x00</code>. There | |||
is an alternative way of expressing this in value C, as <code>'\0'</code>, and | |||
this is clearer in this context. | |||
Refer to the figure - perhaps before drawing one of your own? | Refer to the figure - perhaps before drawing one of your own? | ||
All this can be decoded by the application (such as <code>gcc</code>) to find out | All this can be decoded by the application (such as <code>gcc</code>) to find out what you wanted it to do. You can do it in your own applications. | ||
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 | You have the tools you need to refine your picture of what is happening here and are <strong>encouraged to experiment</strong>. 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. | ||
happening here and are <strong>encouraged to experiment</strong>. 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 (<code>arguments.c</code>) to get you | Because we’re really kind, there’s a template (<code>arguments.c</code>) to get you | ||
Line 92: | Line 66: | ||
=== Puzzle === | === Puzzle === | ||
What expression could be used to calculate the number of bytes needed | What expression could be used to calculate the number of bytes needed for the <code>argv[]</code> array? | ||
for the <code>argv[]</code> array? | |||
<div class="toccolours mw-collapsible mw-collapsed"> | <div class="toccolours mw-collapsible mw-collapsed"> | ||
Line 106: | Line 79: | ||
<code>argc * sizeof(&"any string");</code> | <code>argc * sizeof(&"any string");</code> | ||
*the & gets a reference (pointer) to the 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! | ||
This is arguably a more ‘correct’ way to do it; it’s all a bit ugly! | |||
</div></div> | </div></div> | ||
---- | ---- | ||
{{PageGraph}} | {{PageGraph}} |
Latest revision as of 10:22, 9 August 2019
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 |
---|
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 countchar *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.
*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 char
s – another C basic data type. They comprise contiguous bytes (char
s) 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 char
s (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?
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!