Что означает int argc, char *argv[]?
Во многих C++ IDE и компиляторах, когда он генерирует основную функцию для вас, это выглядит так:
int main(int argc, char *argv[])
Когда я кодирую C++ без IDE, просто с помощью компилятора командной строки, я набираю:
int main()
без каких-либо параметров. Что это значит и важно ли это для моей программы?
13 ответов
argv
а также argc
как аргументы командной строки передаются main()
в C и C++.
argc
будет количество строк, на которые указывает argv
, Это (на практике) будет 1 плюс количество аргументов, поскольку практически все реализации будут добавлять имя программы к массиву.
Переменные названы argc
(количество аргументов) и argv
(вектор аргумента) по соглашению, но им может быть присвоен любой действительный идентификатор: int main(int num_args, char** arg_strings)
одинаково действителен
Они также могут быть полностью опущены, давая int main()
, если вы не собираетесь обрабатывать аргументы командной строки.
Попробуйте следующую программу:
#include <iostream>
int main(int argc, char** argv) {
std::cout << "Have " << argc << " arguments:" << std::endl;
for (int i = 0; i < argc; ++i) {
std::cout << argv[i] << std::endl;
}
}
Запуск с ./test a1 b2 c3
будет выводить
Have 4 arguments:
./test
a1
b2
c3
argc
количество аргументов, передаваемых в вашу программу из командной строки и argv
это массив аргументов.
Вы можете перебирать аргументы, зная их количество, например:
for(int i = 0; i < argc; i++)
{
// argv[i] is the argument at index i
}
Предположим, вы запускаете свою программу таким образом (используя sh
синтаксис):
myprog arg1 arg2 'arg 3'
Если вы объявили свой основной как int main(int argc, char *argv[])
затем (в большинстве сред) ваш main()
будет называться как будто как:
p = { "myprog", "arg1", "arg2", "arg 3", NULL };
exit(main(4, p));
Однако, если вы объявили свой основной как int main()
, это будет называться что-то вроде
exit(main());
и вы не получите аргументы переданы.
Обратите внимание на две дополнительные вещи:
- Это только две стандартные подписи для
main
, Если конкретная платформа принимает дополнительные аргументы или другой тип возвращаемого значения, то это расширение и на него нельзя полагаться в переносимой программе. *argv[]
а также**argv
точно эквивалентны, так что вы можете написатьint main(int argc, char *argv[])
какint main(int argc, char **argv)
,
int main();
Это простая декларация. Он не может принимать аргументы командной строки.
int main(int argc, char* argv[]);
Это объявление используется, когда ваша программа должна принимать аргументы командной строки. Когда бегаешь так:
myprogram arg1 arg2 arg3
argc
или Счетчик аргументов будет установлен на 4 (четыре аргумента), и argv
или Argument Vectors, будут заполнены строковыми указателями на "myprogram", "arg1", "arg2" и "arg3". Вызов программы ( myprogram
) входит в аргументы!
В качестве альтернативы вы можете использовать:
int main(int argc, char** argv);
Это также верно.
Есть еще один параметр, который вы можете добавить:
int main (int argc, char *argv[], char *envp[])
envp
Параметр также содержит переменные среды. Каждая запись имеет следующий формат:
VARIABLENAME=VariableValue
как это:
SHELL=/bin/bash
Список переменных среды заканчивается нулем.
ВАЖНО: НЕ используйте argv
или же envp
значения непосредственно в вызовах system()
! Это огромная дыра в безопасности, поскольку злоумышленники могут устанавливать переменные среды для команд командной строки и (потенциально) наносить огромный ущерб. В общем просто не пользуюсь system()
, Почти всегда есть лучшее решение, реализованное с помощью библиотек C.
Рассмотрим декларацию:
int main (int argc, char *argv[])
В приведенном выше объявлении тип второго названного параметра на самом деле является . То есть является указателем на указатель на . Это потому, что
char* []
распадается на
char**
из-за распада типа. Например, приведенные ниже объявления эквивалентны:
int main (int argc, char *argv[]); //first declaration
int main (int argc, char **argv); //RE-DECLARATION. Equivalent to the above declaration
Другими словами,
argv
— это указатель, указывающий на первый элемент динамически выделяемого массива с элементами типа . Более того, каждый элемент динамически размещаемого массива (с элементами типа
char*
) сами указывают на символ, который является началом (динамически выделяемой) символьной строки с нулевым завершением . То есть каждый элемент
argv[i]
указывает на первый элемент динамически размещаемого массива с элементами типа
char
(и не
const char
). Схема дана для наглядности:
Как уже было сказано в других ответах, эта форма декларации
main
используется, когда мы хотим использовать аргумент(ы) командной строки.
Параметры для main
представляют параметры командной строки, предоставленные программе при запуске. argc
Параметр представляет количество аргументов командной строки, и char *argv[]
является массивом строк (символьных указателей), представляющих отдельные аргументы, предоставленные в командной строке.
main
функция может иметь два параметра, argc
а также argv
, argc
целое число (int
), и это количество аргументов, переданных программе.
Имя программы всегда является первым аргументом, поэтому в программе будет хотя бы один аргумент и минимальное значение argc
будет один. Но если программа имеет два аргумента, значение argc
будет три
параметр argv
указывает на строковый массив и называется вектором аргумента. Это одномерный строковый массив аргументов функции.
Первый параметр - это число предоставленных аргументов, а второй параметр - список строк, представляющих эти аргументы.
Аргументы командной строки: main( int argc, char * argv[])
В Unix, когда вы передаете команде дополнительные аргументы, эти команды должны быть переданы исполняющемуся процессу. Например, при вызовеls -al
, он выполняет программуls
и передает строку-al
в качестве аргумента:
% ls
content.html index.html primary.0.html
% ls -al
total 20
drwxr-xr-x 2 dwharder users 4096 Sep 11 16:38 .
drwxr-xr-x 6 dwharder users 4096 Sep 11 16:35 ..
-rwxr-xr-x 1 dwharder users 117 Sep 11 16:38 content.html
-rwxr-xr-x 1 dwharder users 1400 Sep 11 16:37 index.html
-rwxr-xr-x 1 dwharder users 532 Sep 11 16:38 primary.0.html
%
Способ доступа работающей программы к этим дополнительным параметрам заключается в том, что они передаются в качестве параметров функции main:
int main( int argc, char *argv[] ) {
Здесь означает количество аргументов иargv
означает вектор аргумента.
Первый аргумент — это количество переданных параметров плюс один, включающий имя программы, которая была запущена для запуска этого процесса. Таким образом, всегда больше нуля иargv[0]
— это имя исполняемого файла (включая путь), который был запущен для запуска этого процесса. Например, если мы запустим
#include <stdio.h>
int main( int argc, char *argv[] ) {
printf( "argv[0]: %s\n", argv[0] );
return 0;
}
Здесь мы компилируем этот код, сначала компилируем и запускаем его так, чтобы имя исполняемого файла былоa.out
а затем мы снова компилируем его и запускаем, чтобы имя исполняемого файла былоarg
:
% gcc argument.0.c
% ./a.out
argv[0]: ./a.out
% gcc -o arg argument.0.c
% ./arg
argv[0]: ./arg
%
Если передано больше дополнительных аргументов командной строки, строка всех символов анализируется и разделяется на подстроки на основе нескольких правил; однако, если все символы являются символами, цифрами или пробелами, оболочка разделит их на основе пробелов и назначитargs[1]
адрес первого,args[2]
адрес второго и так далее.
Следующая программа печатает все аргументы:
#include <stdio.h>
int main( int argc, char *argv[] ) {
int i;
printf( "argc: %d\n", argc );
printf( "argv[0]: %s\n", argv[0] );
if ( argc == 1 ) {
printf( "No arguments were passed.\n" );
} else {
printf( "Arguments:\n" );
for ( i = 1; i < argc; ++i ) {
printf( " %d. %s\n", i, argv[i] );
}
}
return 0;
}
Здесь мы выполняем эту программу с одним, а затем с двенадцатью аргументами командной строки:
% gcc argument.c
% ./a.out first
argc: 2
argv[0]: ./a.out
Arguments:
1. first
% ./a.out first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth
argc: 13
argv[0]: ./a.out
Arguments:
1. first
2. second
3. third
4. fourth
5. fifth
6. sixth
7. seventh
8. eighth
9. ninth
10. tenth
11. eleventh
12. twelfth
%
Ради забавы
Теперь вам может быть интересно, что на самом деле происходит (а если нет, то можете пропустить это). Во-первых, когда команда выполняется, оболочка анализирует командную строку и разделяет отдельные части нулевым символом.\0
. Например, выполнение
% ./a.out first second third fourth fifth
имеет ли оболочка генерировать строку./a.out☐first☐second☐third☐fourth☐fifth☐
где поле представляет нулевой символ. Далее память для массива из шести (argc
) выделяются указатели, и этим шести указателям присваивается первый символ каждой строки, в которую была проанализирована командная строка. Наконец, для стека выделяется память, и с использованием 8-байтового выравнивания два аргумента помещаются в стек. Это показано на рисунке 1.
Рисунок 1. Результат вызова./a.out first second third fourth fifth
в командной строке.
Дальнейшее развлечение
В Unix оболочка выполняет дальнейшую обработку команды. Например, если он обнаружит подстановочные знаки, обозначающие файлы в текущем каталоге, он попытается расширить эти подстановочные знаки. К ним относятся?
за одного неизвестного персонажа и*
для любого количества символов.
Например, следующая команда проверяет файл в текущем каталоге:
% ls
a.out argument.0.c argument.1.c content.html images index.html primary.0.html src
% ./a.out *
argc: 9
argv[0]: ./a.out
Arguments:
1. a.out
2. argument.0.c
3. argument.1.c
4. content.html
5. images
6. index.html
7. primary.0.html
8. src
% ./a.out *.html
argc: 4
argv[0]: ./a.out
Arguments:
1. content.html
2. index.html
3. primary.0.html
% ./a.out argument.?.c
argc: 3
argv[0]: ./a.out
Arguments:
1. argument.0.c
2. argument.1.c
Аналогичным образом вы можете указать командной строке рассматривать пробелы как часть одной строки или игнорировать подстановочные знаки, используя обратную косую черту перед пробелом или подстановочным знаком или заключая строку в одинарные или двойные кавычки.
% ./a.out hi\ there\?
argc: 2
argv[0]: ./a.out
Arguments:
1. hi there?
% ./a.out "hi there?"
argc: 2
argv[0]: ./a.out
Arguments:
1. hi there?
% ./a.out 'hi there?'
argc: 2
argv[0]: ./a.out
Arguments:
1. hi there?
%
Наконец, если вы окружите текст обратными кавычками, он сначала выполнит это, а затем заменит вывод команды:
% ./a.out `ls *.c`
argc: 4
argv[0]: ./a.out
Arguments:
2. argument.0.c
3. argument.1.c
%
Угадайте, что произойдет, если вы войдете .
Отказ от ответственности: этот пост взят непосредственно с https://ece.uwaterloo.ca/~dwharder/icsrts/C/05/. Первоначально он был написан Дугласом Вильгельмом Хардером из Университета Ватерлоо . Если оно полностью принадлежит другому человеку, то зачем я его сюда поместил? Потому что я прочитал его пост, узнал что-то новое, и он мне настолько понравился, что я разместил его здесь, чтобы другие люди тоже получили от него пользу. Опять же, вся тяжелая работа и аплодисменты достаются мистеру Хардеру, а не мне. Спасибо.
Просто добавить, потому что кто-то говорит, что есть третий параметр (*envp[]
), это правда, но это не безопасно для POSIX, если вы хотите, чтобы ваша программа использовала переменные среды, вы должны использоватьextern char
окружающая среда ;D
Оба
int main(int argc, char *argv[]);
int main();
являются юридическими определениями точки входа для программы на C или C++. Stroustrup: FAQ по стилю и технике C++ подробно описывает некоторые варианты, которые возможны или допустимы для вашей основной функции.
Когда используешь
Если вы узнаете что-то из этого
#include<iostream>
using namespace std;
int main(int argc, char** argv) {
cout << "This program has " << argc << " arguments:" << endl;
for (int i = 0; i < argc; ++i) {
cout << argv[i] << endl;
}
return 0;
}
Эта программа имеет 3 аргумента. Тогда вывод будет таким.
C:\Users\user\Desktop\hello.exe
hello
people