C là một ngơn ngữ lập trình có cấu trúc, tuy vậy nó vẫn chứa một số câu lệnh làm phá vớ cấu trúc của chương trình:
Bài 9 Hàm Mục tiêu:
9.7.1 Biến tự động
Biến tự động thật ra là biến cục bộ mà chúng ta đã nói ở trên. Phạm vi của một biến tự động có thể nhỏ hơn hàm, nếu nó được khai báo bên trong một câu lệnh ghép: phạm vi của nó bị giới hạn trong câu lệnh ghép đó. Chúng có thể được khai báo bằng từ khóa auto, nhưng sự khai báo này là không cần thiết. Bất kỳ một biến được khai báo bên trong một hàm hoặc một khối lệnh thì mặc nhiên là thuộc lớp auto và hệ thống cung cấp vùng bộ nhớ được yêu cầu cho biến đó.
9.7.2 Biến ngoại
Trong C, một chương trình lớn có thể được chia thành các module nhỏ hơn, các module này có thể được biên dịch riêng lẻ và được liên kết lại với nhau. Điều này được thực hiện nhằm tăng tốc độ quá trình biên dịch các chương trình lớn. Tuy nhiên, khi các module được liên kết, các tập tin phải được chương trình thơng báo cho biết về các biến toàn cục được yêu cầu. Một biến tồn cục chỉ có thể được khai báo một lần. Nếu hai biến tồn cục có cùng tên được khai báo trong cùng một tập tin, một thông điệp lỗi ‘duplicate variable name’ (tên biến trùng) có thể được hiển thị hoặc đơn giản trình biên dịch C chọn một biến khác. Một lỗi tương tự xảy ra nếu tất cả các biến tồn cục được u cầu bởi chương trình chứa trong mỗi tập tin. Mặc dù trình biên dịch khơng đưa ra bất kỳ một thông báo lỗi nào trong khi biên dịch, nhưng sự thật các bản sao của cùng một biến đang được tạo ra. Tại thời điểm liên kết các tập tin, bộ liên kết sẽ hiển thị một thông báo lỗi như sau ‘duplicate label’ (nhãn trùng nhau) vì nó khơng biết sử dụng biến nào. Lớp extern được dùng trong trường hợp này. Tất cả các biến toàn cục được khai báo trong một tập tin và các biến giống nhau được khai báo là ở ngoài trong tất cả các tập tin. Xem đoạn mã lệnh sau:
int i,j; extern int i,j;
char a; extern char a;
main() xyz() { { . i = j * 5 . . . . } } abc() pqr() { { i = 123; j = 50; . . . . } }
File2 có các biến tồn cục giống như File1, ngoại trừ một điểm là các biến này có từ khóa extern
được thêm vào sự khai báo của chúng. Từ khóa này nói với trình biên dịch là tên và kiểu của biến tồn cục được sử dụng mà khơng cần phải tạo lại sự lưu trữ cho chúng. Khi hai module được liên kết, các tham chiếu đến các biến ngoại được giải quyết.
Nếu một biến không được khai báo trong một hàm, trình biên dịch sẽ kiểm tra nó có so khớp với bất kỳ biến tồn cục nào khơng. Nếu khớp với một biến tồn cục, thì trình biên dịch sẽ xem như một biến toàn cục đang được tham chiếu đến.
9.7.3 Biến tĩnh
Các biến tĩnh là các biến cố định bên trong các hàm và các tập tin. Không giống như các biến tồn cục, chúng khơng được biết đến bên ngoài hàm hoặc tập tin của chúng, nhưng chúng giữ được giá trị của chúng giữa các lần gọi. Điều này có nghĩa là, nếu một hàm kết thúc và sau đó được gọi lại, các biến tĩnh đã định nghĩa trong hàm đó vẫn giữ được giá trị của chúng. Sự khai báo biến tĩnh được bắt đầu với từ khóa static.
Có thể định nghĩa các biến tĩnh có cùng tên như hướng dẫn với các biến ngoại. Các biến cục bộ (biến tĩnh cũng như biến động) có độ ưu tiên cao hơn các biến ngoại và giá trị của các biến ngoại sẽ không ảnh hưởng bởi bất kỳ sự thay đổi nào các biến cục bộ. Các biến ngoại có cùng tên với các biến nội trong một hàm không thể được truy xuất trực tiếp bên trong hàm đó.
Các giá trị khởi tạo có thể được gán cho các biến trong sự khai báo các biến tĩnh, nhưng các giá trị này phải là các hằng hoặc các biểu thức. Trình biên dịch tự động gán một giá trị mặc nhiên 0 đến các biến tĩnh không được khởi tạo. Sự khởi tạo thực hiện ở đầu chương trình.
Xem hai chương trình sau. Sự khác nhau giữa biến cục bộ: tự động và tĩnh sẽ được làm rõ. Ví dụ về biến tự động: #include <stdio.h> main() { incre(); incre();
incre(); }
incre() {
char var = 65; /* var is automatic variable*/
printf(“\nThe character stored in var is %c”, var++); }
Kết quả của chương trình trên sẽ là:
The character stored in var is A The character stored in var is A The character stored in var is A Ví dụ về biến tĩnh: #include<stdio.h> main() { incre(); incre(): incre(): } incre() {
static char var = 65; /* var is static variable */ printf(“nThe character stored in var is %c”, var++); }
Kết quả của chương trình trên sẽ là:
The character stored in var is A The character stored in var is B The character stored in var is C
Cả hai chương trình gọi incre() ba lần. Trong chương trình thứ nhất, mỗi lần incre() được gọi, biến var với lớp lưu trữ auto (lớp lưu trữ mặc định) được khởi tạo lại là 65 (là mã ASCII tương ứng của ký tự A). Vì vậy khi kết thúc hàm, giá trị mới của var (66) bị mất đi (ASCII ứng với ký tự B).
Trong chương trình thứ hai, var là của lớp lưu trữ static. Ở đây var được khởi tạo là 65 chỉ một lần duy nhất khi biên dịch chương trình. Cuối lần gọi hàm đầu tiên, var có giá trị 66 (ASCII B)
và tương tự ở lần gọi kế tiếp var có giá trị 67 (ASCII C). Sau lần gọi hàm cuối cùng, var được tăng giá trị theo sự thi hành của lệnh printf(). Giá trị này bị mất khi chương trình kết thúc.