Khác biệt giữa bản sửa đổi của “C (ngôn ngữ lập trình)”

Nội dung được xóa Nội dung được thêm vào
svvsrgasvs
Dòng 3:
'''Ngôn ngữ lập trình C''' là một ngôn ngữ [[lập trình kiểu mệnh lệnh|mệnh lệnh]] được phát triển từ đầu [[thập niên 1970]] bởi [[Ken Thompson]] và [[Dennis Ritchie]] để dùng trong [[hệ điều hành]] [[Unix|UNIX]]. Từ dó, ngôn ngữ này đã lan rộng ra nhiều hệ điều hành khác và trở thành một những ngôn ngữ phổ dụng nhất. C là ngôn ngữ rất có hiệu quả và được ưa chuộng nhất để viết các [[phần mềm hệ thống]], mặc dù nó cũng được dùng cho việc viết các [[phần mềm ứng dụng|ứng dụng]]. Ngoài ra, C cũng thường được dùng làm phương tiện giảng dạy trong [[khoa học máy tính]] mặc dù ngôn ngữ này không được thiết kế dành cho người nhập môn.
 
Alo
== Các đặc csaafsrgđ ==
=== Tổng quan ===
C là một [[ngôn ngữ lập trình]] tương đối nhỏ gọn vận hành gần với phần cứng và nó giống với ngôn ngữ [[Assembler]] hơn hầu hết các [[ngôn ngữ bậc cao]]. Hơn thế, C đôi khi được đánh giá như là "có khả năng di động", cho thấy sự khác nhau quan trọng giữa nó với [[ngôn ngữ lập trình bậc thấp|ngôn ngữ bậc thấp]] như là Assembler, đó là việc mã C có thể được dịch và thi hành trong hầu hết các máy tính, hơn hẳn các ngôn ngữ hiện tại trong khi đó thì Assembler chỉ có thể chạy trong một số máy tính đặc biệt. Vì lý do này C được xem là [[ngôn ngữ bậc trung]].
 
C đã được tạo ra với một mục tiêu là làm cho nó thuận tiện để viết các chương trình lớn với số lỗi ít hơn trong [[mẫu hình]] [[lập trình thủ tục]] mà lại không đặt gánh nặng lên vai người viết ra [[trình biên dịch|trình dịch]] C, là những người bề bộn với các đặc tả phức tạp của ngôn ngữ. Cuối cùng C có thêm những chức năng sau:
* Một [[ngôn ngữ cốt lõi]] đơn giản, với các chức năng quan trọng chẳng hạn như là những hàm hay việc xử lý tập tin sẽ được cung cấp bởi các bộ [[thư viện (khoa học máy tính)|thư viện các thủ tục]].
* Tập trung trên mẫu hình [[lập trình thủ tục]], với các phương tiện lập trình theo kiểu [[lập trình cấu trúc|cấu trúc]].
* Một hệ thống kiểu đơn giản nhằm loại bỏ nhiều phép toán không có ý nghĩa thực dụng.
* Dùng ngôn ngữ [[tiền xử lý]], tức là các câu lệnh [[tiền xử lý C]], cho các nhiệm vụ như là định nghĩa các [[macro]] và hàm chứa nhiều tập tin [[mã nguồn]] (bằng cách dùng câu lệnh tiền xử lý dạng <code>#include</code> chẳng hạn).
* Mức thấp của ngôn ngữ cho phép dùng tới [[bộ nhớ|bộ nhớ máy tính]] qua việc sử dụng kiểu dữ liệu <code>pointer</code>.
* Số lượng từ khóa rất nhỏ gọn.
* Các [[tham số (khoa học máy tính)|tham số]] được đưa vào các hàm bằng giá trị, không bằng địa chỉ.
* Hàm các con trỏ cho phép hình thành một nền tảng ban đầu cho [[tính đóng (ngôn ngữ lập trình|tính đóng]] và [[tính đa hình]].
* Hỗ trợ các [[Bản ghi (ngôn ngữ lập trình)|bản ghi]] hay các kiểu dữ liệu kết hợp do người dùng từ khóa định nghĩa <code>struct</code> cho phép các dữ liệu liên hệ nhau có thể được tập hợp lại và được điều chỉnh như là toàn bộ.
 
Một số chức năng khác mà C không có (hay còn thiếu) nhưng có thể tìm thấy ở các ngôn ngữ khác bao gồm:
* [[An toàn kiểu]],
* Tự động [[Thu dọn rác (ngôn ngữ lập trình)|Thu dọn rác]],
* Các [[lớp (khoa học máy tính)|lớp]] hay các [[Đối tượng (OOP)|đối tượng]] cùng với các ứng xử của chúng (xem thêm [[Lập trình hướng đối tượng|OOP]]),
* Các [[hàm lồng nhau]],
* [[Lập trình tiêu bản]] hay [[Lập trình tiêu bản|Lập trình phổ dụng]],
* [[Quá tải (ngôn ngữ lập trình)|Quá tải]] và [[Quá tải toán tử]],
* Các hỗ trợ cho [[đa luồng]], [[đa nhiệm]] và [[mạng máy tính|mạng]].
 
Mặc dù C còn thiếu nhiều chức năng hữu ích nhưng lý do quan trọng để C được chấp nhận vì nó cho phép các trình dịch mới được tạo ra một cách nhanh chóng trên các nền tảng mới và vì nó cho phép [[lập trình viên|người lập trình]] dễ kiểm soát được những gì mà chương trình (do họ viết) thực thi. Đây là điểm thường làm cho mã C chạy hiệu quả hơn các ngôn ngữ khác. Thường thì chỉ có ngôn ngữ [[ASM]] chỉnh bằng tay chạy nhanh hơn (ngôn ngữ C), bởi vì ASM kiểm soát được toàn bộ máy. Mặc dù vậy, với sự phát triển các trình dịch C, và với sự phức tạp của các [[CPU]] hiện đại, C đã dần thu nhỏ khoảng cách khác biệt về vận tốc này.
 
Một lý do nữa cho việc C được sử dụng rộng rãi và hiệu quả là do các trình dịch, các thư viện và các [[phần mềm thông dịch]] của các ngôn ngữ bậc cao khác lại thường được tạo nên từ C.
 
=== Thí dụ "hello, world" ===
Thí dụ đơn giản sau đây được thấy trong lần in đầu tiên của cuốn "[[The C Programming Language]]", và đã trở thành bài tiêu chuẩn trong chương nhập môn của hầu hết các loại sách giáo khoa về lập trình. Chương trình hiển thị câu "hello, world!" trên [[đầu ra chuẩn]], mà thường là một màn hình. Mặc dù vậy, nó có thể xuất ra một tập tin hay xuất ra trên một thiết bị phần cứng kể cả trên một [[vùng chứa]], tùy thuộc vào việc đầu ra chuẩn được chỉ thị vào đâu khi chương trình này được thực thi.
 
<source lang="c" line style="font-size:1.2em;" >
#include <stdio.h>
 
int main(void)
{
printf("hello, world!");
return 0;
}
</source>
 
Chương trình trên sẽ dịch đúng trong hầu hết các trình dịch hỗ trợ chuẩn [[ANSI C]] hay chuẩn [[#C99|C99]].
 
Sau đây là các phân tích theo từng dòng mã của thí dụ trên
 
<source lang="c" line start="1" style="font-size:1.2em;" >
#include <stdio.h>
</source>
 
<div id="INCLUDE">Dòng đầu tiên này là một chỉ thị [[tiền xử lý]] <code>#include</code>. Điều này sẽ làm cho bộ tiền xử lý (bộ tiền xử lý này là một công cụ để kiểm tra mã nguồn trước khi nó được dịch) tiến hành thay dòng lệnh đó bởi toàn bộ các dòng mã hay thực thể trong tập tin mà nó đề cập đến (tức là tập tin <code>stdio.h</code>). Dấu ngoặc nhọn bao quanh <code>stdio.h</code> cho biết rằng tập tin này có thể tìm thấy trong các nơi đã định trước cho bộ tiền xử lý biết thông qua các ''đường tìm kiếm'' đến các tập tin <code>header</code>. Tập hợp các tập tin được khai báo sử dụng qua các chỉ thị tiền xử lý còn được gọi là '''các tập tin bao gồm'''.</div>
 
<source lang="c" line start="3" style="font-size:1.2em;" >
int main(void)
</source>
 
<div id="MAIN">Dòng trên biểu thị một hàm chuẩn tên <code>main</code>. Hàm này có mục đích đặc biệt trong C. Khi chương trình thi hành thì hàm <code>main()</code> được gọi trước tiên. Phần mã <code>int</code> chỉ ra rằng ''giá trị trả về'' của hàm <code>main</code> (tức là giá trị mà <code>main()</code> sẽ được trả về sau khi thực thi) sẽ có kiểu là một số nguyên. Còn phần mã <code>(void)</code> cho biết rằng hàm <code>main</code> sẽ không cần đến tham số để gọi nó. Xem thêm [[Void (kiểu dữ liệu)|Void]]</div>.
 
<source lang="c" line start="4" style="font-size:1.2em;" >
{
</source>
 
Dấu '{' cho biết sự bắt đầu của định nghĩa của hàm <code>main</code>.
 
<source lang="c" line start="5" style="font-size:1.2em;" >
printf("hello, world\n");
</source>
 
Dòng trên gọi đến một hàm chuẩn khác tên là <code>[[printf]]</code>. Hàm này đã được khai báo trước đó trong trong tập tin <code>stdio.h</code>. Dòng này sẽ cho phép tìm và thực thi mã (đã được hỗ trợ sẵn) với ý nghĩa là hiển thị lên đầu ra chuẩn dòng chữ <br /><code> hello, world<kí tự xuống dòng EOL-chuyển dấu nhắc sang dòng mới></code>.<br />Mã kí tự <code>\n</code> là một ''dãy thoát'' được chuyển dịch thành dấu kí tự EOL (viết tắt từ chữ ''End-Of-Line'') có nghĩa là chuyển vị trí [[dấu nhắc]] xuống đầu một dòng kế. Gía trị trả về của hàm <code>printf</code> (theo khai báo nguyên mẫu chuẩn của hàm này trong C) có kiểu <code>int</code>, nhưng vì giá trị trả về này không được (người lập trình) dùng tới nên giá trị đó bị bỏ qua (một cách lặng lẽ).
 
<source lang="c" line start="7" style="font-size:1.2em;" >
return 0;
</source>
 
Dòng này sẽ kết thúc việc thực thi mã của hàm <code>main</code> và buộc nó trả về giá trị 0 (là một số nguyên như khai báo ban đầu <code> int main </code>).
 
<source lang="c" line start="8" style="font-size:1.2em;" >
}
</source>
 
Dấu '}' cho biết việc kết thúc mã cho hàm <code>main</code>.
 
=== Các kiểu ===
C có một hệ thống kiểu tương tự như của [[Pascal (ngôn ngữ lập trình)|Pascal]], mặc dù chúng khác nhau trong một số khía cạnh. Có nhiều kiểu cho các số nguyên với nhiều cỡ cho có đấu và không có dấu, có kiểu số [[floating point]], kiểu các kí tự <code>char</code>, các kiểu thứ tự <code>enum</code>, kiểu bản ghi <code>record</code> và kiểu đơn vị <code>union</code>.
 
C tạo ra sự mở rộng mạnh mẽ việc sử dụng của kiểu các con trỏ <code>[[pointer]]</code>, một dạng đơn giản các [[tham chiếu (ngôn ngữ lập trình)|tham chiếu]] mà chúng chứa địa chỉ các vùng nhớ. Các con trỏ có thể được ''tham chiếu ngược'' (''dereference'') để lấy về giá trị của dữ liệu được chứa trong địa chỉ đó (địa chỉ mà con trỏ chỉ vào). Địa chỉ này có thể được điều chỉnh bằng các phép gán thông thường và các [[phép toán số học trên con trỏ]]. Trong thời gian thực thi, một con trỏ đại diện cho một địa chỉ của bộ nhớ. Trong thời gian chuyển dịch, nó là một kiểu phức tạp đại diện cho cả địa chỉ và kiểu của dữ liệu. Điều này cho phép các biểu thức bao gồm các con trỏ được kiểm tra về kiểu. Các con trỏ thì được dùng cho nhiều mục tiêu trong C. Các dòng kí tự <code>string</code> thường được đại diện bởi một con trỏ chỉ tới một dãy của các kí tự. Sự [[cấp phát bộ nhớ động]], được miêu tả sau đây, thì được tiến hành thông qua các con trỏ.
 
Một ''[[con trỏ rỗng]]'' có nghĩa là nó không chỉ đến một chỗ nào hết. Điều này có ích trong những trường hợp như là con trỏ <code>''next''</code> trong một nút cuối của một [[danh sách liên kết]] <code>linked list</code>. Việc tham chiếu ngược một con trỏ trống gây ra các biểu hiện không dự đoán trước được. Các con trỏ kiểu <code>void</code> thì lại có thể chỉ đến một đối tượng mà không cần biết kiểu của đối tượng đó. Điều này đặc biệt hữu dụng trong [[lập trình tiêu bản]] bởi vì cỡ và kiểu của các đối tượng mà chúng chỉ tới thì không thể biết được và do đó không thể thực hiện tham chiếu ngược, nhưng chúng lại có thể được hoán chuyển thành các con trỏ của các kiểu khác.
 
Các kiểu mảng <code>array</code> trong C thì có cỡ cố định, độ lớn tĩnh của nó phải được biết trước trong thời gian chuyển dịch. Điều này gây nhiều trở ngại trong thực tế bởi vì người ta có thể chỉ định các vùng nhớ ở thời gian thực thi dựa trên các thư viện chuẩn và hành xử chúng như là các mảng. Không như các ngôn ngữ khác, C biểu thị các mảng giống như trường hợp các con trỏ: chúng đóng vai trò một địa chỉ của bộ nhớ và một kiểu dữ liệu. Do đó, các giá trị chỉ số có thể vượt quá cỡ của một mảng.
 
C cũng cung cấp các kiểu mảng đa chiều. Các giá trị chỉ số của các mảng đa chiều thì được gán theo thứ tự hàng chính. Một cách có ý nghĩa thì các mảng này hoạt động như là mảng của các mảng nhưng thực chất chúng được phân bố như là mảng một chiều với việc tính và tạo các vị trí tương đối.
 
C thường được dùng trong việc lập trình các hệ thống bậc thấp, ở đó có thể cần thiết để xem số nguyên như là một địa chỉ của bộ nhớ, là một giá trị ''double precision'', hay là một kiểu con trỏ. Trong các trường hợp này, C cung cấp việc ''hoán chuyển'', mà phép toán này sẽ bắt buộc chuyển đổi giá trị từ một kiểu sang một kiểu khác. Dùng phép ''hoán chuyển'' sẽ làm mất đi phần nào tính an toàn mà thường được cung cấp bởi hệ thống kiểu.
 
=== Lưu trữ dữ liệu ===
Một trong những chức năng quan trọng nhất của một ngôn ngữ lập trình là việc cung cấp cơ sở cho việc quản lý [[bộ nhớ (máy tính)|bộ nhớ]] và các đối tượng được chứa trong bộ nhớ. C cung ứng 3 phương cách để cấp phát bộ nhớ cho các đối tượng:
# <div id="STAT">Sự [[cấp phát vùng nhớ tĩnh]]: khoảng trống dành cho đối tượng thì được cung cấp trong phần mã nhị phân ở thời gian dịch; những đối tượng này có một thời gian sống lâu dài theo sự tồn tại của phần mã nhị phân chứa chúng (các đối tượng).</div>
# <div id="AUTO">Sự [[cấp phát vùng nhớ tự động]]: Các đối tượng tạm thời có thể được chứa trong một chồng (''stack''), và khoảng trống này thì được trả về một cách tự động và có thể được dùng lại sau khi khối mã mà chúng (tức các đối tượng tạm thời) được khai báo đã thực thi xong.</div>
# <div id="DYNAMIC"> Sự [[cấp phát vùng nhớ động]]: Các khối của bộ nhớ với bất kì cỡ lớn mong muốn nào đều có thể được yêu cầu (hay xin) trong thời gian thi hành bằng cách dùng các hàm thư viện như là <code>[[malloc|malloc()]]</code>, <code>[[malloc|realloc()]]</code> và <code>[[malloc|free()]]</code> từ một khu vực của bộ nhớ có tên là [[dynamic memory allocation|heap]]; các khối này có thể được tái dụng sau khi gọi hàm <code>[[malloc|free()]]</code> để hoàn trả chúng lại cho bộ nhớ.</div>
 
Ba phương án này thích hợp cho các tình huống khác nhau và có những hậu quả khác nhau. Thí dụ, kiểu cấp phát tĩnh sẽ không cần thời gian (để tính toán) cho sự cấp phát, kiểu cấp phát tự động sẽ cần một khoảng thời gian nào đó cho dự tính, và kiểu cấp phát động có thể đòi hỏi một lượng lớn thời gian dùng dễ tính toán cho việc cấp phát và hoàn trả (các vùng nhớ đã được yêu cầu trước đó). Mặt khác, khoảng trống của chồng thường giới hạn cho vùng nhớ tĩnh hay cho khoảng trống của heap, và chỉ kiểu cấp phát vùng nhớ động là cho phép sự cấp phát cho các đối tượng mà kích thước của nó chỉ có thể biết được trong lúc thi hành. Hầu hết các chương trình C đều dùng nhiều cả ba phương cách này.
 
Khi có thể thì sự cấp phát tự động hay sự cấp phát tĩnh thường được dề nghị dùng vì kho nhớ được quản lý bởi trình dịch, giải phóng cho người lập trình những lồi lầm phiền hà khi phải xin cấp phát và hoàn trả các vùng nhớ bằng tay. Rất tiếc nhiều cấu trúc dữ liệu có thể trương nở trong thời gian thực thi và vì kiểu cấp phát tĩnh và kiểu tự động phải có một độ lớn cố định ở thời gian dịch nên trong nhiều tình huống mà buộc phải dùng kiểu cấp phát động. Các dãy thay đổi về độ lớn là một thí dụ điển hình của trường hợp này. (Xem thí dụ từ bài [[malloc]] về các dãy được cấp phát vùng nhớ động.)
 
== Cú pháp ==