int argc, char * argv [] หมายถึงอะไร


508

ในหลาย C ++ IDE และคอมไพเลอร์เมื่อมันสร้างฟังก์ชั่นหลักสำหรับคุณดูเหมือนว่า:

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

เมื่อฉันใช้รหัส C ++ โดยไม่มี IDE เพียงแค่คอมไพเลอร์บรรทัดคำสั่งฉันพิมพ์:

int main()

ไม่มีพารามิเตอร์ใด ๆ สิ่งนี้หมายความว่าอะไรและมีความสำคัญต่อโปรแกรมของฉันหรือไม่


47
หากโปรแกรมของคุณกำลังเพิกเฉยต่ออาร์กิวเมนต์บรรทัดคำสั่งสิ่งที่คุณเขียนก็ไม่เป็นไร หากโปรแกรมของคุณต้องการประมวลผลอาร์กิวเมนต์บรรทัดคำสั่งแสดงว่า IDE ทำถูกต้อง
Jonathan Leffler

30
คำแนะนำสำหรับแฮ็กเกอร์: ลองประกาศint main(int argc, char* argv[], char* envp[])และพิมพ์อาร์กิวเมนต์สุดท้าย ;)
ulidtko

7
@ulidtko มันไม่ดีที่คุณกำลังสอนมือใหม่ที่จะแนะนำช่องโหว่ในโปรแกรมของพวกเขา;)
Gab是好人

13
@Gab การพิมพ์ตัวแปรสภาพแวดล้อมอย่างง่ายนำไปสู่ความเสี่ยงได้อย่างไร เพียงแค่ไม่ผ่านสตริงที่เสียทุกคำต่อการsystem()โทร DB แบบสอบถาม ฯลฯ ตามปกติด้วยการป้อนข้อมูลของผู้ใช้
ulidtko

2
@ulidtko ที่น่าสนใจ .. คุณช่วยอธิบายได้ไหมว่าทำไมคุณไม่ต้องผ่านสตริงที่ไม่บริสุทธิ์, เคียวรี db, ฯลฯ ขณะใช้char **envpอาร์กิวเมนต์?
ปรมาจารย์ James

คำตอบ:


651

argvและargcมีการส่งผ่านอาร์กิวเมนต์บรรทัดคำสั่งไปยังmain()ใน C และ C ++ อย่างไร

argcargvจะมีจำนวนของสตริงที่ชี้ไปตาม นี้จะ (ในทางปฏิบัติ) เป็น 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 มาตรฐาน ฉันไม่เคยได้ยินเกี่ยวกับระบบที่ทำสิ่งนี้ในทางปฏิบัติ แต่มันอาจมีอยู่จริงและจะไม่เป็นการละเมิดมาตรฐานใด ๆ
Chuck

77
@Chuck: เนื่องจาก "ค่าargv[argc]จะเป็น 0" (C ++ 03 §3.6.1 / 2) argvจึงไม่สามารถเป็นค่าว่างได้
James McNellis

20
@Chuck: C (อย่างน้อย C99) มีความต้องการเดียวกัน
James McNellis

2
คิดว่าฉันควรจะเพิ่มนี่คือสิ่งเดียวกันในระบบส่วนใหญ่ออกมีแม้ว่าพวกเขาจะใจลอยบางครั้ง ตัวอย่างเช่นใน Pascal / Delphi / Lazarus คุณจะได้รับ; ParamStr และ ParamCount (ถ้าหน่วยความจำทำหน้าที่ฉันถูกต้อง) ประเด็นของฉันคือเมื่อคุณ (ถ้าเคย) เขียนแอปพลิเคชั่นดั้งเดิมในภาษาอื่น ๆ / oses มีโอกาสที่ดีที่กำหนดไว้ข้างต้นสำหรับคุณที่จะใช้และพวกเขาทำงานอย่างสมบูรณ์แบบเดียวกัน (รายการนับ / สตริง) ในระบบทั้งหมดที่สนับสนุน พวกเขา
คริสเตียน

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'

หากคุณประกาศหลักของคุณเป็น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 (ส่วนขยายทั่วไป) มาตรฐานซี
Justin Time - Reinstate Monica

1
ขอบคุณสำหรับ pedantry ที่ดี @Justin คำตอบอัปเดตให้มีความถูกต้องมากขึ้น
Toby Speight

ไม่มีความคิด - ฉันแนะนำให้คุณสร้างตัวอย่างที่ทำซ้ำได้น้อยที่สุดและถามมัน (สมมติว่ากระบวนการไม่เพียงพอที่จะช่วยคุณตอบคำถามเอง)
Toby Speight

9

พารามิเตอร์ที่ใช้mainแทนพารามิเตอร์บรรทัดคำสั่งที่จัดเตรียมให้กับโปรแกรมเมื่อเริ่มทำงาน argcพารามิเตอร์หมายถึงจำนวนของการขัดแย้งบรรทัดคำสั่งและchar *argv[]เป็นอาร์เรย์ของสตริง (ชี้ตัวอักษร) เป็นตัวแทนของการขัดแย้งบุคคลที่มีให้บริการในบรรทัดคำสั่ง


2
Argv [] มี argv [arg] เป็นตัวชี้ว่างเสมอ และ Argv [0] จะเป็น (เต็มพา ธ ) / executableName เป็นสตริงที่สิ้นสุดด้วย nul
user3629249

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ได้
Jonathan Leffler

7

mainฟังก์ชั่นสามารถมีสองพารามิเตอร์และargc เป็นพารามิเตอร์จำนวนเต็ม ( ) และเป็นจำนวนอาร์กิวเมนต์ที่ส่งไปยังโปรแกรมargvargcint

ชื่อโปรแกรมมักเป็นอาร์กิวเมนต์แรกเสมอดังนั้นจะมีอาร์กิวเมนต์อย่างน้อยหนึ่งรายการในโปรแกรมและค่าต่ำสุด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    

รายการตัวแปรสภาพแวดล้อมสิ้นสุดด้วยค่า null

สำคัญ:อย่าใช้สิ่งใด ๆargvหรือenvpค่าโดยตรงในการโทรsystem()! นี่เป็นช่องโหว่ความปลอดภัยขนาดใหญ่เนื่องจากผู้ใช้ที่ประสงค์ร้ายสามารถตั้งค่าตัวแปรสภาพแวดล้อมเป็นคำสั่งบรรทัดคำสั่งและ (อาจ) ทำให้เกิดความเสียหายอย่างมาก system()โดยทั่วไปก็ไม่ได้ใช้ มีวิธีแก้ปัญหาที่ดีกว่าที่นำมาใช้ผ่านไลบรารี C เสมอ


3

พารามิเตอร์แรกคือจำนวนอาร์กิวเมนต์ที่ระบุและพารามิเตอร์ที่สองคือรายการของสตริงที่แสดงถึงอาร์กิวเมนต์เหล่านั้น


7
รายการแรกใน argv [0] คือชื่อโปรแกรมไม่ใช่อาร์กิวเมนต์
user3629249

@ user3629249 ชื่อโปรแกรมพร้อมเส้นทางโปรแกรม ;)
อาจารย์เจมส์

1

ทั้งสอง

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

เป็นข้อกำหนดทางกฎหมายของจุดเริ่มต้นสำหรับโปรแกรม C หรือ C ++ Stroustrup: สไตล์ C ++ และคำถามที่พบบ่อยเกี่ยวกับเทคนิครายละเอียดของรูปแบบที่เป็นไปได้หรือถูกกฎหมายสำหรับฟังก์ชันหลักของคุณ


4
อาจต้องการใส่ช่องว่างใน ... int main()==> int main(void)... เพื่อความเข้ากันได้และการอ่านได้ ฉันไม่ทราบว่า C เวอร์ชั่นเก่าทั้งหมดอนุญาตให้ฟังก์ชัน void มีรายการพารามิเตอร์ว่างในการประกาศหรือไม่
dylnmc

1
@dylnmc สิ่งนี้ไม่ให้ความสามารถในการอ่านใด ๆ และเทียบเท่าในทุกเวอร์ชัน C ++ เฉพาะใน C เท่านั้นที่มีความแตกต่าง แต่เฉพาะในการประกาศไม่ใช่ในการกำหนด
Ruslan

@ Ruslan ขออภัยฉันโพสต์สิ่งนี้เมื่อฉันเพิ่งเรียนรู้ C และฉันอาจได้อ่านว่าในรุ่นแรก ๆ ของ C voidจำเป็นต้องมี อย่าอ้างฉันในเรื่องนี้และตอนนี้ฉันรู้ว่ามันเป็นความคิดเห็นที่โง่เล็กน้อย แต่ก็ไม่สามารถทำร้ายได้
dylnmc

ถ้า argc <3 ส่งคืนข้อผิดพลาดล่ะ สิ่งที่อาจผิดพลาด?
AVI
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.