You can pass some arguments to C programs. When main() is called at the beginning of a calculation, it is passed three parameters. The first of them determines the number of command arguments when accessing the program. The second is an array of pointers to character strings containing these arguments (one argument per line). The third is also an array of pointers to character strings; it is used to access operating system parameters (environment variables).

Any such line is represented as:

variable = value\0

The last line can be found by the two trailing zeros.

Let's name the arguments of the main() function accordingly: argc, argv and env (any other names are possible). Then the following descriptions are acceptable:

main(int argc, char *argv)

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

Let's assume that on drive A: there is some program prog.exe. Let's address it as follows:

A:\>prog.exe file1 file2 file3

Then argv is a pointer to the line A:\prog.exe, argv is a pointer to the line file1, etc. The first actual argument is pointed to by argv, and the last by argv. If argc=1, then there are no parameters after the program name on the command line. In our example, argc=4.

Recursion

Recursion is a method of calling in which a function refers to itself.

An important point when composing a recursive program is the organization of the output. An easy mistake to make here is that the function will sequentially call itself indefinitely. Therefore, the recursive process must, step by step, simplify the problem so that in the end there is a non-recursive solution for it. Using recursion is not always desirable, as it can lead to stack overflow.

Library functions

In programming systems, routines for solving frequently encountered problems are combined into libraries. Such tasks include: calculating mathematical functions, data input/output, string processing, interaction with tools operating system etc. The use of library routines relieves the user of the need to develop appropriate tools and provides him with additional services. The functions included in the libraries are supplied with the programming system. Their declarations are given in *.h files (these are so-called include or header files). Therefore, as mentioned above, at the beginning of a program with library functions there should be lines like:

#include<включаемый_файл_типа_h>

For example:

#include

There are also facilities for expanding and creating new libraries with user programs.

Global variables are allocated a fixed place in memory for the entire duration of the program. Local variables are stored on the stack. Between them there is a memory area for dynamic allocation.

The malloc() and free() functions are used to dynamically allocate free memory. The malloc() function allocates memory, the free() function frees it. The prototypes of these functions are stored in the stdlib.h header file and look like:

void *malloc(size_t size);

void *free(void *p);

The malloc() function returns a void pointer; For proper use, the function value must be converted to a pointer to the appropriate type. If successful, the function returns a pointer to the first byte of free memory of size size. If there is not enough memory, the value 0 is returned. To determine the number of bytes needed for a variable, use the sizeof() operation.

An example of using these functions:

#include

#include

p = (int *) malloc(100 * sizeof(int)); /* Allocate memory for 100

integers */

printf("Not enough memory\n");

for (i = 0; i< 100; ++i) *(p+i) = i; /* Использование памяти */

for (i = 0; i< 100; ++i) printf("%d", *(p++));

free(p); /* Free memory */

Before using the pointer returned by malloc(), you must ensure that there is enough memory (the pointer is not null).

Preprocessor

A C preprocessor is a program that processes input to the compiler. The preprocessor looks at the source program and performs the following actions: connects specified files to it, performs substitutions, and also controls compilation conditions. Program lines starting with the # symbol are intended for the preprocessor. Only one command (preprocessor directive) is allowed to be written on one line.

Directive

#define identifier substitution

causes the named identifier to be replaced in subsequent program text with the substitution text (note the absence of a semicolon at the end of this command). Essentially, this directive introduces a macro definition, where "identifier" is the name of the macro definition, and "substitution" is the sequence of characters with which the preprocessor replaces the specified name when it finds it in the program text. It is customary to type the name of a macro definition in capital letters.

Let's look at examples:

The first line causes the program to replace the identifier MAX with the constant 25. The second line allows you to use the word BEGIN in the text instead of the opening curly brace (().

Note that since the preprocessor does not check the compatibility between the symbolic names of macro definitions and the context in which they are used, it is recommended to define such identifiers not with the #define directive, but with the help of the const keyword with an explicit indication of the type (this applies to a greater extent to C+ +):

const int MAX = 25;

(the int type can be omitted, as it is the default).

If the #define directive looks like:

#define identifier(identifier, ..., identifier) ​​substitution

and there is no space between the first identifier and the opening parenthesis, then this is the definition of a macro substitution with arguments. For example, after a line like:

#define READ(val) scanf("%d", &val)

statement READ(y); treated the same as scanf("%d",&y);. Here val is an argument and macro substitution with the argument is performed.

If there are long definitions in the substitution that continue in the next line, the character \ is placed at the end of the next continuation line.

You can put objects separated by ## into a macro definition, for example:

#define PR(x, y) x##y

After this, PR(a, 3) will call substitution a3. Or, for example, macro definition

#define z(a, b, c, d) a(b##c##d)

will result in replacing z(sin, x, +, y) with sin(x+y).

The # symbol placed before a macro argument indicates that it is converted to a string. For example, after the directive

#define PRIM(var) printf(#var"= %d", var)

the following fragment of the program text

is converted like this:

printf("year""= %d", year);

Let's describe other preprocessor directives. The #include directive has been seen before. It can be used in two forms:

#include "filename"

#include<имя файла>

The action of both commands is to include files with specified name. The first of them loads a file from the current directory or the directory specified as a prefix. The second command searches for the file in standard locations defined in the programming system. If the file whose name is written in double quotes is not found in the specified directory, then the search will continue in the subdirectories specified for the #include command<...>. #include directives can be nested within each other.

The next group of directives allows you to selectively compile parts of the program. This process is called conditional compilation. This group includes the directives #if, #else, #elif, #endif, #ifdef, #ifndef. The basic form of writing the #if directive looks like this:

#if constant_expression sequence_of operators

Here the value of a constant expression is checked. If it is true, then the specified sequence of statements is executed, and if it is false, then this sequence of statements is skipped.

The action of the #else directive is similar to the action of the else command in the C language, for example:

#if constant_expression

statement_sequence_2

Here, if the constant expression is true, then operator_sequence_1 is executed, and if false, operator_sequence_2 is executed.

The #elif directive means an "else if" action. The basic form of its use is:

#if constant_expression

statement_sequence

#elif constant_expression_1

statement_sequence_1

#elif constant_expression_n

sequence_of_statements_n

This form is similar to the C language construct: if...else if...else if...

Directive

#ifdef identifier

determines whether the specified identifier is currently defined, i.e. whether it was included in directives like #define. String of the form

#ifndef identifier

checks whether the specified identifier is currently undefined. Any of these directives can be followed by an arbitrary number of lines of text, possibly containing an #else statement (#elif cannot be used) and ending with the line #endif. If the condition being checked is true, then all lines between #else and #endif are ignored, and if false, then the lines between the check and #else (if there is no word #else, then #endif). #if and #ifndef directives can be nested within each other.

View directive

#undef identifier

causes the specified identifier to be considered undefined, i.e. not subject to replacement.

Let's look at examples. The following three directives:

check whether the WRITE identifier is defined (i.e. whether there was a command like #define WRITE...), and if so, then the WRITE name begins to be considered undefined, i.e. not subject to replacement.

Directives

#define WRITE fprintf

checks whether the WRITE identifier is undefined, and if so, the WRITE identifier is determined instead of the fprintf name.

The #error directive is written in the following form:

#error error_message

If it occurs in the program text, compilation stops and an error message is displayed on the display screen. This command is mainly used during the debugging phase. Note that the error message does not need to be enclosed in double quotes.

The #line directive is intended to change the values ​​of the _LINE_ and _FILE_ variables defined in the C programming system. The _LINE_ variable contains the line number of the program currently being executed. The _FILE_ identifier is a pointer to a string with the name of the program being compiled. The #line directive is written as follows:

#line number "file_name"

Here number is any positive integer that will be assigned to the _LINE_ variable, file_name is an optional parameter that overrides the value of _FILE_.

The #pragma directive allows you to pass some instructions to the compiler. For example, the line

indicates that the C program contains assembly language strings. For example:

Let's look at some global identifiers or macronames (macro definition names). Five such names are defined: _LINE_, _FILE_, _DATE_, _TIME_, _STDC_. Two of them (_LINE_ and _FILE_) have already been described above. The _DATE_ identifier specifies a string that stores the date the source file was translated into object code. The _TIME_ identifier specifies a string that stores the time at which the source file was translated into object code. The _STDC_ macro has a value of 1 if standard defined macro names are used. Otherwise this variable will not be defined.

Optional and named arguments

Optional Arguments

C# 4.0 introduces a new feature that makes it easier to specify arguments when calling a method. This remedy is called optional arguments and allows you to define a default value for a method parameter. This value will be used by default if a corresponding argument is not specified for the parameter when calling the method. Therefore, it is not necessary to provide an argument for such a parameter. Optional arguments make it easier to call methods where default arguments are applied to some parameters. They can also be used as a "shortcut" form of method overloading.

The main impetus for adding optional arguments was the need to simplify interaction with COM objects. In several Microsoft object models (for example, Microsoft Office) functionality is provided through COM objects, many of which were written a long time ago and are designed to use optional parameters.

An example of using optional arguments is shown below:

Using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 ( class Program ( // Arguments b and c are optional when calling static int mySum(int a, int b = 5, int c = 10) ( return a + b + c; ) static void Main() ( int sum1 = mySum(3); int sum2 = mySum(3,12); Console.WriteLine("Sum1 = "+sum1);

It should be kept in mind that all optional arguments must be specified to the right of the required ones. In addition to methods, optional arguments can be used in constructors, indexers, and delegates.

One benefit of optional arguments is that they make it easier for the programmer to handle complex method and constructor calls. After all, it is often necessary to specify more parameters in a method than is usually required. And in such cases, some of these parameters can be made optional through careful use of optional arguments. This means that you only need to pass those arguments that are important in a given case, rather than all the arguments that would otherwise be required. This approach allows you to rationalize the method and simplify the programmer’s handling of it.

Named Arguments

One more functionality, which was added to C# with the release of .NET 4.0, is support for the so-called named arguments. As you know, when passing arguments to a method, their order, as a rule, must coincide with the order in which the parameters are defined in the method itself. In other words, the argument value is assigned to the parameter based on its position in the argument list.

Named arguments are designed to overcome this limitation. A named argument allows you to specify the name of the parameter to which its value is assigned. And in this case, the order of the arguments no longer matters. Thus, named arguments are somewhat similar to the previously mentioned object initializers, although they differ from them in their syntax. To specify an argument by name, use the following form of syntax:

parameter_name: value

Here parameter_name denotes the name of the parameter to which the value is passed. Of course, parameter_name must be the name of the actual parameter for the method being called.

Tags: Options command line

Command Line Options

C is a compiled language. After assembly, the program is executable file(we do not consider creating dynamic libraries, drivers, etc.). Our programs are very simple and do not contain Runtime libraries, so they can be transferred to a computer with the same operating system (and similar architecture) and run there.

The program can accept parameters during startup. They are arguments to the main function. The general view of the main function is as follows

Void main(int argc, char **argv) ( ... )

The first argument of argc is the number of parameters passed to the function. The second argument is an array of strings – the parameters themselves. Since the parameters of a function can be anything, they are passed as strings, and the program itself must parse them and convert them to the desired type.

The first argument (argv) is always the program name. In this case, the name is displayed depending on where the program was launched from.

#include #include void main(int argc, char **argv) ( printf("%s", argv); )

Now let's learn how to work a little with the command line. This will be needed in order to pass arguments to our program. The Win+R key combination brings up the Run window. Type cmd in it and you will open the command line. You can also find cmd.exe by searching in the Start menu. In Unix-like operating systems, you can call the terminal program.

We won't be learning too many commands. Only those that are needed for work.

The cd command, standard for all operating systems, navigates to the desired folder. There are two reserved names - . (dot) and.. (two dots). The dot is the name of the current folder.

Doesn't go anywhere

Accessing the parent folder

Go to parent folder

To go to the desired one, write the CD address. For example, you need to go to windows to the folder C:\Windows\System32

Cd C:\Windows\System32

In Linux, if you need to go to the /var/mysql folder

Cd /var/mysql

If the path contains spaces, it is written in double quotes

Cd "D:\Docuents and Settings\Prolog"

The terminal has the following useful features: if you press the up arrow, the previous executed command will appear. If you press tab, the terminal will try to complete the line to a command known to it, or complete the path, going through all the folders and files in the current folder.
Type cd C:\
press tab and see what happens.

Another important command, dir on Windows and ls on Linux, displays the contents of the current folder (the folder you are currently in) to the console.

Your program has returned full name. Go to the folder where your program is located and look at its contents


Now that we've navigated to our folder, we can run our program. To do this, type her name.


Note that the name has changed. Since the program is called from its own folder, the relative name is displayed. Now let's change the program and make it print all the arguments. which were given to her.

#include #include void main(int argc, char **argv) ( int i; for (i = 0; i< argc; i++) { printf("%s\n", argv[i]); } }

Assemble the project. Before assembling, make sure the program is closed. Now call the program, passing it different arguments. To do this, write the name of the program and the arguments separated by a space


Let's now write a program that takes two number arguments and prints their sum

#include #include #include void main(int argc, char **argv) ( int a, b; if (argc != 3) ( printf("Error: found %d arguments. Needs exactly 2", argc-1); exit(1); ) a = atoi(argv); b = atoi(argv); printf("%d", a + b);

Let's collect and call


This is how most programs work. By clicking on a shortcut, you call the program to which it refers. Most programs also accept various arguments. For example, you can call firefox browser from the command line and pass the arguments
firefox.exe "www.mozilla.org" "site" and it will immediately open the sites at the specified addresses in two tabs.

Many standard commands also have parameters. In Windows it is customary that they begin with a forward slash, in Unix with a minus or two minuses. For example

Displays only folders, but in the linux terminal

Ls -l lists all files and folders with attributes

To view additional Windows commands, type help at the command line or see the manual (it's easy to find on the Internet). For Linux there are many more commands and their options, and some of them are independent programming languages, so it’s worth learning at least the minimum set and their options.

Borland C++ supports three arguments to main(). The first two are the traditional argc and argv. These are the only arguments to main() defined by the ANSI C standard. They allow command line arguments to be passed to the program. Command line arguments are the information that follows the program name on the operating system command line. For example, when a program is compiled using the Borland line compiler, it is typically typed bcc program_name

Where program_name is a program that needs to be compiled. The program name is passed to the compiler as an argument.

The argc parameter contains the number of command line arguments and is an integer. It is always equal to at least 1, since the program name qualifies as the first argument. The argv parameter is a pointer to an array of character pointers. Each element of this array points to a command line argument. All command line arguments are strings. All numbers are converted by the program into internal format. The following program prints "Hello" followed by the username when typed directly after the program name:

#include

{
if(argc!=2)
{
printf("You forgot to type your name\n");
return 1;
}
printf("Hello %s", argv);
return 0;
}

If you call this program name, and the user name is Sergey, then to start the program you should type:
name Sergey.
As a result of the program the following will appear:
"Hello Sergey."

Command line arguments must be separated by spaces or tabs. Commas, semicolons, and similar characters are not considered delimiters. For example:

Consists of three lines, while

Herb,Rick,Fred

This is one line - commas are not delimiters.

If you need to pass a string containing spaces or tabs as a single argument, you must enclose it in double quotes. For example, this is one argument:

"this is a test"

It is important to declare argv correctly. The most typical method is:

Empty parentheses indicate that the array does not have a fixed length. You can access individual elements using argv indexing. For example, argv points to the first line, which always contains the program name. argv points to the next line and so on.

Below is a small example of using command line arguments. It counts down from the value specified on the command line and emits a signal when it reaches zero. Note that the first argument contains a number converted to an integer using the standard atoi() function. If the string "display" is present as the second argument, then the counter itself will be displayed on the screen.

/* counting program */

#include
#include
#include
int main(int argc, char *argv)
{
int disp, count;
if(argc<2)
{
printf("You must enter the length of the count\n");
printf("on the command line. Try again.\n");
return 1;
}
if (argc==3 && !strcmp(argv,"display")) disp = 1;
else disp = 0;
for(count=atoi(argv); count; -count)
if (disp) printf("%d ", count);
printf("%c", "\a"); /* on most computers this is a call */
return 0;
}

Please note that if no arguments are specified, an error message appears. This is most typical for programs that use command line arguments to issue instructions if an attempt was made to run the program without the correct information.

To access individual command line characters, add a second index to argv. For example, the following program prints out all the arguments it was called with, one character at a time:

#include
int main(int argc, char *argv)
{
int t, i;
for(t=0; t {
i = 0;
while(argv[t][i])
{
printf("%c", argv[t][i]);
}
printf(" ");
}
return 0;
}

We must remember that the first index is for accessing a string, and the second is for accessing a character in a string.

Typically argc and argv are used to obtain source commands. It is theoretically possible to have up to 32767 arguments, but most operating systems don't even allow you to get close to that. Typically these arguments are used to specify a file name or options. Using command line arguments gives the program a professional look and allows the program to be used in batch files.

If you include the WILDARGS.OBJ file supplied with Borland C++, you can use templates in *.EXE type arguments. (Borland C++ automatically handles wildcards and increments argc accordingly.) For example, if you connect WILDARGS.OBJ to the following program, it will tell you how many files match the filename specified on the command line:

/* Link this program with WILDARGS.OBJ */

#include
int main(int argc, char *argv)
{
register int i;
printf("%d files match specified name\n", argc-1);
printf("They are: ");
for(i=1; i printf("%s ", argv[i]);
return 0;
}

If we call this program WA, then run it as follows, we will get the number of files with the EXE extension and a list of the names of these files:

In addition to argc and argv, Borland C++ also provides a third command line argument -env. The env parameter allows a program to access information about the operating system environment. The env parameter must follow argc and argv and is declared as follows:

As you can see, env is declared in the same way as argv. Just like argv, it is a pointer to an array of strings. Each line is an environment string defined by the operating system. The env parameter has no equivalent argc parameter that tells how many environment rows there are. Instead, the last line of the environment is null. The following program prints all the environment strings currently defined in the operating system:

/* this program displays all the environment lines */

#include
int main(int argc, char *argv, char *env)
{
int;
for(t=0; env[t]/ t++)
printf("%s\n", env[t]);
return 0;
}

Please note that although argc and argv are not used by the program, they must be present in the parameter list. C doesn't know the parameter names. Instead, their use is determined by the order in which the parameters are declared. In fact, you can call the parameter whatever you like. Since argc, argv, and env are traditional names, it is best to continue to use them so that anyone reading the program can instantly understand that these are arguments to the main() function.

A typical task for programs is to look up a value defined in an environment string. For example, the contents of the PATH line allow programs to use search paths. The following program demonstrates how to find strings that declare standard search paths. It uses the standard library function strstr(), which has the following prototype:

Char *strstr(const char *str1, const char *str2);

The strstr() function searches for the string pointed to by str1 in the string pointed to by str2. If such a string is found, a pointer to the first position is returned. If no matches are found, the function returns NULL.

/* the program searches among the environment strings for a line containing PATH */

#include
#include
int main (int argc, char *argv, char *env)
{
int;
for(t=0; env[t]; t++)
{
if(strstr(env[t], "PATH"))
printf("%s\n", env[t]);
}
return 0;
}

It happens that data is transferred to a program from the command line when it is called. Such data is called command line arguments. It looks like this, for example:

./a.out test.txt ls -lt /home/peter/

Here the programs a.out (from the current directory) and ls (from the same directory specified in the PATH environment variable) are called. The first program from the command line receives one word - test.txt, the second - two: -lt and /home/peter/.

If the program is written in C, then when it is launched, control is immediately transferred to the main() function, therefore, it is the function that receives the command line arguments that are assigned to its parameter variables.

Previously, we defined the main() function as if it takes no parameters and returns nothing. In fact, in the C language, any function by default (if nothing else is defined) returns an integer. You can be sure of this. If you write the code this way:

main() ( printf ("Hi \n") ; return 0 ; )

Then no warning or error will occur during compilation. The same thing happens if you write int main() . This proves that the function by default returns an integer and not nothing (void). Although what a function returns can always be “overridden”, for example, voidmain() or float main() .

When calling a program from the command line, the following pair of data is always passed into it:

  1. integer, indicating the number of words (elements separated by spaces) on the command line when called,
  2. pointer to an array of strings, where each line is a separate word from the command line.

Keep in mind that the program name itself also counts. For example, if the call looks like this:

./a.out 12 theme 2

Then the first argument of the program has the value 4, and the array of strings is defined as ("./a.out", "12", "theme", "2").

Note the terminology, there are only two program arguments (a number and an array), but as many command line arguments as you like. Command line arguments are "converted" into program arguments (into main() function arguments).
This data (number and pointer) is passed to the program even when it is simply called by name without passing anything to it: ./a.out. In this case, the first argument has the value 1, and the second points to an array consisting of just one line ("./a.out").

Just because data is passed into the program does not mean that the main() function must accept it. If the main() function is defined without parameters, then command line arguments cannot be accessed. Although nothing prevents you from transmitting them. There will be no error.

To access the data passed to the program, it must be assigned to variables. Since the arguments are immediately passed to main() , its header should look like this:
main (int n, char *arr)

The first variable (n) contains the number of words, and the second variable contains a pointer to an array of strings. Often the second parameter is written as **arr . However, it's the same thing. Recall that the array of strings itself contains pointers to strings as its elements. And we pass a pointer to the first element of the array to the function. It turns out that we are passing a pointer to a pointer, i.e. **arr.

Exercise
Write a program like this:

#include int main(int argc, char ** argv) ( int i; printf ("%d \n", argc) ; for (i= 0 ; i< argc; i++ ) puts (argv[ i] ) ; }

It displays the number of words on the command line when it is called, and each word on a new line. Call it without command line arguments and with arguments.

In the program we used the parameter variables argc and argv. It is customary to use these names, but in fact they can be anything. It's better to stick to this standard so that your programs are more understandable not only to you, but also to other programmers.

The practical significance of transferring data to the program

If you have any experience with the GNU/Linux command line, you know that most commands have switches and arguments. For example, when viewing the contents of directories, copying, moving, the file system objects on which the command is executed are specified as arguments. The features of its implementation are determined using keys. For example, in a team

Cp -r ../les_1 ../les_101

cp is the command name, -r is the switch, and ../les_1 and ../les_101 are the command arguments.

In general, most often, file addresses and “modifiers” (these are keys) of the program execution process are transferred to programs when they are launched.

Let's write a program that opens files specified by the user on the command line for writing or adding and writes (adds) there the same information that the user enters from the keyboard during program execution:

#include #include main (int argc, char ** argv) ( int i, ch; FILE * f[ 5 ] ; if (argc< 3 || argc >7) (puts ( "Invalid number of parameters") ; return 1 ; ) if (strcmp (argv[ 1 ] , "-w" ) != 0 && strcmp (argv[ 1 ] , "-a" ) != 0 ) ( puts ( "The first parameter can be either -w or -a") ; return 2 ; ) for (i= 0 ; i< argc- 2 ; i++ ) { f[ i] = fopen (argv[ i+ 2 ] , argv[ 1 ] + 1 ) ; if (f[ i] == NULL) { printf ("The file %s cannot be opened\n ", argv[ i+ 2 ] ) ; return 3 ; ) ) while ((ch = getchar () ) != EOF) for (i= 0 ; i< argc- 2 ; i++ ) putc (ch, f[ i] ) ; for (i= 0 ; i < argc- 2 ; i++ ) fclose (f[ i] ) ; return 0 ; }

Explanations for the code:

  1. An array of five file pointers is created. Therefore, you can open no more than five files at the same time. The file pointer of the first file will be stored in array element f, the second - in f, etc.
  2. The number of command line arguments is checked. There should be at least three of them, because... the first is the program name, the second is the file opening mode, the third is the first or only file to be written to. Since the program allows you to open only five files, then total number There cannot be more than seven command line arguments. Therefore, if the number of arguments is less than 3 or more than 7, then the program terminates, because The return statement causes the function to exit, even if there is more code after it. A value returned from a function that is not equal to 0 can be interpreted by the parent process as a message that the program terminated with an error.
  3. Checks the validity of the second command line argument. If it is neither "-w" nor "-a", then the conditional expression in the second if returns 1 (true). The strcmp() function allows you to compare strings and returns 0 if they are equal.
  4. IN for loop files are opened at the specified addresses, which begin with the third element of the argv array. This is why 2 is added to i to get the elements of the argv array, starting from the third. The argc-2 expression indicates the number of filenames passed; because argc stores the total number of command line arguments, the first two of which are not file names.
  5. The expression argv+1 allows you to “cut” the substring “w” (or “a”) from the string “-w” (or “-a”), because argv is essentially a pointer to the first element of the string. By adding one to the pointer, we move it to the next element of the array.
  6. If the file cannot be opened, the fopen() function returns NULL. In this case, the program ends.
  7. Every character entered by the user on the keyboard is written to all open files.
  8. At the end the files are closed.

Close