Skip to content
Narrow screen resolution Wide screen resolution Auto adjust screen size Increase font size Decrease font size Default font size default color grey color
         
 | 
VNOI - Olympic tin học Việt Nam

Điểm tin VOJ

Số thành viên:6040
Số bài tập:1001
Số bài nộp:722923
Bài nộp hôm nay:0

Top 10 thành viên xuất sắc

HạngThành viênĐiểm
1mr_invincible587.9
2white_cobra418.6
3hieult403.4
4phaleq384.0
5vodanh9x368.2
6con_nha_ngheo352.0
7flash_mt350.2
8darksabers349.8
9yenthanh132345.3
10rockman9x_94343.1
Từ Pascal đến C (1) In E-mail
(39 votes)
Người viết: Ngô Minh Đức   
24/03/2008
TỪ PASCAL ĐẾN C

Mở đầu

Hầu hết chúng ta đều biết và sử dụng ngôn ngữ lập trình Pascal. Đó là ngôn ngữ được sử dụng nhiều nhất trong các kì thi tin học ở nước ta hiện nay. Tuy nhiên, C cũng là một ngôn ngữ được sử dụng rộng rãi để giải các bài tóan tin học; đôi khi nó cung cấp một số thuận lợi nhất định so với Pascal.

Bài viết này sẽ giúp các bạn nắm được các khái niệm cơ bản của C, thông qua đối chiếu với ngôn ngữ Pascal, từ đó áp dụng vào việc giải các bài tóan tin học. Sau khi đọc xong bài viết này, bạn cũng có thể chuyển đổi một chương trình giải tóan bằng Pascal sang ngôn ngữ C.

Nếu bạn đã thông thạo ngôn ngữ Pascal, thì bài viết này sẽ giúp bạn hiểu C nhanh chóng hơn việc đọc tòan bộ một quyển giáo trình dạy C.

Giới thiệu sơ lược

Đều là những ngôn ngữ lập trình có cấu trúc nên mỗi khái niệm trong Pascal có một khái niệm tương ứng , hoặc tương tự, trong C; chỉ có cú pháp, câu lệnh là khác nhau. C tương đối khó hơn vì cú pháp của nó tự do hơn, dẫn đến những lỗi khó phát hiện trong khi viết chương trình.

Trong bài viết này, bạn cũng gặp một số khái niệm của ngôn ngữ C mà Pascal không có. Phần lớn những khái niệm này liên quan đến con trỏ (pointer).

 

Một số lưu ý cơ bản:

  1. C không cho phép các thủ tục lồng nhau, vì vậy bạn phải lọai bỏ các thủ tục lồng nhau trong chương trình Pascal trước khi chuyển nó sang ngôn ngữ C

  2. Ngôn ngữ C phân biệt ký tự thường và ký tự hoa: AAA, aaa và Aaa là 3 tên gọi khác nhau. Để tiện lợi, người ta thường ký hiệu các hằng bằng ký tự hoa, các biến bằng ký tự thường. Các từ khóa của C luôn luôn được kí hiệu bằng các chữ cái thường.

 

Một chương trình đơn giản

Dưới đây là một chương trình C rất đơn giản tính giai thừa của 6. Bạn nên gõ lại chứ đừng copy đọan mã; như thế sẽ giúp bạn thuộc cú pháp của C nhanh hơn.

#include <stdio.h> 

#define VALUE 6 

int i,j;

void main() 

{   

    j=1;   

    for (i=1; i<=VALUE; i++)     

        j=j*i;   

    printf("Giai thừa của %d là %d\n",VALUE,j); 

}

 

Và đây là đọan chương trình Pascal tương ứng:

program samp;

const value=6; 

var i,j:integer; 

begin   

    j:=1;   

    for i:=1 to value do     

        j:=j*i;   

    writeln('Giai thừa của ',value,' là ',j); 

end.

 

Bạn có thể thấy tương ứng 1-1 giữa những câu lệnh. Khác biệt duy nhất là đọan chương trình C bắt đầu bằng #include <stdio.h>. Dòng này đưa thư viện I/O chuẩn vào chương trình để bạn có thể đọc/viết các giá trị, xử lý file văn bản, v.v... C có rất nhiều các thư viện chuẩn như stdio, string, time, math, v.v...

Dòng #define định nghĩa một hằng. Lệnh int i,j; khai báo 2 biến tòan cục kiểu số nguyên Các kiểu dữ liệu thông dụng khác là float (số thực), char (ký tự), cả hai đều có thể định nghĩa theo cùng cú pháp như trên.

Dòng main() khai báo thủ tục chính. Mọi chương trình C đều phải có một thủ tục có tên “main”. Trong C, { } thay thế cho beginend của Pascal, = thay thế cho :=. Vòng lặp for và lệnh printf hơi lạ một chút, nhưng chúng có cùng chung chức năng như các dòng lệnh tương ứng trong chương trình Pascal. Lưu ý C sử dụng dấu ngoặc kép thay vì dấu nháy đơn ( )  đối với chuỗi ký tự.

Khi bạn quen, lệnh printf của C sẽ dễ sử dụng hơn lệnh write trong Pascal. Phần trong dấu ngoặc kép được gọi là chuỗi định dạng (format string); nó mô tả dữ liệu được định dạng thế nào khi viết ra. Chuỗi định dạng chứa những chữ như Giai thừa của , \n (kí tự xuống dòng), và các tóan tử xác định vị trí của các biến. Hai tóan tử trong chuỗi định dạng trên (%d %d) cho biết các giá trị nguyên trong chuỗi tham số phía sau sẽ được in ra tại vị trí này. Có những tóan tử khác dành cho số thực, kí tự, chuỗi, v.v... Bạn có thể dùng phần hướng dẫn của Turbo C chẳng hạn để xem danh sách các tóan tử này. Một điều quan trọng là các tham số đi đằng sau phải có kiểu đúng như các tóan tử trong chuỗi định dạng. Ví dụ bạn không thể viết %d nhưng tham số tương ứng đằng sau lại là một biến kiểu float.

Chương trình trên chạy tốt, nhưng có thể được cải tiến bằng cách đọc thẳng giá trị thay vì sử dụng hằng số. Bạn hãy sửa lại chương trình, lọai bỏ hằng VALUE, thay vào đó khai báo value như một biến tòan cục. Sau đó thêm hai dòng sau vào đầu thủ tục main:

printf("Nhập giá trị:"); 

scanf("%d",&value);

 

Đọan mã tương ứng trong Pascal như sau:

write('Nhập giá trị:'); 

readln(value);

 

Lệnh scanf cùng sử dụng một kiểu chuỗi định dạng như printf (bạn hãy xem phần help để biết thêm chi tiết). Bạn cũng cần lưu ý dấu & trước biến value. Đây là tóan tử địa chỉ (address operator) của C: nó trả về địa chỉ của biến; nhưng chúng ta sẽ bàn điều này sau khi đề cập đến kiểu con trỏ. Bạn phải sử dụng dấu & trong lệnh scanf trước bất kỳ biến nào kiểu char, int, float, hoặc kiểu những kiểu record (chúng ta sẽ để cập kiểu record sau). Nếu bạn gõ thiếu dấu &, bạn sẽ gặp lỗi “segmentation fault” khi chạy chương trình.

 

Những lỗi cần tránh:

- Quên dấu & trong lệnh scanf

- Quên dấu */ ở cuối của dòng chú thích

 

Cấu trúc rẽ nhánh và vòng lặp

Các câu lệnh điều kiện if và vòng lặp while trong C cũng dựa trên ý tưởng về các biểu thức Boolean như trong Pascal. Tuy nhiên trong C không có kiểu Boolean một cách tường minh- bạn phải sử dụng kiểu số nguyên để thay thế. Trong C, số 0 được hiểu là false và các số nguyên còn lại được hiểu là true.

Dưới đây là một đọan chương trình đơn giản được dịch từ Pascal sang C.

Đọan mã Pascal:

if (x=y) and (j>k) then     

    z:=1 

else   

    q:=10;

 

Đọan mã C trông rất giống, nhưng có một số điểm khác biệt quan trọng:

if ((x==y) && (j>k))   

    z=1; 

else   

    q=10;

 

Lưu ý dấu = trong Pascal trở thành dấu = = trong C. Đây là một khác biệt rất quan trọng, bởi vì C vẫn chấp nhận dấu = thông thường ở vị trí này khi bạn biên dịch chương trình, nhưng nó sẽ thực thi rất khác khi chạy. Tóan tử and trong Pascal trở thành && trong C. Bạn cũng cần lưu ý rằng trong C có một dấu chấm phẩy sau câu lệnh z=1, không có từ khóa then, và biểu thức Boolean phải được đặt hòan tòan trong những dấu ngoặc.

Bảng sau cho thấy những cặp tóan tử tương ứng trong Pascal và C:

Pascal

C

=

==

< 

< 

> 

> 

<=

<=

>=

>=

<> 

!=

AND

&&

OR

||

NOT

!

Có một vấn đề là bạn có thể quên mà đánh dấu = thay vì = = . Bởi vì số nguyên thay thế cho kiểu Boolean, nên câu lệnh sau hợp lệ trong C:

void main() 

{   

    int a;

    

    printf("Nhập một số:");   

    scanf("%d", &a);   

    if (a)   

    {     

        ...

    } 

}

 

Nếu a là một số khác 0, đọan code trong cặp dấu { } thứ hai sẽ được thực thi. Giả sử bạn có câu lệnh sau trong Pascal:

if a=b then

 

bạn dịch sang C thành:

if (a=b)  /* câu lệnh đúng là "if (a==b)" */

 

Trong C, câu lệnh này có nghĩa là: “Gán b cho a, rồi kiểm tra giá trị Boolean của a”. Nếu a bằng 0 thì câu lệnh if là false; còn ngược lại thì nó là true. Đây là một thực thi không mong đợi của chương trình; vì vậy tốt hơn hết bạn nên cẩn thận với dấu = và = =.

 

Câu lệnh while cũng dễ chuyển đổi. Chẳng hạn, đọan mã Pascal sau:

while a < b do 

begin   

    ...

end;

 

Ta có đọan chương trình C tương ứng

while (a < b) 

{   

    ...

}

 

C cũng cung cấp một cấu trúc “do-while” để thay thể cho cấu trúc “repeat-until” của Pascal:

do 

{   

    ...

} 

while (a < b);

 

Vòng lặp for trong C hơi khác một chút so với Pascal, bởi vì nó chỉ là một cách viết gọn của câu lệnh while. Ví dụ như chúng ta có đọan mã C sau:

x=1; 

while (x<10) 

{   

    ...

    x++; /* x++ tương đương với x=x+1 */ 

}

 

Bạn có thể chuyển đọan chương trình trên thành một vòng lặp for như sau:

for(x=1; x<10; x++) 

{   

    ...

}

 

Lưu ý rằng vòng lặp while gồm 3 bước, bước khởi tạo (x=1), bước kiểm tra (x<10), và bước gia giảm (x++). Câu lệnh for cho phép bạn đưa cả ba bước vào một dòng lệnh; thế nhưng ngòai ra bạn có thể đặt bất kỳ thứ gì vào ba phần này. Chẳng hạn bạn có vòng lặp sau:

a=1; 

b=6; 

while (a < b) 

{   

    a++;   

    printf("%d\n",a); 

}

 

Bạn có thể đưa tất cả vào một câu lệnh for:

for (a=1,b=6; a < b; a++,printf("%d\n",a));

 

Những lệnh như thế này thường gây rắc rối trong việc đọc và hiệu chỉnh chương trình; có lẽ bạn nên tránh sử dụng chúng.

 

Những lỗi cần tránh:

- Viết nhầm dấu = thay vì muốn viết = = trong câu lệnh if hoặc while

- Vô tình đặt dấu ; ở cuối câu lệnh for hoặc if, dẫn đến câu lệnh mất tác dụng. Ví dụ đọan chương trình:

for (x=1; x<10; x++);   

    printf("%d\n",x);

sẽ chỉ in ra một giá trị bởi vì có dấu ; đằng sau lệnh for.

 

Sử dụng mảng

Trong phần này, bạn sẽ viết một chương trình tạo ra 10 số ngẫu nhiên và sau đó sắp xếp chúng:

 

#include <stdio.h>

 

#define MAX 10

 

int a[MAX];

int rand_seed=10;

 

int rand() /* trả về một số ngẫu nhiên giữa 0 và 32767*/ 

{

    rand_seed = rand_seed * 1103515245 +12345;   

    return (unsigned int)(rand_seed / 65536) % 32768; 

}

 

void main() 

{   

    int i,t,x,y;

  

    /* tạo mảng */   

    for (i=0; i < MAX; i++)   

    {     

        a[i]=rand();     

        printf("%d\n",a[i]);   

    }

  

    /* còn những lệnh khác sẽ được thêm vào vị trí này */

}

Đọan mã này chứa nhiều khái niệm mới. Dòng int a[MAX]; cho thấy cách khai báo mảng số nguyên trong C. Để ví dụ, khai báo int a[10]; trong Pascal sẽ tương ứng như sau:

a:array [0..9] of integer;

 

Trong ngôn ngữ C, tất cả các mảng đều có chỉ số bắt đầu từ 0 và kết thúc tại n-1. Do đó lệnh int a[10]; khai báo một mảng 10 phần tử, và chỉ số lớn nhất hợp lệ là 9. Không như Pascal, C không cho phép chỉ định phạm vi của các chỉ số.

Dòng int rand_seed=10 cũng khai báo một biến tòan cục. Biến này được gán giá trị mặc định bằng 10 khi chương trình bắt đầu. Lưu ý rằng trong một bộ sinh số ngẫu nhiên thực, giá trị seed cần được gán bằng các giá trị ngẫu nhiên, chẳng hạn như gán bằng giờ hệ thống,v.v... Còn ở đây, do rand_seed được gán cố định nên thủ tục rand sẽ cho ra các giá trị như nhau mỗi khi chạy chương trình.

Dòng int rand() khai báo một hàm (function). Câu lệnh tương đương trong Pascal là:

function rand:integer;

 

Có nghĩa là hàm rand không cần tham số và trả về một giá trị có kiểu integer.

Bốn dòng tiếp theo là phần thân của hàm rand.

Thủ tục main không có gì lạ: ta khai báo bốn biến địa phương; và điền vào mảng 10 số ngẫu nhiên nhờ một vòng for. Bây giờ bạn hãy thêm đọan mã sau vào sau dòng chú thích còn những lệnh khác...

/* bubble sort */   

for (x=0; x < MAX-1; x++)      

    for (y=0; y < MAX-x-1; y++)       

        if (a[y] > a[y+1])       

        { 

            t=a[y]; 

            a[y]=a[y+1]; 

            a[y+1]=t;       

        }

/* in ra mảng đã được sắp xếp */   

printf("--------------------\n");   

for (i=0; i < MAX; i++)     

printf("%d\n",a[i]);

 

Những lỗi cần tránh:

- C không kiểm tra range check, do đó bạn có thể sử dụng chỉ số vượt qúa phạm vi của mảng mà không biết.

- Lệnh gọi đến một hàm/thủ tục cần phải có dấu ngoặc , ngay cả khi không có tham số. Ví dụ, C vẫn chấp nhận lệnh x=rand;  nhưng thủ tục sẽ không được thực thi; thay vào đó biến x sẽ nhận địa chỉ nhớ của thủ tục rand. Bạn phải viết là x=rand();

 

Các tóan tử trong C

Các tóan tử trong C cũng tương tự như trong Pascal:

Pascal

C

+

+

-

-

/

/

*

*

div

/

Mod

%

Tóan tử / thực thi phép chia nguyên khi cả hai tóan hạng đều là số nguyên; trong những trường hợp còn lại nó thực thi phép chia thực

 

void main() 

{   

    float a;

    a=10/3;   

    printf("%f\n",a); 

}

Đọan mã trên sẽ in ra một giá trị thực bởi vì a được khai báo kiểu float, nhưng a sẽ nhận giá trị là 3.0 bởi vì đọan mã thực hiện một phép chia nguyên

Trong C, thứ tự ưu tiên các tóan tử cũng giống như của Pascal; dấu ngoặc đơn cũng điều khiển thứ tự thực hiện các phép tính. Chúng ta sẽ bàn kỹ hơn về vấn đề này khi đề cập đến kiểu con trỏ (pointer)

 
< Trước