"Real Programmers always confuse Christmas and Halloween because OCT 31 == DEC 25" -- Andrew Rutherford
orvoid main(void);
However, main is sort of overloaded to take parameters as well:int main(void);
As we've seen with arrays as parameters, the declarations above are equivalent.int main(int argc, char *argv[]); int main(int argc, char **argv);
int main(int argc, char **argv); int main(int foo, char **bar); int main(int fred, char **barney); int main(int argv, char **argc); // You're just asking for trouble here!
void main(int argc, char *argv[])
{
int i;
for (i = 0; i < argc; i++)
printf("arg%i = %s\n", i, argv[i]);
}
If our program was named foo.exe and we were to invoke the program like this:
we would see something like this printed out:foo one two three 911
Another example:foo one two three 911
foo one "two three" four 911
Within Visual Studio we see:foo one two three four 911
because the IDE invokes the program using the entire path.E:\Data\Courses\Summer2004\CS220\Code\Chapter16\RTL\Debug\foo.exe one two three four 911
A more compact way of printing the arguments using pointers instead of subscripts:
void main(int argc, char **argv)
{
while (*argv)
printf("%s\n", *argv++);
}
Diagram of the arguments when invoked as:
foo one "two three" four 911
Note: Because argv is an array of pointers to characters (strings), you can only pass strings to a program. If you want to use the parameter as a number, you will have to convert it from a string to a number yourself. See the Data Conversion section in the C Runtime Library.![]()
include <stdio.h> /* printf */
include <stdlib.h> /* atoi */
include "uucode.h"
int main(int argc, char **argv)
{
int mode;
/* If less than 1 argument is provided, remind the user */
/* how to use the program. */
if (argc < 3)
{
printf("\n");
printf(" Usage: uucode {mode} {inputfile} [decode_path]\n\n");
printf(" mode = 1 for encoding, 2 for decoding\n");
printf(" inputfile = file to encode/decode\n");
printf(" decode_path = filename to store in encoded file (only for encoding)\n\n");
printf(" Examples: uucode preamble.txt mypreamble.txt > preamble.uue\n");
printf(" uucode preamble.uue\n\n");
return -1;
}
/* First argument is the mode, 1=encode, 2=decode */
mode = atoi(argv[1]);
/* Encode */
if (mode == 1)
{
/* If only 2 args, the input/remote filename are the same */
if (argc == 3)
{
if (uuencode(argv[2], argv[2]))
printf("Encoding failed: %s, %s\n", argv[2], argv[2]);
}
/* The input filename and remote filename are different */
else
{
if (uuencode(argv[2], argv[3]))
printf("Encoding failed: %s, %s\n", argv[2], argv[3]);
}
}
/* Decode */
else if (mode == 2)
{
if (uudecode(argv[2]))
printf("Decoding failed: %s\n", argv[2]);
}
else
{
printf("Bad mode: %i Should be 1 or 2.\n", mode);
}
return 0;
}
where env is similar to argv in that it is a pointer to a pointer to a char. These pointers point to the strings in the environment.int main(int argc, char **argv, char **env);
void main(int argc, char **argv, char **env)
{
while (*env)
printf("%s\n", *env++);
}
The output from the above program running on my computer looks like this. Notice
that this program produces the same results as the SET command typed at the console:
We can experiment with this in C:C:\> set type 'set' and press return
const char *GetEnvironmentSetting(const char **env, const char *key)
{
int len = strlen(key);
while (*env)
{
if (!strncmp(key, *env, len))
return *env + len + 1;
env++;
}
return NULL;
}
void main(int argc, char **argv, char **env)
{
const char *value = GetEnvironmentSetting(env, "MyTemp");
if (value)
printf("MyTemp is %s.\n", value);
else
printf("MyTemp is not set.\n");
}
The environment is a very powerful and easy way to seamlessly configure software. You should try exploiting
this concept.
Final notes on main. Not all implementations will support the environment pointer:
ANSI C:
Traditionally accepted implementations:int main(void); int main(int argc, char **argv);
Finally, there is a getenv function (stdlib.h) that you can call anywhere in your program that will return the value a specific environment string:int main(void); int main(int argc, char **argv); int main(int argc, char **argv, char **env); extern char *environ[]; // External global variable
This is almost identical to the GetEnvironmentSetting function implemented above and can be used without the parameter to main:char *getenv(char const *string);
void main(void)
{
value = getenv("MyTemp");
if (value)
printf("MyTemp is %s.\n", value);
else
printf("MyTemp is not set.\n");
}
This example simply returns from main, which causes the program to terminate:int atexit( void ( *func )( void ) );
void MyExit(void)
{
printf("In MyExit function...\n");
}
void main(void)
{
atexit(MyExit);
printf("In main...\n");
}
Output:
This code actually calls exit to terminate the program prematurely (but safely):In main... In MyExit function...
void MyExit(void)
{
printf("In MyExit function...\n");
}
void SomeFn(void)
{
printf("In SomeFn calling exit...\n");
exit(0);
}
void main(void)
{
atexit(MyExit);
printf("In main...\n");
SomeFn();
}
Output:
This program sets up several exit functions:In main... In SomeFn calling exit... In MyExit function...
void MyExit1(void)
{
printf("In MyExit1 function...\n");
}
void MyExit2(void)
{
printf("In MyExit2 function...\n");
}
void MyExit3(void)
{
printf("In MyExit3 function...\n");
}
void SomeFn(void)
{
printf("In SomeFn calling exit...\n");
exit(0);
}
void main(void)
{
atexit(MyExit1);
atexit(MyExit2);
atexit(MyExit3);
printf("In main...\n");
}
And we can see that they are called in the reverse order in which they were assigned:
Output:
In main... In MyExit3 function... In MyExit2 function... In MyExit1 function...
Using it in a program like this:int system( const char *command );
void main(void)
{
system("notepad");
}
will cause the Windows Notepad application to run. You can also pass command line arguments to other
programs as well. The example below calls the Microsoft C/C++ compiler and passes a filename to it
to compile:
void main(void)
{
system("cl E:\\Projects\\Game1\\main.c");
}
A simple program to execute almost any command from C:
void main(void)
{
char buffer[100];
printf("What command do you want to execute?\n");
fgets(buffer, 100, stdin);
system(buffer);
printf("This line will be printed after the system call above terminates.\n");
}
Example run (program is rtl.exe):
E:\Data\Courses\Summer2002\CS220\Code\Chapter16\RTL\Debug>rtl
What command do you want to execute?
dir d:\ e:\
Volume in drive D is Applications
Volume Serial Number is 1084-18F9
Directory of d:\
04/10/2002 07:03a <DIR> borlandc
05/24/2002 11:22a <DIR> CygWin
12/06/2001 06:08p <DIR> Data
12/10/2001 05:56p 126,875 dirinfo.mcd
12/07/2001 03:37p <DIR> JBuilder4
07/19/2002 12:41p <DIR> Program Files
07/05/2002 10:25a <DIR> stuff
1 File(s) 126,875 bytes
6 Dir(s) 604,979,200 bytes free
Volume in drive E is Data
Volume Serial Number is DCA8-DC74
Directory of e:\
05/10/2002 01:59p <DIR> CVSRoot
07/19/2002 07:54a <DIR> Data
01/15/2002 09:49a 16,663 dirinfo.mcd
12/07/2001 12:36p <DIR> Documents and Settings
07/22/2002 10:06a <DIR> Download
02/05/2002 10:46a 29,607 Export_HKEY_CURRENT_USER_Software_Microsoft_DevStudio.reg
12/06/2001 02:51p <DIR> i386
07/15/2002 08:59a <DIR> images
02/01/2002 09:06a <DIR> Installs
12/07/2001 12:29p <DIR> Program Files
05/23/2002 12:44p 0 s1cc
05/23/2002 12:44p 0 s1cc.1
05/23/2002 12:44p 0 s1cc.2
05/23/2002 12:44p 0 s1cc.3
05/23/2002 12:44p 0 s1cc.4
02/01/2002 11:58a <DIR> Share
02/05/2002 10:39a <DIR> sp5
07/05/2002 04:10p <DIR> stuff
07/17/2002 06:59a <DIR> temp
03/01/2002 05:02p 25,761 TempMon1.gif
04/23/2002 08:43a <DIR> WebReaper
12/07/2001 12:39p <DIR> WINNTX
8 File(s) 72,031 bytes
14 Dir(s) 4,069,343,232 bytes free
This line will be printed after the system call above terminates.
_execl _execle _execlp _execlpe
_execv _execve _execvp _execvpe
Passing a (variable-length) list to exec:
void main(void)
{
int retval;
// Using a list only (must specify path)
retval = _execl("c:\\winnt\\system32\\notepad", "c:\\winnt\\system32\\notepad", "c:\\somefile.txt", NULL);
// We only reach this if the call to _execl fails
printf("Exec failed. retval = %i, errno = %i\n", retval, errno);
perror("Message");
}
If we want to have the system find the command in the environment (the PATH variable), we can use this:
// Using a list and getting path from the environment
retval = _execlp("notepad", "notepad", "c:\\somefile.txt", NULL);
Passing a vector to exec:
void main(void)
{
const char *args[] = {"c:\\winnt\\system32\\notepad", "c:\\somefile.txt", NULL};
int retval;
// Using a vector only (must specify path)
retval = _execv("c:\\winnt\\system32\\notepad", args);
// We only reach this if the call to _execv fails
printf("Exec failed. retval = %i, errno = %i\n", retval, errno);
perror("Message");
}
If we want to have the system find the command in the environment (the PATH variable), we can use this:
// Using a vector and getting path from the environment
retval = _execvp("notepad", args);
It may seem redundant to specify the name of the program twice. The first occurrence is the program that the OS
is going to run. The second occurrence will be placed into argv[0] for the program to be run. Common sense might indicate that
they should be the same, but it isn't enforced.
const char *args[] = {"notepad", "c:\\somefile.txt", NULL};
_execvp("notepad", args);
or
_execlp("notepad", "notepad", "c:\\somefile.txt", NULL);
The spawn family of functions is similar to the exec family of functions, but has
slightly different capabilities.
_spawnl _spawnle _spawnlp _spawnlpe
_spawnv _spawnve _spawnvp _spawnvpe
Notes
exec code (Also command line, environment, atexit, system, spawn)