Що означає 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
@Gab як проста друк змінних середовища призводить до вразливості? Просто не передайте доручені рядки дослівно на system()дзвінки, запити БД тощо. Як зазвичай це стосується введення користувача.
улідтко

2
@ulidtko Цікаво .. Чи можете ви пояснити, чому вам не потрібно передавати зіпсовані рядки, db-запити тощо під час використання 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. Я ніколи не чув про систему, яка це робить на практиці, але вона, безумовно, може існувати і не порушує жодних стандартів.
Чак

77
@Chuck: Оскільки "значення argv[argc]має бути 0" (C ++ 03 §3.6.1 / 2), argvне може бути нульовим.
Джеймс Мак-Нілліс

20
@Chuck: C (принаймні C99) має ту саму вимогу.
Джеймс Мак-Нілліс

2
Думаю, я повинен додати, це те саме в більшості систем там, хоча вони були абстраговані кілька разів. Наприклад, у Pascal / Delphi / Lazarus ви отримуєте; ParamStr і ParamCount (якщо пам'ять служить мені правильно). Моя думка, коли ви (якщо взагалі колись) пишете рідні програми іншими мовами / oses, є хороший шанс, що вищезгадане визначено для вас, і вони працюють ідеально однаково (кількість / рядок список) у всіх системах, які підтримують їх.
Крістіан

8
@ EmilVikström Ні, це серйозна помилка, яка, ймовірно, призводить до сегментації. *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'

Якщо ви оголосили свого основного як 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. Відповідь оновлена, щоб бути правильнішою.
Toby Speight

Ніякої ідеї - я пропоную вам створити мінімально відтворюваний приклад і запитати його (припускаючи, що процес недостатній, щоб допомогти вам відповісти на нього самостійно).
Toby Speight

9

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


2
Argv [] завжди має argv [arg] як нульовий покажчик. і Argv [0] - це завжди (повний шлях) /
ExecutableName

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параметр integer ( ), і це кількість аргументів, переданих програмі.

Ім'я програми завжди є першим аргументом, тому для програми буде щонайменше один аргумент, а мінімальне значення argcбуде один. Але якщо у програми є два аргументи, значення argcwill буде три.

Параметр argvвказує на рядковий масив і називається вектором аргументу . Це одновимірний рядковий масив аргументів функції.


5
int main();

Це проста декларація. Він не може приймати жодних аргументів командного рядка.

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

Ця декларація використовується, коли ваша програма повинна приймати аргументи командного рядка. Коли бігають так:

myprogram arg1 arg2 arg3

argc, або Кількість аргументів буде встановлено на 4 (чотири аргументи), або argv, або Вектори аргументів, будуть заповнені рядковими покажчиками на "мійпрограма", "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(). Майже завжди є краще рішення, реалізоване через бібліотеки С.


3

Перший параметр - кількість наданих аргументів, а другий - список рядків, що представляють ці аргументи.


7
Перший запис у argv [0] - це назва програми, а не аргумент
user3629249

@ user3629249 Назва програми з програмним шляхом. ;)
Майстер Джеймс

1

Обидва

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

є юридичними визначеннями точки входу для програми C або C ++. Stroustrup: C ++ Style and Technique FAQ (FAQ) описує деякі варіанти, які є можливими або законними для вашої основної функції.


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

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

@ Руслан Вибачте, я опублікував це, коли я тільки вивчав С, і, можливо, я прочитав, що в дуже ранніх версіях C voidце потрібно. Не цитуйте мене з цього приводу, і я тепер знаю, що це трохи дурний коментар. Але це не може зашкодити.
dylnmc

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