Что означает int argc, char * argv []?


508

Во многих C ++ IDE и компиляторах, когда он генерирует основную функцию для вас, это выглядит так:

int main(int argc, char *argv[])

Когда я кодирую C ++ без IDE, просто с помощью компилятора командной строки, я набираю:

int main()

без каких-либо параметров. Что это значит и важно ли это для моей программы?


47
Если ваша программа будет игнорировать аргументы командной строки, то то, что вы пишете, хорошо. Если вашей программе нужно обрабатывать аргументы командной строки, тогда IDE делает это правильно.
Джонатан Леффлер

30
Подсказка для хакеров: попробуйте объявить int main(int argc, char* argv[], char* envp[])и распечатать последний аргумент. ;)
ulidtko

7
@ulidtko нехорошо, что ты учишь новичков внедрять уязвимости в свои программы;)
Gab 是 好人

13
@ Габ, как простая печать переменных среды приводит к уязвимости? Только не передавайте испорченные строки дословно system()вызовам, запросам в БД и т. Д. Как обычно, при вводе пользователем.
ulidtko

2
@ulidtko Интересно .. Можете ли вы объяснить, почему вам не нужно передавать испорченные строки, запросы БД и т. д. при использовании char **envpаргумента?
Мастер Джеймс

Ответы:


651

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

8
argcможет быть 0, в этом случае argvможет быть NULL. Это разрешено стандартом AFAIK. Я никогда не слышал о системе, которая делает это на практике, но она, безусловно, может существовать и не будет нарушать какие-либо стандарты.
Чак

78
@Chuck: Так как «Значение argv[argc]должно быть 0» (C ++ 03 §3.6.1 / 2), argvне может быть нулевым.
Джеймс МакНеллис

20
@ Чак: C (по крайней мере, C99) имеет такое же требование.
Джеймс МакНеллис

2
Думаю, я должен добавить, что это то же самое в большинстве систем, хотя иногда они абстрагируются. Например, в Pascal / Delphi / Lazarus вы получаете; ParamStr и ParamCount (если память мне не изменяет). Моя точка зрения такова, что когда вы (если когда-либо) пишете собственные приложения на других языках / языках, есть большая вероятность того, что вышеупомянутое определено для вас, и они работают совершенно одинаково (счетчик / список строк) во всех системах, которые поддерживают их.
Кристиан

8
@ EmilVikström Нет, это серьезная ошибка, которая, вероятно, приводит к segfault. *NULLточно не равно NULL.
Meagar

52

argcэто число аргументов, передаваемых в вашу программу из командной строки, и argvэто массив аргументов.

Вы можете перебирать аргументы, зная их количество, например:

for(int i = 0; i < argc; i++)
{
    // argv[i] is the argument at index i
}

19

Предположим, что вы запускаете свою программу таким образом (используя shсинтаксис):

myprog arg1 arg2 'arg 3'

Если вы объявили ваш main как int main(int argc, char *argv[]), то (в большинстве сред) ваш main()вызов будет выглядеть так:

p = { "myprog", "arg1", "arg2", "arg 3", NULL };
exit(main(4, p));

Однако, если вы объявили свой главный как int main(), он будет называться что-то вроде

exit(main());

и вы не получите аргументы переданы.

Еще две вещи, на которые стоит обратить внимание:

  1. Это только две стандартные подписи для main . Если конкретная платформа принимает дополнительные аргументы или другой тип возвращаемого значения, то это расширение и на него нельзя полагаться в переносимой программе.
  2. *argv[]и **argvв точности эквивалентны, так что вы можете написать int main(int argc, char *argv[])как int main(int argc, char **argv).

2
Если мы технические, basic.start.main/2явно разрешаем определенные реализацией дополнительные версии main(), при условии, что реализация предоставляет две предопределенные версии. Таким образом, они не совсем не соответствуют. Наиболее распространенным из них является envp, что так хорошо известны как в C и C ++ , что это буквально очень первая запись в разделе J.5 (общие расширения) стандарта C .
Джастин Тайм - Восстановить Монику

1
Спасибо за хороший педантизм @Justin. Ответ обновлен, чтобы быть более правильным.
Тоби Спейт

Понятия не имею - я предлагаю вам создать минимальный воспроизводимый пример и задать его (при условии, что этот процесс недостаточен, чтобы помочь вам ответить на него самостоятельно).
Тоби Спейт

9

Параметры для mainпредставления параметров командной строки, предоставленных программе при ее запуске. argcПараметр представляет количество аргументов командной строки, и char *argv[]представляет собой массив строк (указатели символов) , представляющие собой отдельные аргументы , предусмотренные в командной строке.


2
Argv [] всегда имеет argv [arg] в качестве нулевого указателя. и Argv [0] всегда является (полный путь) /
executetableName

3
@ user3629249: не обязательно; argv[0]что бы программа, запускающая программу на C, дала это как argv[0]. В случае с Bash это часто (возможно, всегда) путь к исполняемому файлу, но Bash - не единственная программа, которая выполняет другие программы. Это permissisble, хотя эксцентричный, чтобы использовать: char *args[] = { "cat", "/dev/null", "/etc/passwd", 0 }; execv("/bin/ls", args);. На многих системах значение воспринимается программой как argv[0]будет cat, хотя исполняемый файл есть /bin/ls.
Джонатан Леффлер

7

mainФункция может иметь два параметра, argcи argv. argcявляется целочисленным intпараметром ( ), и это число аргументов, переданных программе.

Имя программы всегда является первым аргументом, поэтому в программе будет хотя бы один аргумент, а минимальное значение argcбудет одним. Но если программа имеет два аргумента, значение argcбудет равно трем.

Параметр argvуказывает на массив строк и называется вектором аргумента . Это одномерный строковый массив аргументов функции.


5
int main();

Это простая декларация. Он не может принимать аргументы командной строки.

int main(int argc, char* argv[]);

Это объявление используется, когда ваша программа должна принимать аргументы командной строки. Когда бегаешь так:

myprogram arg1 arg2 arg3

argcили Счетчик аргументов будет установлен на 4 (четыре аргумента), а argvВекторы аргументов будут заполнены строковыми указателями на «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.


3

Первый параметр - это количество предоставленных аргументов, а второй параметр - список строк, представляющих эти аргументы.


7
первая запись в argv [0] - это имя программы, а не аргумент
user3629249

@ user3629249 Имя программы с путем программы. ;)
Мастер Джеймс

1

Оба

int main(int argc, char *argv[]);
int main();

являются юридическими определениями точки входа для программы на C или C ++. Stroustrup: FAQ по стилю и технике C ++ подробно описывает некоторые варианты, которые возможны или допустимы для вашей основной функции.


4
Возможно, стоит добавить void в ... int main()==> int main(void)... для совместимости и читабельности. Я не знаю, позволяют ли все более старые версии C пустым функциям иметь пустой список параметров в объявлении.
dylnmc

1
@dylnmc это не дает никакого улучшения читабельности, и в точности эквивалентно во всех версиях C ++. Только в C это имеет значение, но только в декларациях, а не в определении.
Руслан

@Ruslan Извините, я опубликовал это, когда только изучал C, и я мог прочитать, что в очень ранних версиях C voidэто необходимо. Не цитируйте меня об этом, и теперь я знаю, что это слегка глупый комментарий. Это не может повредить, хотя.
dylnmc

Что делать, если argc <3 возвращает ошибку? что могло пойти не так?
AVI
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.