Apa yang dimaksud dengan int argc, char * argv []?

508

Dalam banyak C ++ IDE dan kompiler, ketika menghasilkan fungsi utama untuk Anda, tampilannya seperti ini:

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

Ketika saya kode C ++ tanpa IDE, hanya dengan kompiler baris perintah, saya ketik:

int main()

tanpa parameter apa pun. Apa artinya ini, dan apakah ini penting untuk program saya?

Greg Treleaven
sumber
47
Jika program Anda akan mengabaikan argumen baris perintah, maka apa yang Anda tulis baik-baik saja. Jika program Anda perlu memproses argumen baris perintah, maka IDE melakukannya dengan benar.
Jonathan Leffler
30
Petunjuk bagi peretas: cobalah mendeklarasikan int main(int argc, char* argv[], char* envp[])dan mencetak argumen terakhir. ;)
ulidtko
7
@ Dulidko tidak baik bahwa Anda mengajar pemula untuk memperkenalkan kerentanan dalam program mereka;)
Gab 是 好人
13
@Gab, bagaimana pencetakan variabel lingkungan yang sederhana menyebabkan kerentanan? Hanya saja, jangan meneruskan string tercemar secara verbal ke system()panggilan, permintaan DB, dll. Seperti biasa dengan input pengguna.
ulidtko
2
@ulidtko menarik .. Dapatkah Anda menjelaskan mengapa Anda tidak harus melewati string tercemar, query db, dll saat menggunakan char **envpargumen?
Tuan James

Jawaban:

651

argvdan argcbagaimana argumen baris perintah dilewatkan ke main()dalam C dan C ++.

argcakan menjadi jumlah string yang ditunjukkan oleh argv. Ini akan (dalam praktiknya) menjadi 1 ditambah jumlah argumen, karena hampir semua implementasi akan menambahkan nama program ke array.

Variabel dinamai argc( jumlah argumen ) dan argv( argumen vektor ) oleh konvensi, tetapi mereka dapat diberi pengidentifikasi yang valid: int main(int num_args, char** arg_strings)sama-sama valid.

Mereka juga dapat dihilangkan seluruhnya, menghasilkan int main(), jika Anda tidak berniat untuk memproses argumen baris perintah.

Coba program berikut ini:

#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;
    }
}

Menjalankannya dengan ./test a1 b2 c3kemauan output

Have 4 arguments:
./test
a1
b2
c3
meagar
sumber
8
argcbisa 0, dalam hal argvini bisa NULL. Itu diizinkan oleh AFAIK standar. Saya belum pernah mendengar tentang sistem yang melakukan hal ini dalam praktiknya, tetapi tentu saja bisa ada dan tidak akan melanggar standar apa pun.
Chuck
77
@Chuck: Karena "Nilai argv[argc]harus 0" (C ++ 03 §3.6.1 / 2), argvtidak boleh nol.
James McNellis
20
@ Chuck: C (setidaknya C99) memiliki persyaratan yang sama.
James McNellis
2
Pikir saya harus menambahkan, ini sama di sebagian besar sistem di luar sana, meskipun mereka diabstraksikan beberapa kali. Misalnya, dalam Pascal / Delphi / Lazarus, Anda mendapatkan; ParamStr dan ParamCount (jika ingatanku benar). Maksud saya adalah, ketika Anda (jika pernah) menulis aplikasi asli dalam bahasa lain / oses, ada kemungkinan yang baik di atas didefinisikan untuk Anda gunakan, dan, mereka bekerja dengan sempurna yang sama (hitungan / daftar string) di semua sistem yang mendukung mereka.
Christian
8
@ EmilVikström Tidak, itu adalah kesalahan serius yang mungkin menghasilkan segfault. *NULLjelas tidak sama dengan NULL.
meagar
52

argcadalah jumlah argumen yang diteruskan ke program Anda dari baris perintah dan argvmerupakan array argumen.

Anda dapat mengulang argumen dengan mengetahui jumlah dari mereka seperti:

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

Misalkan Anda menjalankan program Anda dengan demikian (menggunakan shsintaks):

myprog arg1 arg2 'arg 3'

Jika Anda menyatakan utama sebagai int main(int argc, char *argv[]), maka (di sebagian besar lingkungan), Anda main()akan dipanggil seolah-olah seperti:

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

Namun, jika Anda menyatakan utama Anda sebagai int main(), itu akan disebut sesuatu seperti

exit(main());

dan Anda tidak mendapatkan argumen yang lulus.

Dua hal tambahan yang perlu diperhatikan:

  1. Ini adalah satu-satunya dua tanda tangan standar yang diamanatkan untuk main. Jika platform tertentu menerima argumen tambahan atau tipe pengembalian yang berbeda, maka itu merupakan ekstensi dan tidak boleh diandalkan dalam program portabel.
  2. *argv[]dan **argvpersis sama, sehingga Anda dapat menulis int main(int argc, char *argv[])sebagai int main(int argc, char **argv).
Toby Speight
sumber
2
Jika kami sedang teknis, basic.start.main/2secara eksplisit memungkinkan versi tambahan yang ditentukan implementasi main(), asalkan implementasi menyediakan dua versi yang telah ditentukan. Jadi, mereka tidak sepenuhnya tidak sesuai. Yang paling umum adalah envp, yang begitu terkenal di kedua C dan C ++ yang secara harfiah entri pertama di bagian J.5 (ekstensi umum) dari standar C .
Justin Time - Pasang kembali Monica
1
Terima kasih atas kesedihan @Justin. Jawaban diperbarui agar lebih benar.
Toby Speight
Tidak tahu - saya sarankan Anda membuat contoh minimal yang dapat direproduksi dan memintanya (dengan asumsi bahwa prosesnya tidak cukup untuk membantu Anda menjawabnya sendiri).
Toby Speight
9

Parameter untuk mainmewakili parameter baris perintah yang disediakan untuk program ketika dimulai. The argcparameter mewakili jumlah argumen baris perintah, dan char *argv[]adalah array dari string (karakter pointer) mewakili argumen individu yang disediakan di baris perintah.

BlueMonkMN
sumber
2
Argv [] selalu memiliki argv [arg] sebagai pointer nol. dan Argv [0] selalu menjadi (path lengkap) / executableName sebagai string nul terminated
user3629249
3
@ user3629249: Tidak harus; argv[0]apa pun program yang meluncurkan program C memberikannya argv[0]. Dalam kasus Bash, seringkali (mungkin selalu) pathname dari executable, tetapi Bash bukan satu-satunya program yang mengeksekusi program lain. Hal ini permissisble, meskipun eksentrik, untuk menggunakan: char *args[] = { "cat", "/dev/null", "/etc/passwd", 0 }; execv("/bin/ls", args);. Pada banyak sistem, nilai yang dilihat oleh program argv[0]akan seperti itu cat, meskipun dieksekusi /bin/ls.
Jonathan Leffler
7

The mainFungsi dapat memiliki dua parameter, argcdan argv. argcadalah intparameter integer ( ), dan itu adalah jumlah argumen yang diteruskan ke program.

Nama program selalu merupakan argumen pertama, sehingga akan ada setidaknya satu argumen untuk suatu program dan nilai minimum argcakan menjadi satu. Tetapi jika suatu program memiliki dua argumen, nilainya argcakan menjadi tiga.

Parameter argvmenunjuk ke array string dan disebut vektor argumen . Ini adalah array string satu dimensi dari argumen fungsi.

moshtagh
sumber
5
int main();

Ini adalah deklarasi sederhana. Tidak dapat mengambil argumen baris perintah.

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

Deklarasi ini digunakan ketika program Anda harus mengambil argumen baris perintah. Ketika dijalankan seperti itu:

myprogram arg1 arg2 arg3

argc, atau Jumlah Argumen, akan ditetapkan ke 4 (empat argumen), dan argv, atau Vektor Argumen, akan diisi dengan pointer string ke "myprogram", "arg1", "arg2", dan "arg3". Doa program ( myprogram) termasuk dalam argumen!

Atau, Anda dapat menggunakan:

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

Ini juga valid.

Ada parameter lain yang dapat Anda tambahkan:

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

The envpparameter juga mengandung variabel lingkungan. Setiap entri mengikuti format ini:

VARIABLENAME=VariableValue

seperti ini:

SHELL=/bin/bash    

Daftar variabel lingkungan diakhiri null.

PENTING: JANGAN menggunakan nilai apa pun argvatau envplangsung dalam panggilan ke system()! Ini adalah lubang keamanan besar karena pengguna jahat dapat mengatur variabel lingkungan ke perintah baris perintah dan (berpotensi) menyebabkan kerusakan besar. Secara umum, jangan gunakan system(). Hampir selalu ada solusi yang lebih baik diimplementasikan melalui perpustakaan C.

adrian
sumber
3

Parameter pertama adalah jumlah argumen yang disediakan dan parameter kedua adalah daftar string yang mewakili argumen tersebut.

Nick Gerakines
sumber
7
entri pertama dalam argv [0] adalah nama program, bukan argumen
user3629249
@ user3629249 Nama program dengan jalur program. ;)
Master James
1

Keduanya

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

adalah definisi hukum dari titik masuk untuk program C atau C ++. Stroustrup: C ++ FAQ Gaya dan Teknik merinci beberapa variasi yang mungkin atau legal untuk fungsi utama Anda.

Chris Becke
sumber
4
Mungkin ingin membatalkan ... ... int main()==> int main(void)... untuk kompatibilitas dan keterbacaan. Saya tidak tahu apakah semua versi C yang lebih lama memungkinkan fungsi void memiliki daftar parameter kosong dalam deklarasi.
dylnmc
1
@dnmnmc ini tidak memberikan keuntungan keterbacaan apa pun, dan persis sama di semua versi C ++. Hanya di C ini memang memiliki perbedaan, tetapi hanya dalam deklarasi, bukan dalam definisi.
Ruslan
@ Ruslan Maaf, saya memposting ini ketika saya baru belajar C, dan saya mungkin telah membaca bahwa dalam versi awal C voiddiperlukan. Jangan mengutip saya tentang itu, dan saya sekarang tahu itu adalah komentar yang agak bodoh. Tidak ada ruginya.
dylnmc
bagaimana jika argc <3 mengembalikan kesalahan? apa yang mungkin salah?
AVI