2011-08-11 49 views
11

Tôi đang học linux C++ lập trình khi tôi nhìn thấychar * const argv [] là gì?

int execve(const char *path, 
      char *const argv[], 
      char *const envp[]); 

Tôi không hiểu là những gì char *const argv[]. Tôi biết char *const foo là một con trỏ const đến char. Và const char *foo là một con trỏ đến một char char. Nhưng char *const argv[] là gì?

Đây có phải là một mảng các con trỏ const tới char hay một mảng con trỏ tới const char không?

Và bây giờ tôi có một số vector<string>, cách chuyển đổi thành char *const argv[]?

Trả lời

28

Có một mảng của con trỏ const char hoặc một mảng các con trỏ đến char const ?

loại đọc phải sang trái:
const luôn liên kết với bên trái (trừ khi nó còn đang ở rất trái)

char *const argv[] 

       ^^ Array of 
     ^^^^^  const 
    ^   pointer to 
^^^^    char 

Một mảng của "const pointer" để char

Vì vậy, các con trỏ trong không thể sửa đổi mảng.
Nhưng những gì họ chỉ vào có thể được sửa đổi.

Lưu ý: Như được chỉ ra bởi Steve bên dưới. Bởi vì điều này đang được sử dụng như một tham số. Nó thực sự phân rã thành "Con trỏ thành "const pointer" thành char" hoặc "char * const *".

Và tôi có một vector < chuỗi > bây giờ, cách chuyển đổi nó thành char * const argv []?

int execve(const char *path, 
     char *const argv[], 
     char *const envp[]); 

int main() 
{ 
    std::vector<std::string> data; /// fill 
    std::vector<char*>   argv; 
    std::vector<char*>   envp; 

    for(std::vector<std::string>::iterator loop = data.begin(); loop != data.end(); ++loop) 
    { 
     argv.push_back(&(*loop)[0]); 
    } 

    // I also bet that argv and envp need to be NULL terminated 
    argv.push_back(NULL); 
    envp.push_back(NULL); 
    execve("MyAppName", &argv[0], &envp[0]); 
} 
+2

+1 cho giải thích sơ đồ: D – Nawaz

+3

Đúng là 'char * const argv []' là một kiểu mảng, nhưng trong ngữ cảnh này, một tham số hàm, kiểu không phải là 'char * const argv []', nó là 'char * const * argv'. –

2

cdecl.org nói:

char *const argv[] 

tuyên bố argv như mảng của const con trỏ đến char

+0

và làm thế nào để chuyển đổi 'vector ' cho 'char * const argv []'? – Kaoet

+1

Cũng hữu ích: http://www.unixwiz.net/techtips/reading-cdecl.html –

+0

@MrPhone: Có thể đăng bài đó dưới dạng câu hỏi riêng. Nó đủ đơn giản, nhưng phải mất nhiều hơn một bình luận để viết ra. –

1
// says: argv is a constant pointer pointing to a char* 
int main(int c, char *const argv[]); 

Bạn sẽ không thể thay đổi "argv" bên trong hàm.

Vì bạn đang học C, tôi khuyên bạn nên thực sự cố gắng hiểu sự khác biệt giữa mảng và con trỏ đầu tiên thay vì những thứ phổ biến.

Trong khu vực tham số và mảng, có một vài quy tắc khó hiểu phải rõ ràng trước khi tiếp tục. Đầu tiên, những gì bạn khai báo trong một danh sách tham số được xử lý đặc biệt. Có những tình huống như vậy mà mọi thứ không có ý nghĩa như một tham số chức năng trong C.Đây là những

  • Chức năng như thông số
  • Mảng là tham số

Mảng là tham số

Thứ hai có lẽ là chưa rõ. Nhưng nó trở nên rõ ràng khi bạn xem xét rằng kích thước của một kích thước mảng là một phần của loại trong C (và một mảng có kích thước kích thước không được đưa ra có một loại không đầy đủ). Vì vậy, nếu bạn sẽ tạo ra một hàm nhận một mảng theo giá trị (nhận một bản sao), thì nó có thể làm như vậy chỉ cho một kích thước! Ngoài ra, mảng có thể trở nên lớn và C cố gắng càng nhanh càng tốt.

Trong C, vì những lý do này, mảng-giá trị không tồn tại. Nếu bạn muốn nhận được giá trị của một mảng, những gì bạn nhận được thay vào đó là một con trỏ đến phần tử đầu tiên của mảng đó. Và đây thực sự đã là giải pháp. Thay vì vẽ một tham số mảng không hợp lệ lên phía trước, một trình biên dịch C sẽ biến đổi kiểu của tham số tương ứng thành một con trỏ. Hãy nhớ điều này, nó rất quan trọng. Tham số sẽ không phải là một mảng, nhưng thay vào đó nó sẽ là một con trỏ đến kiểu phần tử tương ứng.

Bây giờ, nếu bạn cố gắng chuyển một mảng, những gì được truyền thay vào đó là một con trỏ đến phần tử đầu tiên của mảng.

Excursion: Chức năng như thông số

Đối hoàn thành, và bởi vì tôi nghĩ rằng điều này sẽ giúp bạn hiểu rõ hơn về vấn đề này, chúng ta hãy nhìn những gì tình trạng của vấn đề là khi bạn cố gắng để có một chức năng như một tham số. Thật vậy, đầu tiên nó sẽ không có ý nghĩa gì cả. Làm thế nào một tham số có thể là một hàm? Huh, tất nhiên chúng tôi muốn có một biến tại địa điểm đó! Vì vậy, những gì trình biên dịch hiện khi điều đó xảy ra là, một lần nữa, để biến đổi hàm thành một con trỏ hàm. Việc cố gắng chuyển một hàm sẽ chuyển một con trỏ tới hàm tương ứng đó. Vì vậy, sau đây là giống nhau (tương tự với ví dụ mảng):

void f(void g(void)); 
void f(void (*g)(void)); 

Lưu ý rằng dấu ngoặc đơn xung quanh *g là cần thiết. Nếu không, nó sẽ chỉ định một hàm trả về void*, thay vì một con trỏ tới hàm trả về void.

Về mảng

Bây giờ, tôi đã nói ngay từ đầu rằng mảng có thể có một loại không đầy đủ - đó sẽ xảy ra nếu bạn không cung cấp cho một kích thước được nêu ra. Vì chúng ta đã tìm ra rằng một tham số mảng không tồn tại nhưng thay vào đó bất kỳ tham số mảng nào là một con trỏ, kích thước của mảng không quan trọng. Điều đó có nghĩa, trình biên dịch sẽ dịch tất cả những điều sau đây, và tất cả là những điều tương tự:

int main(int c, char **argv); 
int main(int c, char *argv[]); 
int main(int c, char *argv[1]); 
int main(int c, char *argv[42]); 

Tất nhiên, nó không có ý nghĩa nhiều để có thể đặt bất kỳ kích thước trong nó, và nó chỉ ném xa. Vì lý do đó, C99 đã đưa ra một ý nghĩa mới cho những con số, và cho phép những thứ khác để xuất hiện giữa dấu ngoặc:

// says: argv is a non-null pointer pointing to at least 5 char*'s 
// allows CPU to pre-load some memory. 
int main(int c, char *argv[static 5]); 

// says: argv is a constant pointer pointing to a char* 
int main(int c, char *argv[const]); 

// says the same as the previous one 
int main(int c, char ** const argv); 

Hai dòng cuối cùng nói rằng bạn sẽ không thể thay đổi "argv" trong vòng chức năng - nó đã trở thành một con trỏ const. Chỉ vài trình biên dịch C hỗ trợ các tính năng C99 đó. Nhưng những tính năng này làm cho nó rõ ràng rằng "mảng" không thực sự là một. Đó là một con trỏ.

Một lời cảnh báo

Lưu ý rằng tất cả tôi đã nói ở trên là đúng chỉ khi bạn đã có một mảng như một tham số của một hàm. Nếu bạn làm việc với các mảng cục bộ, một mảng sẽ không phải là một con trỏ. Nó sẽ hoạt động như một con trỏ, vì như đã giải thích trước đó một mảng sẽ được chuyển đổi thành một con trỏ khi giá trị của nó được đọc. Nhưng nó không nên nhầm lẫn với con trỏ.

Một ví dụ điển hình như sau:

char c[10]; 
char **c = &c; // does not work. 

typedef char array[10]; 
array *pc = &c; // *does* work. 

// same without typedef. Parens needed, because [...] has 
// higher precedence than '*'. Analogous to the function example above. 
char (*array)[10] = &c; 
+0

Không chắc chắn lý do tại sao điều này đã được giảm giá hôm nay –

Các vấn đề liên quan