Mengapa kita membutuhkan argc sementara selalu ada nol di akhir argv?

117

Tampaknya argv[argc]selalu NULL, jadi saya pikir kita dapat melintasi daftar argumen tanpa argc. Satu whileputaran akan melakukan ini.

Jika selalu ada NULLdi akhir argv, mengapa kita membutuhkannya argc?

StarPinkER
sumber
17
Ini mungkin masalah kenyamanan. Memberi programmer cara mudah untuk melakukan bail out lebih awal jika tidak ada cukup argumen, tanpa perulangan. Kalau tidak, kami pasti akan memiliki fungsi yang disebut int argc(char *argv[])melakukan persis seperti ini :-))
cnicutar
5
Hanya untuk memperjelas "\0"tidak sama dengan penunjuk NULL ( 0setara dengan NULL di C ++)
Mats Petersson
31
Mengapa kita membutuhkan argv [argc] menjadi NULL jika kita memiliki argc?
Ambroz Bizjak
7
Bagaimana lagi Anda akan menentukan jumlah argumen dalam waktu yang konstan?
avakar
4
Jangan menganggap tag linux / unix sesuai di sini, karena perilaku ini harus benar untuk semua kompiler di semua sistem operasi.
Darrel Hoffman

Jawaban:

106

Ya, argv[argc]==NULLdijamin. Lihat C11 5.1.2.2.1 Memulai program (penekanan saya)

Jika mereka dideklarasikan, parameter ke fungsi utama harus mematuhi batasan berikut:

Nilai argc tidak boleh negatif. argv [argc] akan menjadi pointer nol.

Menyediakan argckarena itu tidak penting tapi masih berguna. Di antara hal-hal lain, ini memungkinkan untuk pemeriksaan cepat bahwa jumlah argumen yang benar telah diteruskan.

Edit: Pertanyaan telah diubah untuk menyertakan C ++. n3337 draft 3.6.1 Fungsi utama mengatakan

2 ... argc adalah jumlah argumen yang diteruskan ke program dari lingkungan tempat program dijalankan. .... Nilai argc tidak boleh negatif. Nilai argv [argc] harus 0 .

simonc
sumber
36
Dan argcbisa menjadi cukup besar, karena shell adalah melakukan ekspansi (sehingga di ls *dalam *diperluas oleh shell sebelum execvedari /bin/lsexecutable). Di sistem saya, saya dapat memiliki argcbeberapa ratus ribu.
Basile Starynkevitch
Itu cukup keren, ini tidak pernah terpikir oleh saya karena saya selalu dianggap argccukup, tetapi saya pasti dapat memikirkan situasi di mana jaminan ini akan relevan dan bahkan diperlukan. +1
Thomas
6
@BasileStarynkevitch Waktu hanya melangkah melalui sebuah array nilai pointer satu waktu ekstra sampai NULL, untuk mendapatkan hitungan, sangat kecil dibandingkan dengan waktu yang sudah dihabiskan untuk menghasilkan array pointer, dan bahkan lebih tidak relevan dibandingkan dengan benar-benar menggunakan setiap nilai argumen dalam program. Dan jika hanya memeriksa apakah jumlah argumen lebih dari N, maka seluruh array tidak diperlukan. Namun, saya sepenuhnya setuju, argcitu adalah hal yang baik.
hyde
43

Ya, argv[argc]dijamin penunjuk null. argcdigunakan untuk kenyamanan.

Mengutip penjelasan resmi dari C99 Rationale, perhatikan kata-kata redundant check :

Dasar Pemikiran untuk Standar Internasional - Bahasa Pemrograman - C §5.1.2.2.1 Memulai program

Spesifikasi argcdan argvsebagai argumen untuk mainmengakui praktik sebelumnya yang ekstensif. argv[argc]diperlukan untuk menjadi pointer nol untuk memberikan pemeriksaan yang berlebihan untuk akhir daftar, juga berdasarkan praktik umum.

Yu Hao
sumber
19

Ini karena alasan historis, dan kompatibilitas dengan kode lama. Awalnya, tidak ada jaminan bahwa akan ada pointer null sebagai elemen terakhir dari array argv. Tapi argc selalu ada.

zentrunix
sumber
... Yang memalukan, di satu sisi. Jika kita punya int main(char *argv[], int argc, ...), maka beberapa program bisa saja menghilangkannya argckarena mereka tidak membutuhkannya. Berlawanan (perlu argctetapi tidak argv) mungkin tidak pernah berguna dalam program nyata.
hyde
@hyde: lihat komentar di atas oleh Basile Starynkevitch
zentrunix
6

Kami "membutuhkan" itu, karena itu diharuskan oleh berbagai standar.

Kita bebas mengabaikan nilai sepenuhnya, tetapi karena ini adalah parameter pertama main, kita harus memilikinya dalam daftar parameter. Di C ++ (dan mungkin dialek C non-standar), Anda bisa menghilangkan nama parameter, seperti cuplikan C ++ ini (mudah diubah ke C):

#include <stdio.h> // C-compatible include, guarantees puts in global namespace

// program will print contents of argv, one item per line, starting from argv[0]

int main(int /*argc*/, char *argv[]) { // uncomment argc for C

    //(void)argc; // uncomment statement for C

    for (int i=0; argv[i]; ++i) {
        puts(argv[i]);
    }

    return 0;
}

Dalam standar C, dengan pengaturan peringatan umum, parameter yang tidak digunakan menghasilkan peringatan, yang dapat diperbaiki dengan pernyataan seperti (void)argc;yang menyebabkan nama digunakan tanpa membuat kode apa pun.

argcmenyenangkan untuk dimiliki, karena jika tidak, banyak program perlu berjalan melalui parameter untuk mendapatkan hitungannya. Juga, dalam banyak bahasa pemrograman dengan array yang memiliki panjang, tidak ada argcparameter apa pun , hanya ada array dengan itemnya.

hyde
sumber
Pertanyaannya adalah tentang C dan C ++. Di C, nama parameter harus diisi.