Ngôn ngữ lập trình C là gì? – Tại sao sử dụng C?

C là một ngôn ngữ lập trình cấp trung, ngôn ngữ lập trình C được phát triển bởi Dennis M. Ritchie để phát triển hệ điều hành UNIX tại Bell Labs. C được thực thi lần đầu tiên trên máy tính DEC PDP-11 vào năm 1972.

Năm 1978, Brian Kernighan và Dennis Ritchie đưa ra mô tả C đầu tiên công khai về C, nay được gọi là tiêu chuẩn K & R.

Ngôn ngữ C được phát triển để tạo ra các ứng dụng hệ thống trực tiếp tương tác với các thiết bị phần cứng như trình điều khiển, kernals vv.

Ngôn ngữ lập trình Java, Hệ điều hành UNIX, trình biên dịch C và tất cả các chương trình ứng dụng UNIX đều đã được viết bằng C.

Lập trình C được coi là cơ sở cho các ngôn ngữ lập trình khác, đó là lý do tại sao nó được biết đến như là ngôn ngữ mẹ.

Vậy, ngôn ngữ lập trình C có thể được xác định như sau:

  1. Ngôn ngữ mẹ.
  2. Ngôn ngữ lập trình hệ thống.
  3. Ngôn ngữ lập trình hướng đối tượng.
  4. Ngôn ngữ lập trình có cấu trúc.
  5. Ngôn ngữ lập trình cấp trung.

1. C như một ngôn ngữ mẹ

Ngôn ngữ C được coi là ngôn ngữ mẹ của tất cả các ngôn ngữ hiện đại vì hầu hết các trình biên dịch, JVMs, Kernals vv được viết bằng ngôn ngữ C và hầu hết các ngôn ngữ theo cú pháp C, như C ++, Java vv.

Nó cung cấp các khái niệm cốt lõi như mảng, chức năng, xử lý tập tin vv được sử dụng trong nhiều ngôn ngữ như C + +, java, C # vv.


2. C như một ngôn ngữ lập trình hệ thống

Một ngôn ngữ lập trình hệ thống được sử dụng để tạo ra các phần mềm hệ thống. Ngôn ngữ C là một ngôn ngữ lập trình hệ vì nó có thể được sử dụng để lập trình ở mức thấp (ví dụ driver và kernel). Nó thường được sử dụng để tạo ra các thiết bị phần cứng, hệ điều hành, trình điều khiển, hạt nhân vv. Ví dụ, kernel của hệ điều hành Linux được viết bằng C.

Nó không thể được sử dụng trong các chương trình internet như java, .net, php vv.


3. C như một ngôn ngữ thủ tục

Một thủ tục được gọi là chức năng, phương thức, chương trình con vv. Một ngôn ngữ thủ tục quy định một loạt các bước hoặc các thủ tục cho chương trình để giải quyết vấn đề.

Một ngôn ngữ thủ tục chia nhỏ chương trình thành các chức năng, cấu trúc dữ liệu vv.

C là một ngôn ngữ thủ tục. Trong C, các biến và nguyên mẫu chức năng phải được khai báo trước khi được sử dụng.


4. C như một ngôn ngữ lập trình có cấu trúc

Một ngôn ngữ lập trình cấu trúc là một tập con của ngôn ngữ thủ tục. Cấu trúc có nghĩa là chia nhỏ một chương trình thành các phần hoặc khối để nó có thể dễ hiểu.

Trong ngôn ngữ C, chúng ta chia chương trình thành các phần bằng cách sử dụng các hàm. Nó làm cho chương trình dễ hiểu hơn và sửa đổi.


5. C như một ngôn ngữ lập trình cấp trung

C được coi là ngôn ngữ bậc trung vì nó hỗ trợ tính năng của cả ngôn ngữ bậc thấp và cấp cao. Chương trình ngôn ngữ C được chuyển đổi thành mã assembly, hỗ trợ số học con trỏ (cấp thấp), nhưng nó là máy tính độc lập (tính năng cao cấp).

Ngôn ngữ cấp thấp là cụ thể cho một máy tức là máy tính phụ thuộc. Đó là máy tính phụ thuộc, nhanh chóng chạy. Nhưng nó không phải là dễ hiểu.

Ngôn ngữ Cấp cao không cụ thể đối với một máy tức là máy độc lập. Nó rất dễ hiểu.


Tại sao sử dụng C?

C ban đầu được sử dụng cho công việc phát triển hệ thống, đặc biệt là các chương trình tạo nên hệ điều hành. C đã được thông qua như là một ngôn ngữ phát triển hệ thống vì nó tạo mã chạy gần như nhanh như mã được viết bằng ngôn ngữ assembly. Một số ví dụ về việc sử dụng C có thể là:

  • Các hệ điều hành.
  • Các trình biên dịch ngôn ngữ.
  • Assemblers.
  • Biên tập văn bản.
  • Print Spoolers.
  • Network Drivers.
  • Chương trình hiện đại.
  • Cơ sở dữ liệu.
  • Ngôn ngữ biên dịch.

Điều kiện tiên quyết để học C

Trước khi học lập trình C, bạn phải có kiến ​​thức căn bản về máy tính.


Phần mềm lập trình C

Tất cả các ví dụ và bài tập thực hành lập trình C trên trang http://hiepsiit.com sử dụng phần mềm Dev C++được giới thiệu trong bài cài đặt môi trường lập trình C.

Lịch sử ngôn ngữ C

Trong bài này, chúng ta sẽ thảo luận về lịch sử ngắn gọn của ngôn ngữ C.

Ngôn ngữ lập trình C được phát triển năm 1972 bởi Dennis M. Ritchie tại Bell Labs của AT&T (American Telephone & Telegraph), đặt tại Hoa Kỳ. C được thực thi lần đầu tiên trên máy tính DEC PDP-11 vào năm 1972.

Dennis M. Ritchie được biết đến như là người sáng lập ra ngôn ngữ C.

Nó được phát triển để khắc phục các vấn đề của các ngôn ngữ trước đây như B, BCPL, vv.

Ban đầu, ngôn ngữ C được phát triển để sử dụng trong hệ điều hành UNIX . Nó thừa hưởng nhiều tính năng của các ngôn ngữ trước đó như B và BCPL.

Hãy xem các ngôn ngữ lập trình được phát triển trước ngôn ngữ C.

Ngôn ngữ Năm Phát triển bởi
Algol 1960 International Group
BCPL 1967 Martin Richard
B 1970 Ken Thompson
Traditional C 1972 Dennis Ritchie
K & R C 1978 Kernighan & Dennis Ritchie
ANSI C 1989 ANSI Committee
ANSI/ISO C 1990 ISO Committee
C99 1999 Standardization Committee

 

Các tính năng của ngôn ngữ C

C là ngôn ngữ được sử dụng rộng rãi. Nó cung cấp rất nhiều tính năng được đưa ra dưới đây:

  1. Đơn giản.
  2. Máy độc lập hoặc di động.
  3. Ngôn ngữ lập trình cấp trung.
  4. ngôn ngữ lập trình có cấu trúc.
  5. Thư viện phong phú.
  6. Quản lý bộ nhớ.
  7. Tốc độ nhanh.
  8. Con trỏ.
  9. Đệ quy.
  10. Mở rộng.

1. Đơn giản

C là một ngôn ngữ đơn giản theo nghĩa nó cung cấp cách tiếp cận có cấu trúc (để phá vỡ vấn đề thành các phần), tập hợp các chức năng thư viện phong phú , các kiểu dữ liệu vv. 


2. Máy độc lập hoặc di động

Không giống như ngôn ngữ assembly, chương trình C có thể được thực hiện trong nhiều máy với sự thay đổi chút ít hoặc không có. Nhưng nó không phải là nền tảng độc lập.


3. Ngôn ngữ lập trình cấp trung

C cũng được sử dụng để lập trình ở mức thấp. Nó được sử dụng để phát triển các ứng dụng hệ thống như kernel, driver, vv. Nó cũng hỗ trợ các tính năng của ngôn ngữ cấp cao. Đó là lý do tại sao nó được gọi là ngôn ngữ bậc trung.


4. Ngôn ngữ lập trình có cấu trúc

C là một ngôn ngữ lập trình có cấu trúc theo nghĩa chúng ta có thể chia nhỏ chương trình thành các phần bằng cách sử dụng các hàm. Vì vậy, nó rất dễ hiểu và sửa đổi.


5. Thư viện phong phú

C cung cấp rất nhiều chức năng sẵn có mà làm cho việc phát triển nhanh chóng.


6. Quản lý bộ nhớ

Nó hỗ trợ tính năng phân bổ bộ nhớ động. Trong ngôn ngữ C, chúng ta có thể giải phóng bộ nhớ được phân bổ bất cứ lúc nào bằng cách gọi hàm free().


7. Tốc độ nhanh

Việc biên dịch và thời gian thực hiện của ngôn ngữ C là nhanh.


8. Con trỏ

C cung cấp tính năng của con trỏ. Chúng ta có thể trực tiếp tương tác với bộ nhớ bằng cách sử dụng các con trỏ. Chúng ta có thể sử dụng con trỏ cho bộ nhớ, cấu trúc, chức năng, mảng, vv.


9. Đệ quy

Trong C, chúng ta có thể gọi hàm trong hàm. Nó cung cấp khả năng sử dụng lại mã cho mỗi chức năng.


10. Mở rộng

Ngôn ngữ C mở rộng vì nó có thể dễ dàng áp dụng các tính năng mới.


 

Các công cụ cần thiết

Nếu bạn muốn cài đặt môi trường lập trình C, bạn cần hai công cụ phần mềm sau đây trên máy tính của bạn:

  1. Trình soạn thảo văn bản.
  2. Trình biên dịch C.

1. Trình soạn thảo văn bản

Được sử dụng để nhập chương trình của bạn. Ví dụ về một số trình soạn thảo bao gồm Windows Notepad, lệnh Chỉnh sửa Hệ điều hành, Tóm tắt, Epsilon, EMACS và vim hoặc vi.

Tên và phiên bản của trình soạn thảo văn bản có thể khác nhau trên các hệ điều hành khác nhau. Ví dụ, Notepad sẽ được sử dụng trên Windows, và vim hoặc vi có thể được sử dụng trên các cửa sổ cũng như trên Linux hoặc UNIX.

Các tệp bạn tạo với trình biên tập của bạn được gọi là các tệp nguồn và chứa các mã nguồn của chương trình. Các tập tin nguồn cho các chương trình C thường được đặt tên với phần mở rộng “.c”.

Trước khi bắt đầu lập trình, hãy chắc chắn rằng bạn có một trình soạn thảo văn bản và bạn có đủ kinh nghiệm để viết một chương trình máy tính, lưu nó trong một tệp, biên dịch nó và cuối cùng thực hiện nó. 


2. Trình biên dịch C

Mã nguồn được viết dưới dạng mã ASCII. Nó cần phải được “biên dịch”, sang ngôn ngữ máy để CPU của bạn thực sự có thể thực hiện chương trình theo các hướng dẫn được đưa ra.

Trình biên dịch biên dịch mã nguồn vào các chương trình thực thi cuối cùng. Trình biên dịch được sử dụng thường xuyên nhất và miễn phí là trình biên dịch GNU C/C++, nếu không bạn có thể có trình biên dịch từ HP hoặc Solaris nếu bạn có hệ điều hành tương ứng.

Phần sau giải thích cách cài đặt trình biên dịch GNU C/C++ trên các hệ điều hành khác nhau. Chúng tôi tiếp tục đề cập đến C/C++ với nhau vì GNU gcc trình biên dịch hoạt động cho cả C và C++ ngôn ngữ lập trình.


Cài đặt môi trường lập trình C

  • Cài đặt trên UNIX/Linux.
  • Cài đặt trên Mac OS.
  • Cài đặt trên Windows.

1. Cài đặt trên UNIX/Linux

Nếu bạn đang sử dụng Linux hoặc UNIX , hãy kiểm tra xem GCC đã được cài đặt trên hệ thống của bạn bằng cách nhập lệnh sau từ dòng lệnh: 

$ gcc -v

Nếu bạn có trình biên dịch GNU được cài đặt trên máy của bạn thì bạn nên in một thông báo như sau:

Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr .......
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)

Nếu GCC không được cài đặt, thì bạn sẽ phải tự cài đặt nó bằng cách sử dụng các hướng dẫn chi tiết có sẵn tại https://gcc.gnu.org/install/

Hướng dẫn này đã được viết dựa trên Linux và tất cả các ví dụ đưa ra đã được biên dịch trên hương vị Cent OS của hệ thống Linux.


2. Cài đặt trên Mac OS

Nếu bạn sử dụng Mac OS X, cách dễ nhất để lấy GCC là tải về môi trường phát triển Xcode từ trang web của Apple và làm theo hướng dẫn cài đặt đơn giản. Một khi bạn đã thiết lập Xcode, bạn sẽ có thể sử dụng trình biên dịch GNU cho C/C++.

Xcode hiện có tại https://developer.apple.com/xcode/ .


3. Cài đặt trên Windows

Để cài đặt GCC trên Windows, bạn cần cài đặt MinGW. Để cài đặt MinGW, hãy truy cập vào trang chủ của MinGW, www.mingw.org và làm theo liên kết tới trang download MinGW. Tải về phiên bản mới nhất của chương trình cài đặt MinGW, có tên MinGW- .exe.

Trong khi cài đặt Min GW, ở mức tối thiểu, bạn phải cài đặt gcc-core, gcc-g++, binutils và thời gian chạy MinGW, nhưng bạn có thể muốn cài đặt thêm.

Thêm thư mục con bin của cài đặt MinGW vào biến môi trường PATH của bạn , để bạn có thể chỉ định các công cụ này trên dòng lệnh bằng các tên đơn giản của chúng.

Sau khi quá trình cài đặt hoàn tất, bạn có thể chạy gcc, g++, ar, ranlib, dlltool và một số công cụ GNU khác từ dòng lệnh Windows.


Phần mềm Dev C++

Nếu bạn đang sử dụng hệ điều hành Windows bạn có thể sử dụng phần mềm Dev C++, khi cài phần mềm Dev C++ cung cấp cho bạn trình soạn thảo văn bản, trình biên dịch C/C++, tính năng debug và nhiều tính năng tiện lợi khác.

Tải Dev C++ tại đây.

Giao diện ban đầu của phần mềm Dev C++:


Phần mềm Turbo C++

Ngoài ra, bạn có thể dùng phần mềm kinh điển Turbo C++ tải về tại https://turboc.codeplex.com/.

Giao diện ban đầu của phần mềm Turbo C++ khá là tù:

Chương trình C đầu tiên


Trước khi bắt đầu lập trình C, bạn cần phải học cách viết, biên dịch và chạy chương trình C đầu tiên.

Để viết chương trình C đầu tiên, mở chương trình Dev C++.

Chọn File -> New -> Source File và viết mã sau:

#include <stdio.h>
 
int main() {
    printf("Hello C Language");
    return 0;
}

#include<stdio.h>: Chứa các hàm nhập xuất. Hàm printf() được định nghĩa trong stdio.h.

int main(): hàm chính được gọi đầu tiên của chương trình bằng ngôn ngữ C.

printf(): hàm printf() được sử dụng để in dữ liệu trên bảng điều khiển.

return 0: câu lệnh return 0, trả về trạng thái thực thi cho hệ điều hành. Giá trị 0 được sử dụng để thực hiện thành công và 1 cho việc thực hiện không thành công.


Làm thế nào để biên dịch và chạy chương trình C

Có 2 cách để biên dịch và chạy chương trình C với Dev C++, theo menu và phím tắt.

Compile: chọn Execute -> Compile (hoặc F9)

Run: chọn Execute -> Compile (hoặc F10)

Compile và Run: chọn Execute -> Compile (hoặc F11)

 


Biên dịch và chạy chương trình trên

Đầu tiên, bạn cầu Save đoạn code trên vào tập tin hello.c.

Tại trình Dev C++, nhấn phím F9 để biên dịch chương trình, sau đó nhấn phím F10 để chạy chương trình.

Kết quả:

Lưu đồ thực thi chương trình ngôn ngữ c

Để hiểu rõ các bước thực thi chương trình c, chúng ta hãy xem một chương trình đơn giản đầu tiên.

File: hello.c

#include <stdio.h>
 
int main() {
    printf("Hello C Language");
    return 0;
}

Lưu đồ (Flow) thực thi

Hãy cố gắng hiểu được flow của chương trình trên bằng các bước được đưa ra dưới đây.

1. Chương trình C (mã nguồn) được gửi đến Preprocessor đầu tiên. Preprocessor có trách nhiệm chuyển đổi các chỉ thị tiền xử lý thành các giá trị tương ứng. Bộ tiền xử lý tạo ra một mã nguồn mở rộng.

2. Mã nguồn được mở rộng được gửi tới trình Compiler biên dịch mã và chuyển đổi nó thành mã assembly.

3. Mã assembly được gửi đến Assembler để lắp ráp mã và chuyển đổi nó thành mã đối tượng. Bây giờ tệp hello.obj được tạo ra.

4. Mã đối tượng được gửi đến Linker liên kết nó tới thư viện như các tệp header. Sau đó, nó được chuyển đổi thành mã thực thi. Một tập tin hello.exe được tạo ra.

5. Mã thực thi được gửi đến Loader nạp nó vào bộ nhớ và sau đó nó được thực thi. Sau khi thực hiện, output của chương trình được gửi đến console.

printf() và scanf() trong C

Các hàm printf() và scanf() trong C được sử dụng cho đầu ra và đầu vào. Cả hai chức năng là các chức năng của thư viện có sẵn, được định nghĩa trong tập tin tiêu đề stdio.h.


1. Hàm printf()

Hàm printf() được sử dụng cho đầu ra. Nó in ra lệnh đã cho vào bảng điều khiển (console).

Cú pháp của hàm printf() được đưa ra dưới đây:

printf("format string", argument_list);

Format string có thể là %d (số nguyên), %c (ký tự) ,%s (chuỗi), %f (float), vv.


2. Hàm scanf()

Hàm scanf() được sử dụng cho đầu vào. Nó đọc dữ liệu đầu vào từ bàn điều khiển.

scanf("format string", argument_list); 

Ví dụ hàm printf() và scanf() trong C

Hãy theo dõi các ví dụ sau để hiểu rõ hơn về hàm printf() và scanf() trong C.


Ví dụ 1

Ví dụ nhập số nguyên n từ console và hiển thị bình phương của nó ra console.

#include <stdio.h>
 
int main() {    
    int number;
    printf("Nhap so nguyen: ");
    scanf("%d",&number);
    printf("Binh phuong cua %d la: %d ", number, number*number);
    return 0;
}

Kết quả:

Nhap so nguyen: 9
Binh phuong cua 9 la: 81

Lệnh scanf(“%d”, &number) đọc số nguyên từ console và lưu trữ giá trị đã cho trong biến number.

Lệnh printf(“Binh phuong cua %d la: %d “, number, number*number) in ra console số number và giá trị bình phương của nó.


Ví dụ 2

Tính tổng của hai số nhập từ console và in tổng của hai số ra console.

#include <stdio.h>
 
int main() {    
    int a;
    int b;
    printf("Nhap so nguyen a: ");
    scanf("%d", &a);
    printf("Nhap so nguyen b: ");
    scanf("%d", &b);    
    printf("Tong cua %d va %d la: %d ", a, b, a + b);
    return 0;
}

Kết quả:

Nhap so nguyen a: 12
Nhap so nguyen b: 8
Tong cua 12 va 8 la: 20

 

Biến trong ngôn ngữ C

Một biến trong C là tên của vị trí bộ nhớ. Nó được sử dụng để lưu trữ dữ liệu. Giá trị của nó có thể được thay đổi và nó có thể được sử dụng lại nhiều lần. Mỗi biến trong C có một loại dữ liệu cụ thể, xác định kích thước của bộ nhớ của biến; phạm vi các giá trị có thể được lưu trữ trong bộ nhớ đó.

Biến là một cách để thể hiện vị trí bộ nhớ thông qua một cái tên để nó có thể được xác định một cách dễ dàng. Tên của một biến có thể bao gồm các chữ cái, chữ số và ký tự gạch dưới. Nó phải bắt đầu bằng một chữ cái thư hoặc một gạch dưới. Biến trong C có phân biệt chữ hoa và chữ thường.


Cú pháp khai báo biến

Cú pháp để khai báo một biến trong C:

type variable_list;

Ví dụ về khai báo biến:

int a;
float b;
char c;

Ở đây, a, b, c là các biến và int, float, char là các kiểu dữ liệu.

Chúng ta cũng có thể khởi tạo giá trị trong khi khai báo các biến như được đưa ra dưới đây:

int a = 10, b = 20; // Khai báo 2 biến kiểu số nguyên
float = 20,8;
char c = 'A';

Quy tắc khai báo biến trong C

  • Một biến có thể có các chữ cái, chữ số và dấu gạch dưới.
  • Tên biến chỉ có thể bắt đầu bằng bảng chữ cái và dấu gạch dưới. Nó không thể bắt đầu bằng chữ số.
  • Không có khoảng trắng trong tên biến.
  • Tên biến không phải là bất kỳ từ hoặc từ khóa dành riêng như int, float, vv.

Tên biến hợp lệ:

int a;
int _ab;
int a30;

 Tên biến không hợp lệ:

int 2;
int a b;
int long;

Các kiểu biến trong C

Có một vài kiểu biến trong C như sau:

  1. Biến local (cục bộ).
  2. Biến global (toàn cục).
  3. Biến static.
  4. Biến automatic.
  5. Biến external.

1. Biến local (cục bộ).

Một biến được khai báo bên trong hàm hoặc khối lệnh được gọi là biến cục bộ.

Nó phải được khai báo khi bắt đầu khối.

void function1() {
    int x = 10; // bien local
}

2. Biến global (toàn cục).

Một biến được khai báo bên ngoài hàm hoặc khối lệnh được gọi là biến toàn cục. Bất kỳ hàm nào cũng có thể thay đổi giá trị của biến toàn cầu. Nó có sẵn cho tất cả các chức năng.

Trong ví dụ dưới đây, biến a là biến global.

int a = 20; // bien global
 
void function1() {
    int x = 10; // bien local
}

3. Biến static (tĩnh).

Một biến được khai báo với từ khóa static được gọi là biến tĩnh.

Nó giữ lại giá trị của nó sau nhiều lần gọi hàm.

#include <stdio.h>
 
int main() {
    function1();
    function1();
    function1();
    return 0;
}
 
int function1() {
    int x = 10; // bien local
    static int y = 10; // bien static
    x = x + 1;
    y = y + 1;
    printf("\n %d, %d", x, y);

Kết quả:

11, 11
11, 12
11, 13

Hàm function1() được gọi 3 lần, biến địa phương x sẽ in cùng một giá trị cho mỗi lệnh chức năng gọi là 11, 11, 11. Nhưng biến tĩnh sẽ in giá trị được tăng lên 1 trong mỗi lần gọi hàm là 11, 12, 13.

4. Biến automatic (tự động).

Tất cả các biến trong C được khai báo trong khối lệnh, là các biến tự động theo mặc định. Bởi chúng ta có thể khai báo một cách rõ ràng biến tự động bằng cách sử dụng từ khóa auto.

void main(){  
    int x = 10; // bien local (cung la bien automatic)
    auto int y = 20; // bien automatic
}  

5. Biến external.

Chúng ta có thể chia sẻ một biến trong nhiều tập tin mã nguồn C bằng cách sử dụng biến external. Để khai báo biến bên ngoài, bạn cần sử dụng từ khóa extern

File: myfile.h

extern int x = 10; // bien external variable (cung la bien global)

File: test.c

#include "myfile.h"
#include <stdio.h>
 
int main() {
    printValue();
}
 
int printValue() {
    printf("x: %d", x);
}

Kết quả:

x: 10

 

Kiểu dữ liệu trong C

Kiểu dữ liệu trong C xác định loại dữ liệu mà một biến có thể lưu trữ như số nguyên, số thực, ký tự vv.


Có 4 loại kiểu dữ liệu trong ngôn ngữ C.

STT. Kiểu & Mô tả
1

Kiểu dữ liệu cơ bản

Đó là các kiểu số học và được phân loại thành: các kiểu số nguyên và các kiểu số thực.

2

Kiểu Enumeration

Đó là các kiểu số học và chúng được sử dụng để xác định các biến chỉ có thể chỉ định một số giá trị số nguyên rời rạc trong suốt chương trình.

3

Kiểu dữ liệu Derived

Các kiểu dữ liệu bao gồm các kiểu con trỏ (Pointer), mảng (Array), cấu trúc (Structure), Union và Function.

4

Kiểu Void

Kiểu Void (vô nghĩa) chỉ định rằng không có giá trị nào có sẵn.


Các loại dữ liệu cơ bản

Các kiểu dữ liệu cơ bản dựa trên số nguyên và số thực. Ngôn ngữ C hỗ trợ cả signed và unsigned.

Kích thước bộ nhớ của các loại dữ liệu cơ bản có thể thay đổi theo hệ điều hành 32 hoặc 64 bit.

Hãy xem các kiểu dữ liệu cơ bản. Kích thước của nó được cho theo kiến ​​trúc 32 bit.
 

Kiểu Dữ LiệuKích Thước Bộ NhớVùng Giá Trị
char1 byte−128 to 127
signed char1 byte−128 to 127
unsigned char1 byte0 to 255
short2 byte−32,768 to 32,767
signed short2 byte−32,768 to 32,767
unsigned short2 byte0 to 65,535
int2 byte−32,768 to 32,767
signed int2 byte−32,768 to 32,767
unsigned int2 byte0 to 65,535
short int2 byte−32,768 to 32,767
signed short int2 byte−32,768 to 32,767
unsigned short int2 byte0 to 65,535
long int4 byte-2,147,483,648 to 2,147,483,647
signed long int4 byte-2,147,483,648 to 2,147,483,647
unsigned long int4 byte0 to 4,294,967,295
float4 byte1.2E-38 to 3.4E+38
double8 byte2.3E-308 to 1.7E+308
long double10 byte3.4E-4932 to 1.1E+4932

 

Ép kiểu trong C

Ép kiểu trong C là việc gán giá trị của một biến có kiểu dữ liệu hiện tại tới biến khác có kiểu dữ liệu khác.

Cú pháp:

(type) value;

Ví dụ:

float c = 35.8f;
int b = (int)c + 1;

Trong ví dụ trên, đầu tiên giá trị dấu phảy động c được đổi thành giá trị nguyên 35. Sau đó nó được cộng với 1 và kết quả là giá trị 36 được lưu vào b.


Phân loại ép kiểu trong C

Trong C, có hai loại ép kiểu dữ liệu:

  1. Nới rộng (widening): Là quá trình làm tròn số từ kiểu dữ liệu có kích thước nhỏ hơn sang kiểu có kích thước lớn hơn. Kiểu biến đổi này không làm mất thông tin.
  2. Thu hẹp (narrowwing): Là quá trình làm tròn số từ kiểu dữ liệu có kích thước lớn hơn sang kiểu có kích thước nhỏ hơn. Kiểu biến đổi này có thể làm mất thông tin

1. Nới rộng (widening)

Nới rộng (widening): Là quá trình làm tròn số từ kiểu dữ liệu có kích thước nhỏ hơn sang kiểu có kích thước lớn hơn. Kiểu biến đổi này không làm mất thông tin. Ví dụ chuyển từ int sang float. Chuyển kiểu loại này có thế được thực hiện ngầm định bởi trình biên dịch.

Ví dụ:

#include <stdio.h>
  
int main() {
    int i = 100;
    long l = i;    // khong yeu cau chi dinh ep kieu
    float f = l;   // khong yeu cau chi dinh ep kieu
    printf("Gia tri Int: %d\n", i);
    printf("Gia tri Long: %d\n", l);
    printf("Gia tri Float: %f\n", f);
    return 0;
}

 Kết quả:

Giá trị Int: 100
Giá trị Long: 100
Giá trị Float:  100.0

2.Thu hẹp (narrowwing)

ep-kieu-du-lieu-noi-rong

Thu hẹp (narrowwing): Là quá trình làm tròn số từ kiểu dữ liệu có kích thước lớn hơn sang kiểu có kích thước nhỏ hơn. Kiểu biến đổi này có thể làm mất thông tin như ví dụ ở trên. Chuyển kiểu loại này không thể thực hiện ngầm định bởi trình biên dịch, người dùng phải thực hiện chuyển kiểu tường minh.

Ví dụ:

#include <stdio.h>
  
int main() {
    double d = 100.04;
    long l = (long) d; // yeu cau chi dinh kieu du lieu (long)
    int i = (int) l; // yeu cau chi dinh kieu du lieu (int)    
    printf("Gia tri Int: %f\n", d);
    printf("Gia tri Long: %d\n", l);
    printf("Gia tri Float: %d\n", i);
    return 0;
}

Kết quả:

Giá trị Double: 100.04
Giá trị Long: 100
Giá trị Int:  100

 

Danh sách từ khóa trong C

Từ khóa là một từ dành riêng. Bạn không thể sử dụng nó như một tên biến, tên hằng số… Chỉ có 32 từ dành riêng (từ khoá) trong ngôn ngữ lập trình C.

Danh sách 32 từ khoá trong C được đưa ra dưới đây:

auto break case char const continue default do
double else enum extern float for goto if
int long register return short signed sizeof static
struct switch typedef union unsigned void volatile while

Chúng ta sẽ học về tất cả các từ khóa trong ngôn ngữ lập trình C trong các bài học sau này.

Toán tử trong C

Toán tử trong C là một ký hiệu được sử dụng để thực hiện một phép tính/chức năng nào đó. Ngôn ngữ lập trình C cung cấp các dạng toán tử sau:

  1. Toán tử số học.
  2. Toán tử quan hệ.
  3. Toán tử logic.
  4. Toán tử so sánh bit.
  5. Toán tử gán.
  6. Toán tử hỗn hợp.
  7. Thứ tự ưu tiên.

1. Toán tử số học trong C

Bảng dưới đây mô tả các toán tử số học được hỗ trợ bởi ngôn ngữ C. Giả sử biến A = 10 và biến B = 20:
 

Toán tử Miêu tả Ví dụ
+ Cộng hai toán hạng A + B sẽ cho kết quả là 30
Trừ hai toán hạng A – B sẽ cho kết quả là -10
* Nhân hai toán hạng A * B sẽ cho kết quả là 200
/ Chia lấy phần nguyên hai toán hạng B / A sẽ cho kết quả là 2
% Chia lấy phần dư B % A sẽ cho kết quả là 0
++ Tăng giá trị toán hạng thêm 1 đơn vị A++ sẽ cho kết quả là 11
Giảm giá trị toán hạng một đơn vị A– sẽ cho kết quả là 9

2. Toán tử quan hệ trong C

Các toán tử quan hệ được sử dụng kiểm tra mối quan hệ giữa hai toán hạng. Kết quả của một biểu thức có dùng các toán tử quan hệ là những giá trị Boolean (logic “true” hoặc “false”). Các toán tử quan hệ được sử dụng trong các cấu trúc điều khiển.

Bảng dưới đây mô tả các toán tử quan hệ được hỗ trợ bởi ngôn ngữ C. Giả sử biến A = 10 và biến B = 20:

Toán tử Miêu tả Ví dụ
== Kiểm tra nếu 2 toán hạng bằng nhau hay không. Nếu bằng thì điều kiện là true. (A == B) là không đúng.
!= Kiểm tra 2 toán hạng có giá trị khác nhau hay không. Nếu không bằng thì điều kiện là true. (A != B) là true.
> Kiểm tra nếu toán hạng bên trái có giá trị lớn hơn toán hạng bên phải hay không. Nếu lớn hơn thì điều kiện là true. (A > B) là không đúng.
< Kiểm tra nếu toán hạng bên trái nhỏ hơn toán hạng bên phải hay không. Nếu nhỏ hơn thì là true. (A < B) là true.
>= Kiểm tra nếu toán hạng bên trái có giá trị lớn hơn hoặc bằng giá trị của toán hạng bên phải hay không. Nếu đúng là true. (A >= B) là không đúng.
<= Kiểm tra nếu toán hạng bên trái có giá trị nhỏ hơn hoặc bằng toán hạng bên phải hay không. Nếu đúng là true. (A <= B) là true.

3. Toán tử logic trong C

Bảng dưới đây mô tả các toán tử logic được hỗ trợ bởi ngôn ngữ C. Giả sử biến A = true (hoặc 1) và biến B = false (hoặc 0): 

Toán tử Miêu tả Ví dụ
&& Được gọi là toán tử logic AND (và). Nếu cả hai toán tử đều có giá trị khác 0 thì điều kiện trở lên true. (A && B) là false.
|| Được gọi là toán tử logic OR (hoặc). Nếu một trong hai toán tử khác 0, thì điều kiện là true. (A || B) là true.
! Được gọi là toán tử NOT (phủ định). Sử dụng để đảo ngược lại trạng thái logic của toán hạng đó. Nếu điều kiện toán hạng là true thì phủ định nó sẽ là false. !(A && B) là true.

4. Toán tử bit trong C

Các toán tử dạng bit cho phép chúng ta thao tác trên từng bit riêng biệt trong các kiểu dữ liệu nguyên thủy. Giả sử A = 60 (= 0011 1100) và B = 13 (= 0000 1101)
 

Toán tử Miêu tả Ví dụ
& Toán tử AND (và) nhị phân sao chép một bit tới kết quả nếu nó tồn tại trong cả hai toán hạng. (A & B) sẽ cho kết quả là 12, tức là 0000 1100
| Toán tử OR (hoặc) nhị phân sao chép một bit tới kết quả nếu nó tồn tại trong một hoặc hai toán hạng. (A | B) sẽ cho kết quả là 61, tức là 0011 1101
^ Toán tử XOR nhị phân sao chép bit mà nó chỉ tồn tại trong một toán hạng mà không phải cả hai. (A ^ B) sẽ cho kết quả là 49, tức là 0011 0001
~ Toán tử đảo bit (đảo bit 1 thành bit 0 và ngược lại). (~A ) sẽ cho kết quả là -61, tức là 1100 0011.
<< Toán tử dịch trái. Giá trị toán hạng trái được dịch chuyển sang trái bởi số các bit được xác định bởi toán hạng bên phải. A << 2 sẽ cho kết quả 240, tức là 1111 0000 (dịch sang trái hai bit)
>> Toán tử dịch phải. Giá trị toán hạng trái được dịch chuyển sang phải bởi số các bit được xác định bởi toán hạng bên phải. A >> 2 sẽ cho kết quả là 15, tức là 0000 1111 (dịch sang phải hai bit)

5. Toán tử gán trong C

Toán tử gán dùng để gán một giá trị vào một biến và có thể gán nhiều giá trị cho nhiều biến cùng một lúc.

Toán tử Miêu tả Ví dụ
= Toán tử gán đơn giản. Gán giá trị toán hạng bên phải cho toán hạng trái. C = A + B sẽ gán giá trị của A + B vào trong C
+= Thêm giá trị toán hạng phải tới toán hạng trái và gán giá trị đó cho toán hạng trái. C += A tương đương với C = C + A
-= Trừ đi giá trị toán hạng phải từ toán hạng trái và gán giá trị này cho toán hạng trái. C -= A tương đương với C = C – A
*= Nhân giá trị toán hạng phải với toán hạng trái và gán giá trị này cho toán hạng trái. C *= A tương đương với C = C * A
/= Chia toán hạng trái cho toán hạng phải và gán giá trị này cho toán hạng trái. C /= A tương đương với C = C / A
%= Lấy phần dư của phép chia toán hạng trái cho toán hạng phải và gán cho toán hạng trái. C %= A tương đương với C = C % A
<<= Dịch trái toán hạng trái sang số vị trí là giá trị toán hạng phải. C <<= 2 tương đương với C = C << 2
>>= Dịch phải toán hạng trái sang số vị trí là giá trị toán hạng phải. C >>= 2 tương đương với C = C >> 2
&= Phép AND bit C &= 2 tương đương với C = C & 2
^= Phép OR loại trừ bit C ^= 2 tương đương với C = C ^ 2
|= Phép OR bit. C |= 2 tương đương với C = C | 2

6. Toán tử hỗn hợp trong C

Có một số toán tử hỗn hợp quan trọng là sizeof và ? : được hỗ trợ bởi ngôn ngữ C.

Toán tử Miêu tả Ví dụ
sizeof() Trả lại kích cỡ của một biến sizeof(a), với a là integer, thì sẽ trả lại kết quả là 4.
& Trả lại địa chỉ của một biến. &a; sẽ cho địa chỉ thực sự của biến a.
* Trỏ tới một biến. *a; sẽ trỏ tới biến a.
? : Biểu thức điều kiện Nếu điều kiện là true ? thì giá trị X : Nếu không thì giá trị Y

7. Thứ tự ưu tiên

Thứ tự ưu tiên của các toán tử trong C

Thứ tự ưu tiên quyết định trật tự thực hiện các toán tử trên các biểu thức. Bảng dưới đây liệt kê thứ tự thực hiện các toán tử trong C.

Loại  Toán tử  Thứ tự ưu tiên 
Postfix  () -> . ++ – –   Trái sang phải 
Unary  + – ! ~ ++ – – (type)* & sizeof  Phải sang trái 
Tính nhân  * / %  Trái sang phải 
Tính cộng  + –  Trái sang phải 
Dịch chuyển  << >>  Trái sang phải 
Quan hệ  < <= > >=  Trái sang phải 
Cân bằng  == !=  Trái sang phải 
Phép AND bit  Trái sang phải 
Phép XOR bit  Trái sang phải 
Phép OR bit  Trái sang phải 
Phép AND logic  &&  Trái sang phải 
Phép OR logic  ||  Trái sang phải 
Điều kiện  ?:  Phải sang trái 
Gán  = += -= *= /= %=>>= <<= &= ^= |=  Phải sang trái 
Dấu phảy  Trái sang phải 

Thay đổi thứ tự ưu tiên của các toán tử trong C

Để thay đổi thứ tự ưu tiên trên một biểu thức, bạn có thể sử dụng dấu ngoặc đơn ():

  • Phần được giới hạn trong ngoặc đơn được thực hiện trước.
  • Nếu dùng nhiều ngoặc đơn lồng nhau thì toán tử nằm trong ngoặc đơn phía trong sẽ thực thi trước, sau đó đến các vòng phía ngoài.
  • Trong phạm vi một cặp ngoặc đơn thì quy tắc thứ tự ưu tiên vẫn giữ nguyên tác dụng.

Ví dụ, x = 10 + 5 * 2; ở đây, x được gán giá trị 20, chứ không phải 30 bởi vì toán tử * có quyền ưu tiên cao hơn toán tử +, vì thế đầu tiên nó thực hiện phép nhân 5 * 2 và sau đó thêm với 10.

Để thay đổi thứ tự ưu tiên ta dùng dấu (), ví dụ, x = (10 + 5) * 2; ở đây x = 30.


 

Ghi chú (Comment) trong C

Comment trong C được sử dụng để cung cấp thông tin (giải thích) các dòng code. Nó được sử dụng rộng rãi để tài liệu hóa code. Có 2 loại comment trong ngôn ngữ lập trình C.

  1. Comment một dòng.
  2. Comment nhiều dòng.

1. Comment một dòng

Comment một dòng trong C được đại diện bởi dấu gạch chéo kép //. Hãy xem một ví dụ về comment dòng đơn trong C.

#include<stdio.h>
 
int main() {
    // in thong tin
    printf("Hello C");
    return 0;
}      

Kết quả:

Hello C

Thậm chí là bạn có thể đặt comment ngay sau câu lệnh, ví dụ:

printf("Hello C"); // Xuất thông tin

2. Comment nhiều dòng

Comment nhiều dòng trong C được đại diện bởi dấu gạch chéo /*…*/. Nó có thể chiếm nhiều dòng nhưng nó không thể được lồng nhau. Cú pháp:

/*  
Ghi chú tại đây
*/ 

Ví dụ comment nhiều dòng trong C:

#include<stdio.h>
 
int main() {    
    /* in thong tin
      comment nhieu dong */
    printf("Hello C");
    return 0;
}

Kết quả:

Hello C

 

Hằng số trong C

Hằng số là một giá trị hoặc biến không thể thay đổi trong chương trình, ví dụ: 10, 20, ‘a’, 3.4, “lập trình c”, vv.

Có nhiều loại hằng trong lập trình C.


Danh sách hằng số trong C

Hằng số (Constant) Ví dụ
Hằng số thập phân 10, 20, 450, vv.
Hằng số thực hoặc số thực dấu phảy động 10.3, 20.2, 450.6, vv.
Hằng số Octal 021, 033, 046, vv.
Hằng số Hexadecimal 0x2a, 0x7b, 0xaa, vv.
Hằng số ký tự ‘a’, ‘b’, ‘x’, vv.
Hằng số chuỗi String “c”, “c program”, vv.

Cách để định nghĩa hằng số trong C

Có hai cách để định nghĩa hằng trong lập trình C.

  1. Từ khóa const.
  2. #define preprocessor.

1. Sử dụng từ khóa const trong C

Từ khóa const được sử dụng để định nghĩa hằng số trong lập trình C.

const float PI = 3.14;

 Bây giờ, giá trị của biến PI không thể thay đổi.

#include <stdio.h>
 
int main() {
    const float PI = 3.14;
    printf("Gia tri PI = %f", PI);
    return 0;
}

Kết quả:

Gia tri PI = 3.14

Nếu bạn cố gắng thay đổi giá trị của PI, nó sẽ hiển thị lỗi thời gian biên dịch.

#include <stdio.h>
 
int main() {
    const float PI = 3.14;
    PI = 100;
    printf("Gia tri PI = %f", PI);
    return 0;
}

Kết quả:

[Error] assignment of read-only variable 'PI'

2. #define preprocessor trong C

#define preprocessor cũng được sử dụng để định nghĩa hằng số trong ngôn ngữ lập trình C. Chúng ta sẽ học về #define preprocessor trong bài học sau.

Ký tự đặc biệt trong C

Ký tự đặc biệt trong C là một dãy các ký tự không đại diện cho chính nó khi được sử dụng bên trong chuỗi ký tự hoặc ký tự.

Nó bao gồm hai hoặc nhiều ký tự bắt đầu bằng dấu gạch chéo ngược \. Ví dụ: \n đại diện cho dòng mới.


Ký tự đặc biệt Ý nghĩa
\a Báo thức hoặc tiếng bíp
\b Dấu Backspace
\f Form Feed
\n Xuống dòng mới (LF)
\r Xuống dòng (CR)
\t Dấu Tab ngang
\v Dấu Tab dọc
\\ Dấu ngạch chéo ngược
\’ Dấu nháy đơn
\” Dấu nháy kép
\? Dấu chấm hỏi
\nnn Số octal
\xhh Số hexadecimal
\0 Null


Ví dụ ký tự đặc biệt trong C

#include <stdio.h>
 
int main() {
    printf("Ban Dang\nHoc Lap Trinh\n\'C\'\n\"Chuc Ban Hoc Vui Ve!\"");
    return 0;  
}

Kết quả:

Ban Dang
Hoc Lap Trinh
'C'
"Chuc Ban Hoc Vui Ve!"

 

Cấu trúc điều khiển if else trong C

Thông thường để kiểm giá trị có thỏa mãn với giá trị mong muốn hay không?. Trong ngôn ngữ C chúng ta thường dùng lệnh If để kiểm tra.
Các Cấu Trúc Điều Khiển

  • Câu lệnh if
  • Câu lệnh if else
  • Câu lênh if…elseif…else
  • Câu lệnh điều kiện lồng nhau

Câu lệnh IF: sử dụng câu lệnh IF để lọc kết quả đúng

if(expression){  
//code to be executed  
}  

Lưu đồ của lệnh If 

Ví dụ lệnh if:

#include<stdio.h>    
int main(){    
int number=0;    
printf("enter a number:");    
scanf("%d",&number);    
if(number%2==0){    
printf("%d is even number",number);    
}    
return 0;  
}    

Kết quả:

enter a number:4
4 is even number

 Kết quả:

enter a number:5

Câu lệnh if else.
Phần trên chúng ta mới chỉ dùng lệnh if để kiểm tra nếu đúng thì sao còn chưa bắt được sự kiện nếu sai thì làm gì. Do đó trong C hay bất kỳ ngôn ngữ lập trình nào đó đều cung cấp cho chúng ta câu lệnh else để xử lý điều kiện sai, theo cú pháp:

if(expression){  
//code to be executed if condition is true  
}else{  
//code to be executed if condition is false  
}  

Lưu đồ của lệnh If - else


Ví dụ lệnh if-else

#include<stdio.h>    
int main(){    
int number=0;    
printf("enter a number:");    
scanf("%d",&number);     
if(number%2==0){    
printf("%d is even number",number);    
}    
else{    
printf("%d is odd number",number);    
}     
return 0;  
}    

Kết quả:

enter a number:4
4 is even number

Kết quả: 

enter a number:5
5 is odd number

Câu lệnh if - else - if 
Thực thi nhiều câu lệnh với nhiều điều kiện khác nhau.
Cấu trúc:

if(condition1){  
//code to be executed if condition1 is true  
}else if(condition2){  
//code to be executed if condition2 is true  
}  
else if(condition3){  
//code to be executed if condition3 is true  
}  
...  
else{  
//code to be executed if all the conditions are false  
}  

Lưu đồ lệnh if-else-if:

Ví dụ lệnh if-else-if:

#include<stdio.h>    
int main(){    
int number=0;    
printf("enter a number:");    
scanf("%d",&number);     
if(number==10){    
printf("number is equals to 10");    
}    
else if(number==50){    
printf("number is equal to 50");    
}    
else if(number==100){    
printf("number is equal to 100");    
}    
else{    
printf("number is not equal to 10, 50 or 100");    
}    
return 0;  
}    

Kết quả:

enter a number:4
number is not equal to 10, 50 or 100

Kết quả: 

enter a number:50
number is equal to 50

 

Câu lệnh switch

Switch so sánh một biểu thức nguyên với một danh sách giá trị các số nguyên, các hằng kí tự hoặc biểu thức hằng. Mỗi giá trị trong danh sách chính là một case (trường hợp) trong khối lệnh của switch. Ngoài ra, trong khối lệnh switch còn có thể có một default case (trường hợp mặc định) có thể có hoặc không. Mặt khác, trong mỗi trường hợp còn chứa các khối lệnh chờ được thực thi.

Cú pháp của cấu trúc rẽ nhánh switch…case

Muốn sử dụng cấu trúc switch…case, bạn dùng cú pháp như sau:

switch(expression){    
case value1:    
 //code to be executed;    
 break;  //optional  
case value2:    
 //code to be executed;    
 break;  //optional  
......    
    
default:     
 code to be executed if all cases are not matched;    
}    

Các qui tắc của lệnh switch tronng ngôn ngữ C
Biểu thức nguyên trong switch được tính toán và kiểm tra lần lượt với giá trị của từng case. Đầu tiên, nó sẽ được so sánh với giá trị của case đầu tiên, nếu bằng nhau thì sẽ thực hiện các lệnh (statement) trong case này cho đến khi nó gặp được từ khoá break. Khi đó, cấu trúc switch…case kết thúc. Chương trình sẽ thực hiện tiếp những dòng lệnh sau cấu trúc switch…case. Ngược lại, nếu như giá trị biểu thức nguyên không bằng giá trị case đầu tiên thì nó sẽ tiếp tục so sánh đến giá trị của case thứ hai và tiếp tục thực hiện như những bước trên. Giả sử, đến cuối cùng vẫn không tìm được giá trị bằng nó thì các khối lệnh trong default sẽ được thực hiện nếu như có tồn tại default.

Chú ý:
1) Biểu thức trong lệnh switch phải là kiểu dữ liệu số nguyên, ký tự.
2) case value phải là hằng số nguyên hoặc ký tự.
3) case value có thể sử dụng trong lệnh switch.
4) Lệnh break trong switch không bắt buộc.

Xem ví dụ sau: Kiểu dữ liệu nào hợp lệ trong lệnh switch:

int x,y,z;  
char a,b;  
float f;  
Lệnh Switch đúng Lệnh Switch sai Lệnh Switch đúng Lệnh Switch sai
switch(x) switch(f) case 3; case 2.5;
switch(x>y) switch(x+2.5) case 'a'; case x;
switch(a+b-2)   case 1+2; case x+2;
switch(func(x,y))   case 'x'>'y'; case 1,2,3;

Sơ đồ hoạt động của cấu trúc switch…case như sau:

Ví dụ lệnh switch :
 

#include<stdio.h>  
int main(){    
int number=0;     
printf("enter a number:");    
scanf("%d",&number);    
switch(number){    
case 10:    
printf("number is equals to 10");    
break;    
case 50:    
printf("number is equal to 50");    
break;    
case 100:    
printf("number is equal to 100");    
break;    
default:    
printf("number is not equal to 10, 50 or 100");    
}    
return 0;  
}    

Kết quả:

enter a number:4
number is not equal to 10, 50 or 100

Kết quả: 

enter a number:50
number is equal to 50

Ví dụ không có lệnh break trong switch :

#include<stdio.h>  
int main(){    
int number=0;    
  
printf("enter a number:");  
scanf("%d",&number);  
  
switch(number){  
case 10:  
printf("number is equals to 10\n");  
case 50:  
printf("number is equal to 50\n");  
case 100:  
printf("number is equal to 100\n");  
default:  
printf("number is not equal to 10, 50 or 100");  
}  
return 0;  
}    

Kết quả:

enter a number:10
number is equals to 10
number is equals to 50
number is equals to 100
number is not equal to 10, 50 or 100

Kết quả: 

enter a number:50
number is equal to 50
number is equals to 100
number is not equal to 10, 50 or 100

 

Các lệnh lặp trong C

Cũng giống như cấu trúc rẽ nhánh, cấu trúc vòng lặp cũng là một trong những thành phần quan trọng của một ngôn ngữ lập trình, vòng lặp là hành động lặp lại một khối lệnh với số lần hữu hạn.

Ngô ngữ C hỗ trợ chúng ta 3 kiểu vòng lặp(loop):

  1. while
  2. do while
  3. for

Cấu trúc lặp while
Vòng lặp while là vòng lặp cơ bản trong C, điều kiện dừng vòng lặp khi expression bằng false

Cú pháp:

while (expression) { 
    statement
}

Sự hoạt động của vòng lặp while:
Bước 1: tính giá trị của (biểu thức) sau while.
Bước 2: nếu giá trị tính được của (biểu thức) là ‘sai’ (==0) thì kết thúc  vòng lặp while.
Bước 3: nếu giá trị của (biểu thức) là ‘đúng’ (!=0) thì thực hiện khối lệnh sau while.
Bước 4: quay lại bước 1

Chú ý: Trong thân vòng lặp while có thể được thực hiện một lần hoặc nhiều lần và cũng có thể không được thực hiện lần nào nếu ngay từ đầu biểu thức sau while đã sai.

Biểu diễn bằng lưu đồ: 

Ví dụ lệnh lặp while:

#include<stdio.h>  
int main(){    
int i=1;      
while(i<=10){      
printf("%d \n",i);      
i++;      
}  
return 0;  
}    

Kết quả:

1
2
3
4
5
6
7
8
9
10

Lặp không xác định trong while

Nếu bạn truyền cho while giá trị là 1, thì vòng lặp while sẽ lặp không xác định

while(1){  
//statement  
}  

Cấu trúc lặp do...while
Vòng lặp do-while cũng giống như while nhưng chỉ có điều là do-while xét điều kiện lặp sau khi mỗi vòng lặp. Cấu trúc do-while chỉ có một cú pháp.
Cú pháp:   

do{
     statement
   }while (expresion);

Giải thích cú pháp:
Bước 1: thực hiện khối lệnh sau do.
Bước 2: kiểm tra giá trị biểu thức <biểu thức> sau while, nếu có giá trị ‘đúng’ ( khác 0) thì lặp lại bước 1, nếu ‘sai’ (=0) thì kết thúc vòng lặp.
Biểu diễn bằng lưu đồ: 

Ví dụ do-while

#include<stdio.h>  
int main(){    
int i=1;      
do{    
printf("%d \n",i);    
i++;    
}while(i<=10);   
return 0;  
}     

Kết quả:

1
2
3
4
5
6
7
8
9
10

Lặp không xác định trong  do-while

Nếu bạn truyền cho while giá trị là 1, thì vòng lặp do-while sẽ lặp không xác định

do{  
//statement  
}while(1);  

Cấu trúc lặp for
Vòng lặp for là vòng lặp khá là phức tạp hơn vòng lặp while. Vòng lặp for có hai cú pháp như sau:

for (expr1; expr2; expr3) {
    statement
}

Trong đó:
    Biểu thức 1: biểu thức khởi đầu.
    Biểu thức 2: biểu thức điều kiện - điều kiện lặp.
    Biểu thức 3: bước nhảy - thường dùng với ý nghĩa là thay đổi bước nhảy.

Cả 3 biểu thức này đều là tuỳ chọn, chúng có thể vắng mặt trong câu lệnh cụ thể nhưng các dấu chấm phẩy vẫn phải có.
Sự hoạt động của vòng lặp for:

  • Bước 1: Thực hiện biểu thức khởi đầu – Biểu thức 1.
  • Bước 2: Tính giá trị biểu thức 2 để xác định điều kiện lặp.
    - Nếu biểu thức 2 có giá trị ‘sai’ (==0) thì ra khỏi vòng lặp.
    - Ngược lại, nếu biểu thức có giá trị ‘đúng’ ( khác 0) thì chuyển tới bước 3.
  • Bước 3: Thực hiện khối lệnh sau for ( thân của for ), chuyển tới bước 4.
  • Bước 4: Thực hiện biểu thức 3, rồi quay về bước 2.

Biểu diễn bằng lưu đồ: 

Ví dụ vòng lặp for:

#include<stdio.h>  
int main(){  
int i=0;        
for(i=1;i<=10;i++){      
printf("%d \n",i);      
}     
return 0;  
}     

Kết quả:

1
2
3
4
5
6
7
8
9
10

Lặp không xác định trong  for 

cú pháp:

for(;;){  
printf("Ví dụ lặp không xác định trong vòng lặp for");  
}  

 

Lệnh break trong ngôn ngữ C

Trong ngôn ngữ C, lệnh break là một lệnh mà khi gặp lệnh đó thì chương trình sẽ nhảy ra khỏi vòng lặp chứa nó.
Cú pháp:

 break;

Lưu đồ lệnh break:

Ví dụ lệnh break trong vòng lặp

#include<stdio.h>  
int main(){  
int i=1;//initializing a local variable    
//starting a loop from 1 to 10    
for(i=1;i<=10;i++){      
printf("%d \n",i);    
if(i==5){//if value of i is equal to 5, it will break the loop    
break;    
}    
}  
return 0;  
}    

Kết quả:

1
2
3
4
5

Ví dụ trên chúng ta thấy rằng vòng lặp đi tứ 1 đến 10, nhưng nó sẽ không print các giá trị sau số 5 (6,7,8,9,10)


Ví dụ lệnh break trong vòng lặp lồng nhau:

#include<stdio.h>  
int main(){  
int i=1,j=1;//initializing a local variable    
for(i=1;i<=3;i++){      
for(j=1;j<=3;j++){    
printf("%d &d\n",i,j);    
if(i==2 && j==2){    
break;//will break loop of j only    
}    
}//end of for loop    
return 0;  
}    

Kết quả:

1 1
1 2
1 3
2 1
2 2
3 1
3 2
3 3

Như bạn thấy đầu ra trên bảng kết quẢ, 2 3 không được in vì có lệnh break  sau khi in i == 2 và j == 2. Nhưng 3 1, 3 2 và 3 3 được in vì lệnh break chỉ có tác động bên trong vòng for trong (for(j=1;j<=3;j++).


 

Lệnh Continue trong c

Lệnh continue là lệnh mà khi gặp nó thì chương trình sẽ bỏ qua những câu lệnh phía dưới nó(trong cùng 1 câu lệnh lặp) để thực hiện 1 vòng lặp mới.
Cú pháp:

continue;

Ví dụ lệnh continue trong C:

#include<stdio.h>  
int main(){  
int i=1;//initializing a local variable       
//starting a loop from 1 to 10    
for(i=1;i<=10;i++){      
if(i==5){//if value of i is equal to 5, it will continue the loop    
continue;    
}    
printf("%d \n",i);    
}//end of for loop    
return 0;  
}    

Kết quả: 

1
2
3
4
6
7
8
9
10

Ví dụ trên ta thấy số 5 không được in


Ví dụ lệnh continue trong vòng lặp lồng nhau:

#include<stdio.h>  
int main(){  
  int i=1,j=1;//initializing a local variable    
  for(i=1;i<=3;i++){      
  for(j=1;j<=3;j++){    
  if(i==2 && j==2){    
   continue;//will continue loop of j only    
  }    
  printf("%d %d\n",i,j);    
 }    
}//end of for loop    
return 0;  
}    

Kết quả:

1 1
1 2
1 3
2 1
2 3
3 1
3 2
3 3

Ví dụ trên ta thấy 2,2 không được in. Vì vòng lặp trong tại vị trí i==2 và j==2 có lệnh continue


 

Lệnh go trong ngôn ngữ C

Trong ngôn ngữ C để nhảy (jump) đến nhãn được định nghĩa trước chúng ta dùng lệnh go

Cú pháp:

goto label;  

Ví dụ dùng lệnh go:

#include <stdio.h>  
int main() {  
  int age;  
   ineligible:  
   printf("You are not eligible to vote!\n");  
  
   printf("Enter you age:\n");  
   scanf("%d", &age);  
   if(age<18)  
        goto ineligible;  
   else  
        printf("You are eligible to vote!\n");  
  
   return 0;  
}  

Kết quả:

You are not eligible to vote!
Enter you age:
11
You are not eligible to vote!
Enter you age:
44
You are eligible to vote!

 

Hàm Trong C (Funtions)

Một chương trình được viết trong ngôn ngữ C gọi là một dãy các hàm, trong đó có một hàm chính ( hàm main()). Hàm chia các bài toán lớn thành các công việc nhỏ hơn giúp thực hiện những công việc lặp lại nào đó một cách nhanh chóng mà không phải viết lại đoạn chương trình. Thứ tự các hàm trong chương trình C  là bất kỳ, song chương trình bao giờ cũng đi thực hiện từ hàm main(). Hàm có thể xem là một đơn vị độc lập của chương trình. Hàm trong C có vai trò ngang nhau, vì vậy không có phép xây dựng một hàm bên trong các hàm khác.


Các tiện ích của hàm

  1. Tái sử dụng
    Là một module chương trình, giải quyết một công việc hoàn chỉnh, được dùng nhiều lần trong chương trình
  2. Tối ưu mã (code)
    • Tránh việc viết lại các đoạn trình giống nhau trong chương trình
    • Phân cấp (chia) chương trình theo tư tưởng: chia để trị => chương trình dễ hiểu, dễ quản lý, dễ bảo trì

 Các loại hàm trong C

Có hai loại hàm trong ngôn ngữ C

  1. Các hàm thư viện (Library Functions): Là các hàm được khai báo trong tập tin header của C như: scanf(), printf(), gets(), puts(), ceil(), floor() v.v..
  2. Các hàm do người lập trình định nghĩa (User-defined functions): Là các hàm do lập trình viên định nghĩa. 

 


Khai báo hàm

Cú pháp khai báo một hàm trong ngôn ngữ C:

kieu_ham ten_ham (danh sach tham so){
/* noi dung cua ham */
}

Trong đó :

  • kieu_ham : là một kiểu dữ liệu chuẩn của C, hoặc kiểu do người dùng tự định nghĩa
  • ten_ham : được đặt theo quy tắc của tên biến, có phân biệt chữ hoa với chữ thường
  • danh sach tham so : các tham số hình thức của  các hàm trong c

Giá trị trả về

Một hàm trong C có thể có giá trị trả về hoặc không có giá trị trả về. Trường hợp hàm không có giá trị, sử dụng từ khóa void để mô tả kiểu của hàm.

Ví dụ hàm không có giá trị trả vê:

void hello(){  
printf("hello c");  
}  

Nếu một hàm có giá trị trả về, chúng ta cần sử dụng kiểu dữ liệu như: int, long, char .v.v. Dữ liệu trả về phụ thuộc vào kiểu khai báo của hàm

Ví dụ hàm có giá trị trả về:

int get(){  
return 10;  
}  

Ví dụ trên về là số 10 kiểu dữ liệu số nguyên. Nếu chúng ta muốn trả về kiểu số thực thì phải khai báo float trước tên hàm

float get(){  
return 10.2;  
}  

Vị trí của hàm

  • Có thể khai báo sau hoặc trước hàm main() trong c.
  • Nếu khai báo sau hàm main() thì phải khai báo prototype của hàm ở đầu chương trình, sau đó phần triển khai nội dung hàm được đặt sau hàm main()
  • Funtion prototype:
    • Khai báo kiểu hàm, tên hàm và các tham số , kết thúc bằng dấu chấm phẩy.
    • Ví dụ : int SUM (int x , int y);        => prototype của hàm SUM
    • Chú ý : Trong phần triển khai của hàm , thì danh sách tham biến và kiểu dữ liệu của hàm phải trùng khớp với những gì đã khai báo trong phần prototype

Lời gọi hàm

  • Hàm được gọi bất kì nơi đâu trong chương trình, có thể từ hàm main() hoặc một hàm khác trong chương trình.
  • Khi hàm A muốn gọi hàm B thì hoặc là B phải triển khai trước A hoặc là B đã khai báo prototype ở đầu chương trình.
  • Hàm được gọi thông qua tên hàm và danh sách các tham số. Ví dụ : Sum(10,20) hoặc Sum(20,a),..
  • Hàm có thể được gọi theo nhiều cách khác nhau
  • Trong C, không có các hàm lồng nhau

Các tham số trong ngôn ngữ C

Một hàm trong ngôn ngữ C không có tham số hoặc nhiều tham số
Ví dụ hàm không có tham số:

void hello(){  
printf("hello c");  
}  

Ví dụ hàm có một tham số:

int add(int a, int b){  
return a+b;  
}  

Cách gọi một hàm trong ngôn ngữ C

Nếu hàm có giá trị trả về, chúng ta nhận giá trị của hàm. Cú pháp gọi một hàm trong ngôn ngữ C như sau:

variable=function_name(arguments...);  

1) variable: Nếu hàm có kiểu dữ liệu là void, không cần khai báo variable, bởi vì hàm void không có giá trị trả về.

2) function_name: Là tên hàm sẽ được gọi.

3) arguments: Truyền các tham số cho hàm.

Ví dụ gọi một hàm:

hello();//Gọi hàm không có giá trị trả về
int value=get();//Gọi hàm có giá trị trả về
int value2=add(10,20);//gọi hàm truyền 2 tham số  

Ví dụ về hàm không có giá trị trả về:

#include<stdio.h>  
void hello(){    
printf("hello c programming \n");    
}    
int main(){        
hello();//gọi hàm
hello();    
hello();    
return 0;  
}    

Kết quả:

hello c programming
hello c programming
hello c programming

Ví dụ về hàm có giá trị trả về:

#include<stdio.h>  
//defining function      
int cube(int n){    
return n*n*n;    
}    
int main(){        
int result1=0,result2=0;      
    
result1=cube(2);//calling function    
result2=cube(3);      
        
printf("%d \n",result1);    
printf("%d \n",result2);    
return 0;  
}    

Kết quả:

8
27

 

Truyền tham chiếu và tham trị trong C

Có hai cách truyền tham số cho hàm: Tham  trị và Tham chiếu (biến) :

Truyền tham chiếu là truyền địa chỉ ô nhớ của biến, do đó khi thay đổi giá trị của biến bên trong phương thức thì giá trị của biến cũng bị thay đổi bên ngoài phương thức.

Truyền tham trị là truyền giá trị của biến (không phải là địa chỉ ô nhớ), khi đó phương thức sẽ tự động tạo ra một địa chỉ ô nhớ mới để lưu trữ giá trị này, do đó nó chỉ được thay đổi trong phương thức hiện hành và giá trị của biến không bị thay đổi bên ngoài phương thức hiện hành.

 

 
Hãy xem các ví dụ sau để hiểu rõ về truyền tham chiếu và truyền giá trị trong C.


Truyền theo tham trị

Truyền theo tham trị, giá trị được truyền cho hàm được lưu trữ cục bộ bởi tham số của hàm trong vị trí ngăn xếp của bộ nhớ.

Chúng ta tìm hiểu ví dụ truyền tham  trị:

#include<stdio.h>
 
void change(int num) {
    num = num + 1;
}
 
int main() {
    int x = 100;
    printf("Truoc khi goi phuong thuc x = %d \n", x);
    change(x); // truyen tham tri vao phuong thuc
    printf("Sau khi goi phuong thuc x = %d \n", x);
    return 0;
}

Kết quả:

Truoc khi goi phuong thuc x = 100
Sau khi goi phuong thuc x = 100

Trong ví dụ trên, giá trị của biến x không bị thay đổi bên ngoài phương thức change(), mặc dù bên trong phương thức change() chúng ta đã cố gắng thay đổi bằng cách tăng m lên 1.
 


Truyền theo tham chiếu

Truyền theo tham chiếu giá trị ban đầu của biến bị thay đổi.

Lưu ý: để hiểu về truyền tham chiếu trong C, bạn phải có hiểu biết về con trỏ (pointer) trong C.

Chúng ta tìm hiểu ví dụ truyền tham chiếu:

Cách 1:

#include<stdio.h>
 
void change(int *num) {
    *num = *num + 1;
}
 
int main() {
    int x = 100;
    printf("Truoc khi goi phuong thuc x = %d \n", x);
    change(&x); // truyen tham chieu vao phuong thuc
    printf("Sau khi goi phuong thuc x = %d \n", x);
    return 0;
}

Cách 2:

#include<stdio.h>
 
void change(int &num) {
    num = num + 1;
}
 
int main() {
    int x = 100;
    printf("Truoc khi goi phuong thuc x = %d \n", x);
    change(x); // truyen tham chieu vao phuong thuc
    printf("Sau khi goi phuong thuc x = %d \n", x);
    return 0;
}

Kết quả:

Truoc khi goi phuong thuc x = 100
Sau khi goi phuong thuc x = 101

Trong ví dụ trên, cách 1 chúng ta thêm *x trong hàm change, còn cách 2 chúng ta thêm &x. Giá trị của biến x bị thay đổi cả bên trong và bên ngoài phương thức change()


 

Hàm đệ quy trong C

Một hàm được gọi là đệ quy nếu bên trong thân nó có một lời gọi đến chính nó. Nghe có vẻ vô lý nhỉ ? Một hàm làm sao có thể gọi nó mãi được, vì nếu như vậy sẽ sinh ra một vòng lặp vô tận. Nhưng trong thực tế, một hàm đệ quy luôn có điều kiện đừng được gọi là “điểm neo”. Khi đạt tới điểm neo, hàm sẽ không gọi chính nó nữa.

Cú pháp tổng quát:

void tenhamdequi()
{
   tenhamdequi(); /* goi chinh no */
}

int main()
{
   tenhamdequi();
}

Hàm đệ quy không thể gọi tới nó mãi, cần phải có một điểm dừng (còn gọi là điểm neo) tại một trường hợp đặc biệt, gọi là trường hợp suy biến (degenerate case).

Thành phần của một hàm đệ quy

Hàm đệ quy gồm 2 phần:

  • Phần cơ sở: Điều kiện thoát khỏi đệ quy
  • Phần đệ quy: Thân hàm có chứa lời gọi đệ quy

Thiết kế giải thuật đệ quy

Thực hiện 3 bước sau:

  • Tham số hóa bài toán
  • Phân tích trường hợp chung: Đưa bài toán về bài toán nhỏ hơn cùng loại, dần dần tiến tới trường hợp suy biến
  • Tìm trường hợp suy biến

Ưu và nhược điểm

Giải thuật đệ quy có ưu điểm là thuận lợi cho việc biểu diễn bài toán, đồng thời làm gọn chương trình. Tuy nhiên cũng có nhược điểm, đó là không tối ưu về mặt thời gian (so với sử dụng vòng lặp), gây tốn bộ nhớ.


Ví dụ tính giai thừa của N dùng đệ quy:

#include<stdio.h>  
int factorial (int n)    
{    
    if ( n < 0)    
        return -1; /*Wrong value*/    
    if (n == 0)    
        return 1; /*Terminating condition*/    
    return (n * factorial (n -1));    
}   
int main(){    
int fact=0;    
fact=factorial(5);    
printf("\n factorial of 5 is %d",fact);    
return 0;  
}    

Kết quả:

factorial of 5 is 120

Hàm trên hoạt động như hình sau:


 

Lớp lưu trữ (Storage Classes) trong C.

Lớp lưu trữ được sử dụng để định nghĩa phạm vi và chu trình sống của biến. Có 4 lớp lưu trữ trong ngôn ngữ C.

  • auto
  • extern
  • static
  • register
Storage Classes Storage Place Default Value Scope Life-time
auto RAM Garbage Value Local Bên trong hàm
extern RAM Zero Global Cho đến khi kết thúc chương trình, có thể khai báo bất kỳ ở đâu trong chương trình
static RAM Zero Local Cho đến khi kết thúc chương trình, Giá trị vẫn tồn tại trong nhiều lần gọi hàm
register Register Garbage Value Local Bên trong hàm

 

Mảng (array) trong C

Mảng (array) trong C là một tập hoặc một nhóm các phần tử (dữ liệu) có kiểu dữ liệu đồng nhất(tương tự). Các phần tử của mảng được lưu trong các vùng nhớ liên tiếp.

Mảng trong C là rất hữu ích nếu bạn muốn lưu trữ các phần tử tương tự. Giả sử bạn phải lưu trữ thông tin của 50 sinh viên. Bạn có thể làm điều này bằng việc sử dụng 50 biến, nhưng với cách này bạn sẽ khó quản lý vì bạn không thể truy cập giá trị của các biến này với chỉ 1 hoặc 2 dòng code.

Một cách khác để làm điều này là sử dụng mảng. Bằng cách sử dụng mảng, bạn có thể truy cập các phần tử một cách dễ dàng với chỉ vài dòng code.


Lợi thế của mảng trong C

  1. Tối ưu hóa code.
  2. Dễ dàng để duyệt các phần tử của mảng.
  3. Dễ dàng sắp xếp dữ liệu.
  4. Truy cập ngẫu nhiên.

Bất lợi của mảng trong C

  1. Kích thước cố định: Kích thước của mảng trong C phải được định nghĩa tại thời điểm khai báo, chúng ta không thể lưu số phần tử vượt quá kích thước này.

Khai báo mảng (array) trong C

Bạn có thể khai báo một mảng trong ngôn ngữ c theo cách sau.

data_type array_name[array_size];

Ví dụ:

int marks[5];

Ở đây, int là data_type, marks là array_name và 5 là array_size.


Khởi tạo mảng (array) trong C

Chú ý rằng chỉ số mảng bắt đầu từ 0 và kết thúc bằng [SIZE-1].

marks[0] = 80; // khoi tao mang
marks[1] = 60;  
marks[2] = 70;  
marks[3] = 85;  
marks[4] = 75;  


Ví dụ mảng trong C

#include<stdio.h>
 
int main() {
    int i = 0;
    int marks[5];  // khai bao mang
    marks[0] = 80; // khoi tao mang
    marks[1] = 60;
    marks[2] = 70;
    marks[3] = 85;
    marks[4] = 75;
    //duyet mang
    for (i = 0; i < 5; i++) {
        printf("%d \n", marks[i]);
    }
    return 0;
}

Kết quả:

80
60
70
85
75

Khai báo với khởi tạo mảng nặc danh trong C

Trong lập trình C, chúng ta có thể khởi tạo mảng nặc danh khi khai báo mảng.
Ví dụ:

int marks[5] = {20, 30, 40, 50, 60};

Trong trường hợp này, mảng marks có kích thước bằng kích thước của mảng nặc danh.

Ví dụ về mảng nặc danh số nguyên:

#include<stdio.h>
 
int main() {
    int i = 0;
    // khai bao mang nac danh
    int marks[5]={20, 30, 40, 50, 60};
    //duyet mang
    for (i = 0; i < 5; i++) {
        printf("%d \n", marks[i]);
    }
    return 0;
}

Kết quả:

20
30
40
50
60

Ví dụ về mảng nặc danh có kiểu dữ liệu là char:

#include<stdio.h>
 
int main() {
    int i = 0;
    // khai bao mang nac danh
    char c[5]={'h', 'o', 'c', ' ', 'C'};
    //duyet mang
    for (i = 0; i < 5; i++) {
        printf("%c", c[i]);
    }
    return 0;
}

Kết quả:

hoc C

 

Mảng 2 chiều trong C

Mảng 2 chiều trong C được biểu diễn dưới dạng hàng và cột, còn được gọi là ma trận. Nó còn được gọi là mảng các mảng hoặc danh sách các mảng.

Mảng 2 chiều, 3 chiều hoặc n chiều được gọi là mảng đa chiều trong C.


Khai báo mảng 2 chiều trong C

data_type array_name[size1][size2];

Ví dụ:

int ma_tran [4][3];

Ở đây, 4 là số hàng và 3 là số cột.


Khởi tạo mảng 2 chiều trong C

1. Khởi tạo mang 2 chieu bằng mảng nặc danh.

#include<stdio.h>
 
int main() {
    int i = 0;
    int j = 0;
    // khai bao mang 2 chieu bang mang nac danh
    int ma_tran[4][3] = {{ 1, 2, 3 }, {2, 3, 4}, {3, 4, 5}, {4, 5, 6}};
    //duyet mang
    for (i = 0; i < 4; i++) {
        for (j = 0; j < 3; j++) {
            printf("%d ", ma_tran[i][j]);
        }
        printf("\n");
    }
    return 0;
}

Kết quả:

1 2 3
2 3 4
3 4 5
4 5 6

2. Khởi tạo mảng 2 chiều bằng cách nhập data từ bàn phím.

#include<stdio.h>
 
int main() {
    int i, j;
     
    // khai bao mang 2 chieu bang mang nac danh
    int ma_tran[4][3];
     
    //nhap mang
    printf("Nhap mang: \n");
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 3; j++) {
            printf("Nhap a[%d][%d] = ", i, j);
            scanf("%d", &ma_tran[i][j]);
        }
        printf("\n");
    } 
     
    //duyet mang
    printf("Ket qua: \n");
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", ma_tran[i][j]);
        }
        printf("\n");
    }
    return 0;
}

Kết quả:

Nhap mang:
Nhap a[0][0] = 1
Nhap a[0][1] = 2
Nhap a[0][2] = 3

Nhap a[1][0] = 4
Nhap a[1][1] = 5
Nhap a[1][2] = 6

Nhap a[2][0] = 7
Nhap a[2][1] = 8
Nhap a[2][2] = 9

Nhap a[3][0] = 9
Nhap a[3][1] = 6
Nhap a[3][2] = 3

Ket qua:
1 2 3
4 5 6
7 8 9
9 6 3

 

Truyền mảng dưới dạng tham số hàm trong C

Muốn truyền một mảng một chiều dưới dạng tham số trong một hàm, bạn sẽ phải khai báo tham số chính thức của hàm theo một trong 3 cách sau và tất cả 3 phương thức khai báo này đều tạo kết quả giống nhau.

Cách 1
Các tham số chính thức là một con trỏ như sau.

return_type function(type *arrayname)  

Cách 2
Các tham số chính thức là một mảng đã định kích cỡ như sau:

return_type function(type arrayname[SIZE])  

Cách 3
Các tham số chính thức là một mảng chưa định kích cỡ như sau:

return_type function(type arrayname[])  

Ví dụ truyền tham số mảng cho hàm:

#include<stdio.h>  
int minarray(int arr[],int size){    
int min=arr[0];    
int i=0;    
for(i=1;i<size;i++){    
if(min>arr[i]){    
min=arr[i];    
}    
}//end of for    
return min;    
}//end of function    
    
int main(){      
int i=0,min=0;    
int numbers[]={4,5,7,3,8,9};//declaration of array    
  
min=minarray(numbers,6);//passing array with size    
printf("minimum number is %d \n",min);    
return 0;  
}    

Kết quả:

minimum number is 3

 

Con trỏ (pointer) trong C

Con trỏ (Pointer) trong C là một biến, nó còn được gọi là locator hoặc indicator chỉ ra một địa chỉ của một giá trị.


Các biểu tượng được sử dụng trong con trỏ

Biểu tượng Tên Mô tả
& Địa chỉ của toán tử Xác định địa chỉ của một biến.
* Toán tử liên kết. Truy cập đến giá trị của địa chỉ.

Toán tử địa chỉ

Toán tử địa chỉ ‘&’ trả về địa chỉ của một biến, bạn cần phải sử dụng ‘%x’ để hiện thị địa chỉ của một biến.

#include<stdio.h>  
 
int main() {
    int number = 50;
    printf("Gia tri cua number la %d\n", number);
    printf("Dia chi cua number la %x", &number);
    return 0;
}

Kết quả:

Gia tri cua number la 50
Dia chi cua number la 23fe4c

Khai báo con trỏ trong C

Con trỏ bằng ngôn ngữ C được khai báo bằng cách sử dụng dấu ‘*’.

int *a;  //con tro tro toi int
char *c; //con tro tro toi char

Ví dụ con trỏ trong C

Ví dụ 1: sử dụng con trỏ để in ra màn hình địa chỉ và giá trị mà con trỏ trỏ đến.

Ví dụ con trỏ trong C

Như bạn thấy trong hình trên, biến con trỏ lưu trữ địa chỉ của biến số ví dụ fff4. Giá trị của biến số là 50. Nhưng địa chỉ của biến con trỏ p là aaa3.

Bằng cách sử dụng toán tử * ( toán tử liên kết ), chúng ta có thể in giá trị của biến con trỏ p.

#include<stdio.h>
 
int main() {
    int number = 50;
    int *p;
    p = &number; // luu tru dia chi cua bien number
    printf("Dia cua con tro p la %d\n", *p);
    printf("Dia chi cua con tro p la %x", p);
    return 0;
}

Kết quả:

Dia cua con tro p la 50
Dia chi cua con tro p la 23fe44

Ví dụ 2: sử dụng con trỏ để hoán đổi 2 số mà không sử dụng biến số thứ 3.

#include<stdio.h>  
 
int main() {
    int a = 10, b = 20;
    int *p1 = &a,*p2 = &b;  
    printf("Truoc khi hoan doi: *p1=%d *p2=%d\n", *p1, *p2);
    // hoan doi
    *p1 = *p1 + *p2;
    *p2 = *p1 - *p2;
    *p1 = *p1 - *p2;
    printf("Sau khi hoan doi: *p1=%d *p2=%d", *p1, *p2);
    return 0;
}

Kết quả:

Dia cua con tro p la 50
Dia chi cua con tro p la 23fe44

Con trỏ NULL (NULL Pointer)

Một con trỏ không được gán bất kỳ giá trị nào được gọi là con trỏ NULL. Nếu không có địa chỉ nào được chỉ định trong con trỏ tại thời điểm khai báo, bạn có thể chỉ định giá trị NULL. Đó là một cách tiếp cận tốt hơn.

int *p = NULL;

Trong hầu hết các thư viện, giá trị của con trỏ là 0 (zero).
 


Sử dụng con trỏ trong C

Có rất nhiều cách sử dụng con trỏ trong lập trình C.

Phân bổ bộ nhớ động

Trong ngôn ngữ C, chúng ta có thể tự động phân bổ bộ nhớ bằng các hàm malloc() và calloc() nơi con trỏ được sử dụng.

Mảng, hàm và cấu trúc (structure)

Con trỏ trong ngôn ngữ c được sử dụng rộng rãi trong các mảng, các hàm và cấu trúc. Nó giúp chúng ta viết ít code hơn và cải thiện hiệu suất. Ví dụ, sử dụng con trỏ trong việc truyền tham chiếu trong C.
 


Con trỏ trỏ tới con trỏ trong C

Như bạn đã biết bản chất của con trỏ trong C là nó trỏ đến địa chỉ ô nhớ của một giá trị, con trỏ cũng là một biến. Vậy khái niệm con trỏ trỏ tới con trỏ trong C là con trỏ trỏ đến địa chỉ ô nhớ của một con trỏ khác.


Cú pháp

Cú pháp của con trỏ trỏ tới con trỏ.

int **p2;

Ví dụ con trỏ trỏ tới con trỏ trong C

Hãy xem một ví dụ về một con trỏ trỏ đến địa chỉ của một con trỏ khác.

Ví dụ con trỏ trỏ tới con trỏ trong C

Như bạn thấy trong hình trên, p2 chứa địa chỉ của p (fff2) và p chứa địa chỉ của biến number (fff4).

#include<stdio.h>
 
int main() {
    int number = 50;
    int *p;      //con tro tro toi int
    int **p2;    //con tro tro toi con tro
    p = &number; //luu tru dia chi cua bien number
    p2 = &p;
    printf("Dia chi cua bien number la %x \n", &number);
    printf("Dia chi cua bien p la %x \n", p);
    printf("Gia tri cua bien *p la %d \n", *p);
    printf("Dia chi cua bien p2 la %x \n", p2);
    printf("Gia tri cua bien **p2 la %d \n", **p2);
    return 0;
}

Kết quả:

Dia chi cua bien number la 23f
Dia chi cua bien p la 23fe44
Gia tri cua bien *p la 50
Dia chi cua bien p2 la 23fe38
Gia tri cua bien **p2 la 50

Các phép toán trên con trỏ

Về mặt bản chất, giá trị lưu trữ bên trong vùng nhớ của con trỏ là địa chỉ, địa chỉ của một biến (hoặc vùng nhớ) có kiểu unsigned int (số nguyên không dấu), do đó, chúng ta có thể thực hiện các phép toán trên con trỏ. Nhưng kết quả của các phép toán thực hiện trên con trỏ sẽ khác các phép toán số học thông thường về giá trị và cả ý nghĩa.

Ngôn ngữ C/C++ định nghĩa cho chúng ta 4 toán tử toán học có thể sử dụng cho con trỏ: ++, --, +, và -.


Increment operator (++)

Như các bạn đã được học, increment operator (++) được dùng để tăng giá trị bên trong vùng nhớ của biến lên 1 đơn vị. Increment operator (++) là toán tử một ngôi, có thể đặt trước tên biến, hoặc đặt sau tên biến

Công thức

new_address= current_address + i * size_of(data type)  

32 bit

Win 32 bit biến số nguyên sẽ tăng lên 2 byte.

64 bit

Win 64 bit biến số nguyên sẽ tăng lên 4 byte.

Ví dụ tăng biến con trỏ nguyên tăng lên 1 trên win 64 bit

#include<stdio.h>  
int main(){  
int number=50;        
int *p;//pointer to int      
p=&number;//stores the address of number variable        
printf("Address of p variable is %u \n",p);        
p=p+1;       
printf("After increment: Address of p variable is %u \n",p);      
return 0;  
}    

Kết quả:

Address of p variable is 3214864300 
After increment: Address of p variable is 3214864304 

Decrement operator (--)

Ngược lại so với increment operator (++), decrement operator (--) sẽ giảm giá trị bên trong vùng nhớ của biến thông thường đi 1 đơn vị. Đối với biến con trỏ, khi sử dụng decrement operator (--), nó sẽ làm thay đổi địa chỉ của con trỏ đang trỏ đến, giá trị địa chỉ mới sẽ bằng giá trị địa chỉ cũ trừ đi kích thước của kiểu dữ liệu mà con trỏ đang trỏ đến.

Công thức tính:

new_address= current_address - i * size_of(data type)  

32 bit

Win 32 bit biến số nguyên sẽ giảm lên 2 byte.

64 bit

Win 64 bit biến số nguyên sẽ giảm lên 4 byte.

Ví dụ tăng biến con trỏ nguyên giảm đi 1 trên win 64 bit

#include <stdio.h>            
void main(){            
int number=50;        
int *p;//pointer to int      
p=&number;//stores the address of number variable        
printf("Address of p variable is %u \n",p);        
p=p-1;       
printf("After decrement: Address of p variable is %u \n",p);        
}      

Kết quả:

Address of p variable is 3214864300 
After decrement: Address of p variable is 3214864296 

Phép toán cộng con trỏ trong C

Sử dụng increment operator (++) cho con trỏ chỉ có thể làm con trỏ trỏ đến địa chỉ tiếp theo trên bộ nhớ ảo bắt đầu từ địa chỉ ban đầu mà con trỏ đang nắm giữ. Trong khi đó, toán tử addition (+) cho phép chúng ta trỏ đến vùng nhớ bất kỳ phía sau địa chỉ mà con trỏ đang nắm giữ.

new_address= current_address + (number * size_of(data type))  

32 bit

Win 32 bit biến số nguyên sẽ được cộng thêm 2 * number.

64 bit

Win 64 bit biến số nguyên sẽ được cộng thêm 4 * number.

Ví dụ cộng thêm giá trị cho con trỏ trên win 64 bit

#include<stdio.h>  
int main(){  
int number=50;        
int *p;//pointer to int      
p=&number;//stores the address of number variable        
printf("Address of p variable is %u \n",p);        
p=p+3; //subtracting 3 from pointer variable    
printf("After subtracting 3: Address of p variable is %u \n",p);        
return 0;  
}    

Kết quả:

Address of p variable is 3214864300 
After adding 3: Address of p variable is 3214864312

Địa chỉ của p là 3214864300. Nhưng sau khi cộng thêm 3 cho biến p sẽ là 3214864312 vì 4*3=12 tăng thêm 12. Bởi vì, ví dụ đang sử dụng Win 64 bit. Nhưng nếu chúng ta sử dụng Win 32 bit, nó chỉ tăng 6, Vì 2*3=6 . Giá trị số nguyên sẽ chiếm lấy 2 byte bộ nhớ trong Win 32 bit. 


Phép toán trừ con trỏ trong C

C Pointer Subtraction

Giống như phép toán cộng, chúng ta có thể trừ giá trị từ biến con trỏ. Công thức tính:

new_address= current_address - (number * size_of(data type))  

 32 bit

Win 32 bit biến số nguyên sẽ được giảm thêm 2 * number.

64 bit

Win 64 bit biến số nguyên sẽ được giảm thêm 4 * number.

Ví dụ trừ giá trị cho con trỏ trên win 64 bit

#include<stdio.h>  
int main(){  
int number=50;        
int *p;//pointer to int      
p=&number;//stores the address of number variable        
printf("Address of p variable is %u \n",p);        
p=p-3; //subtracting 3 from pointer variable    
printf("After subtracting 3: Address of p variable is %u \n",p);        
return 0;  
}    

Kết quả: 

Address of p variable is 3214864300 
After subtracting 3: Address of p variable is 3214864288

Sau khi trừ giá trị 3 từ biến con trỏ, nó sẽ giảm đi (3*4) =12 từ giá trị ban đầu.

Con trỏ void trong ngôn ngữ C

Tuy nhiên bởi vì con trỏ void không biết loại của đối tượng mà nó trỏ đến là lại gì, cho nên nó không thể derefenced(nghĩa là ko thể thực hiện toán tử * để lấy giá trị của con trỏ void). Nghĩa là, con trỏ void trước hết phải được ép kiểu sang một loại con trỏ khác trước khi nó được khai báo :

Ví dụ:

void *px, *py;
int x = 1;
float y = 0.5;
px = &x;
py = &y;
printf("%d %f",*(int*)px,*(float*)py);

 

Con trỏ hàm là gì?

Con trỏ hàm là một biến lưu trữ địa chỉ của một hàm, thông qua biến đó, ta có thể gọi hàm mà nó trỏ tới. Điều này rất thuận tiện khi bạn muốn định nghĩa các chức năng khác nhau cho một nhóm các đối tượng khá giống nhau. (Như ví dụ về Button ở trên).

Sử dụng con trỏ hàm như thế nào?

Một con trỏ hàm có thể khởi tạo theo mẫu sau:

<kiểu trả về> (*<tên con trỏ>)(<danh sách đối số>);

Ví dụ về con trỏ hàm nhận vào một biến kiểu int và trả về dữ liệu kiểu void.

void (*func)(int);

Nhưng đây mới chỉ là khai báo, cũng giống như mọi con trỏ khác, con trỏ hàm phải được định nghĩa giá trị trước khi sử dụng, nhưng chúng ta không thể dùng từ khóa new hay malloc để cấp phát vùng nhớ cho một con trỏ hàm, vì như thế thì chẳng cách nào định nghĩa được các lệnh của nó, hơn nữa vùng nhớ của lệnh và của biến cũng khác nhau vậy chỉ còn một cách là cho nó trỏ đến một vùng nhớ lưu trữ giá trị khai báo sẵn.
Về bản chất, máy chỉ hiểu được các lệnh mã máy với 0 và 1, nên không chỉ có biến hay con trỏ, các câu lệnh cũng có địa chỉ của riêng nó.

Cũng nhưng những con trỏ thông thường, chúng ta có thể truyền địa chỉ của một hàm vào con trỏ với cách đơn giản như sau:

void thefunc(int a)
{
	// DO SOMETHING
}
int main()
{
	// ...
	void (*func)(int);
	func = &thefunc;
	// ...
}

Và để gọi một hàm đã lưu trữ trong con trỏ hàm, ta chỉ cần gọi con trỏ với một danh sách đối số phù hợp:

func(1); 
// OR
(*func)(1);

Lưu ý là con trỏ hàm và hàm được trỏ đến phải có cùng danh sách đối số và kiểu trả về.

Truyền hàm vào hàm

Do con trỏ hàm được khai báo dựa theo kiểu trả về và danh sách đối số của hàm sẽ được trỏ đến nên để thuận tiện hơn trong các thao tác xử lý, ta nên định kiểu cho mỗi kiểu con trỏ hàm để nó có một cái tên nhất định (thông qua từ khóa typedef). Chẳng hạn như:

typedef int (*Func_int)();

Vậy là ta đã có thể sử dụng kiểu dữ liệu Func_int như một kiểu dữ liệu định nghĩa các con trỏ hàm không đối số trả về một phần tử kiểu int.

Theo đó, ta có thể yêu cầu một đối số func_int từ một hàm, như sau:

void foo(func_int fun, int a)
{
	// DO SOMETHING
	// ...
}

Và thao tác truyền hàm vào hàm được thực hiện như sau:

typedef int (*func_int)();
 
void foo(func_int fun, int a)
{
	// DO SOMETHING
	// ...
}
 
int doSomething()
{
	// DO SOMETHING
	// ...
}
 
int main()
{
	// ...
	foo(&doSomething, 0);
	// ...
}

 

Cấp phát động trong C

Ngôn ngữ C cung cấp cho chúng ta 4 hàm dùng để cấp phát và giải phóng bộ nhớ động, nhằm giải quyết các vấn đề liên quan đến bộ nhớ.Các hàm này đều nằm trong thư viện stdlib.h

  1. malloc()
  2. calloc()
  3. realloc()
  4. free()

Trước khi tìm hiểu các hàm trên chúng ta phân biệt giữa bộ nhớ động với bộ nhớ động

Bộ nhớ tĩnh Bộ nhớ động
Bộ nhớ được cấp phát tại thời điểm dịch chương trình. Bộ nhớ được cấp phát tại thời điểm chạy chương trình.
Bộ nhớ không thể tăng khi chương trình đang chạy. Bộ nhớ có thể tăng khi chương trình đang chạy.
Thường sử dụng mảng. Được sử dụng trong danh sách liên kết.

1. Trước hết là hàm malloc(): 

Hàm này dùng để cấp phát bộ nhớ động cho một mảng với size_t num là số phần tử của mảng.
Hàm này không khởi tạo bộ nhớ tại thời điểm chạy chương trình
Trả về giá trị NULL nếu bộ nhớ không đủ
Cú pháp:

ptr=(cast-type*)malloc(byte-size)  

Ví dụ về hàm malloc()

#include<stdio.h>  
#include<stdlib.h>  
int main(){  
  int n,i,*ptr,sum=0;    
    printf("Enter number of elements: ");    
    scanf("%d",&n);    
    ptr=(int*)malloc(n*sizeof(int));  //memory allocated using malloc    
    if(ptr==NULL)                         
    {    
        printf("Sorry! unable to allocate memory");    
        exit(0);    
    }    
    printf("Enter elements of array: ");    
    for(i=0;i<n;++i)    
    {    
        scanf("%d",ptr+i);    
        sum+=*(ptr+i);    
    }    
    printf("Sum=%d",sum);    
    free(ptr);     
return 0;  
}    

Kết quả:

Enter elements of array: 3
Enter elements of array: 10
10
10
Sum=30

2. Hàm calloc() trong C

Hàm này cấp phát nhiều khối khi bộ nhớ yêu cầu
Khởi tạo các giá trị ban đầu là 0.
Trả về giá trị NULL nếu bộ nhớ không đủ.

Cú pháp:

ptr=(cast-type*)calloc(number, byte-size)  

Ví dụ về hàm calloc()

#include<stdio.h>  
#include<stdlib.h>  
int main(){  
 int n,i,*ptr,sum=0;    
    printf("Enter number of elements: ");    
    scanf("%d",&n);    
    ptr=(int*)calloc(n,sizeof(int));  //memory allocated using calloc    
    if(ptr==NULL)                         
    {    
        printf("Sorry! unable to allocate memory");    
        exit(0);    
    }    
    printf("Enter elements of array: ");    
    for(i=0;i<n;++i)    
    {    
        scanf("%d",ptr+i);    
        sum+=*(ptr+i);    
    }    
    printf("Sum=%d",sum);    
    free(ptr);    
return 0;  
}    

Kết quả:

Enter elements of array: 3
Enter elements of array: 10
10
10
Sum=30

3. Hàm realloc() trong C

Nếu 2 hàm malloc() và calloc() không đủ bộ nhớ, chúng ta có thể cấp thêm bộ nhớ bằng hàm realloc(), nó sẽ thay đổi kích thước bộ nhớ.

Cú pháp:

ptr=realloc(ptr, new-size)  

4. Hàm free() trong C

Dùng để giải phóng vùng nhớ đã cấp phát.

Cú pháp :

free(ptr)

 

Cấu trúc (structure) trong C

Structure trong C (cấu trúc trong C) là một kiểu dữ liệu người dùng tự định nghĩa (user defined datatype) cho phép bạn lưu trữ các loại phần tử khác nhau.

Mỗi phần tử của một cấu trúc được gọi là một thành viên (member).

Nó hoạt động như một template trong C++ và lớp trong Java. Bạn có thể khai báo các loại phần tử khác nhau trong đó.


Định nghĩa cấu trúc trong C
Từ khóa struct được sử dụng để xác định cấu trúc. Hãy xem cú pháp để định nghĩa cấu trúc trong
C.

struct structure_name {
    data_type member1;
    data_type member2;
    ...
    data_type memeberN;
};

Ví dụ định nghĩa cấu trúc của Employee trong C.

struct employee {
    int id;
    char name[50];
    float salary;
};

Khai báo biến cấu trúc

Có hai cách để khai báo biến cấu trúc:

  1. Sử dụng từ khóa struct trong hàm main().
  2. Khai báo biến tại thời điểm định nghĩa cấu trúc.

1. Cách 1
Khai báo biến cấu trúc bên trong hàm main(), ví dụ:

struct employee {
    int id;
    char name[50];
    float salary;
};
 
int main() {
    struct employee e1, e2;
}

2. Cách 2
Khai báo biến cấu trúc tại thời điểm định nghĩa cấu trúc, ví dụ:

struct employee {
    int id;
    char name[50];
    float salary;
} e1, e2;

Cách tiếp cận nào tốt hơn?

Khi số lượng biến không cố định, sử dụng phương pháp tiếp cận thứ nhất. Nó cung cấp cho bạn sự linh hoạt để khai báo biến cấu trúc nhiều lần. Khi số lượng biến được cố định, sử dụng phương pháp thứ 2.


Truy cập các thành viên của cấu trúc

Có hai cách để truy cập vào các thành viên cấu trúc:

  1. Bởi . (thành viên hoặc toán tử chấm).
  2. Bởi ->(toán tử con trỏ cấu trúc).

Ví dụ:

e1.id = 17;
e1.name = "Vinh";
e1.salary = 1000;

Ví dụ cấu trúc (structure) trong C
Ví dụ 1: lưu trữ thông tin của một employee.

#include<stdio.h>
#include <string.h>
 
struct employee {
    int id;
    char name[50];
    float salary;
} e1; // khai bao bien e1
 
int main() {
    // luu tru thong tin employee
    e1.id = 17;
    strcpy(e1.name, "Vinh Tran"); // sao chep string thanh mang char
    e1.salary = 1000;
    // hien thi thong tin employee ra man hinh
    printf("employee 1 id : %d\n", e1.id);
    printf("employee 1 name : %s\n", e1.name);
    printf("employee 1 salary : %f\n", e1.salary);
    return 0;
}


Kết quả:

employee 1 id : 17
employee 1 name : Vinh Tran
employee 1 salary : 1000.000000


Ví dụ 2: Lưu trữ thông tin của nhiều employee.

#include<stdio.h>
#include <string.h>
 
struct employee {
    int id;
    char name[50];
    float salary;
};
 
int main() {
    // khai bao employee e1, e2
    struct employee e1, e2;
     
    // luu tru thong tin employee e1
    e1.id = 17;
    strcpy(e1.name, "Vinh Tran"); // sao chep string thanh mang char
    e1.salary = 1000;
    // luu tru thong tin employee e2
    e2.id = 37;
    strcpy(e2.name, "Quy Pham"); // sao chep string thanh mang char
    e2.salary = 1700;    
     
    // hien thi thong tin employee e1 ra man hinh
    printf("employee 1 id : %d\n", e1.id);
    printf("employee 1 name : %s\n", e1.name);
    printf("employee 1 salary : %f\n", e1.salary);
    // hien thi thong tin employee e2 ra man hinh
    printf("employee 2 id : %d\n", e2.id);
    printf("employee 2 name : %s\n", e2.name);
    printf("employee 2 salary : %f\n", e2.salary);    
    return 0;
}

Kết quả:

employee 1 id : 17
employee 1 name : Vinh Tran
employee 1 salary : 1000.000000
employee 2 id : 37
employee 2 name : Quy Pham
employee 2 salary : 1700.000000

 

Mảng của structure trong C

Bạn có thể khai báo và sử dụng mảng của structure trong C để lưu trữ nhiều thông tin của các loại dữ liệu khác nhau.

Ví dụ về cấu trúc với mảng lưu trữ thông tin của 5 sinh viên và in các phần tử của nó ra màn hình.

#include<stdio.h>
#include <string.h>
 
struct student {
    int id;
    char name[10];
};
 
int main() {
    int i;
    struct student st[5];
    printf("Nhap thong tin cho 5 sinh vien: \n");
    for (i = 0; i < 5; i++) {
        printf("Nhap id: ");
        scanf("%d", &st[i].id);
        printf("Nhap name: ");
        scanf("%s", &st[i].name);
    }
    printf("Danh sach sinh vien: \n");
    for (i = 0; i < 5; i++) {
        printf("Id: %d, Name: %s\n", st[i].id, st[i].name);
    }
    return 0;
}


Kết quả:

Nhap thong tin cho 5 sinh vien:
Nhap id: 1
Nhap name: Tan
Nhap id: 2
Nhap name: Vinh
Nhap id: 3
Nhap name: Hoa
Nhap id: 4
Nhap name: Phu
Nhap id: 5
Nhap name: Quy
Danh sach sinh vien:
Id: 1, Name: Tan
Id: 2, Name: Vinh
Id: 3, Name: Hoa
Id: 4, Name: Phu
Id: 5, Name: Quy

 

Structure lồng nhau trong C

Như bạn đã biết structure trong C (cấu trúc trong C) là một kiểu dữ liệu người dùng tự định nghĩa (user defined datatype). Nên bạn hoàn toàn có thể sử dụng structure bên trong structure khác, nó được biết đến như structure lồng nhau trong C.

Có 2 cách để định nghĩa cấu trúc lồng nhau trong C:

  1. Theo cấu trúc riêng biệt.
  2. Theo cấu trúc nhúng.

1. Cấu trúc riêng biệt

Ví dụ, chúng ta tạo ra 2 cấu trúc và cấu trúc phụ thuộc được sử dụng bên trong cấu trúc chính như một thành viên.

struct Date {
    int day;
    int month;
    int year;
};
struct Employee {
    int id;
    char name[20];
    struct Date birthday;
} emp1;


Trong ví dụ trên, cấu trúc birthday được sử dụng như một thành viên của cấu trúc Employee.


2. Cấu trúc nhúng.

Cấu trúc nhúng là viêc định nghĩa cấu trúc bên trong một cấu trúc khác và nó cũng là một trường hợp của cấu trúc (structure) lồng nhau trong C.

Ví dụ:

struct Employee {
    int id;
    char name[20];
    struct Date {
        int day;
        int month;
        int year;
    } birthday;
} emp1;


Truy cập cấu trúc lồng nhau

Bạn có thể truy cập các thành viên của cấu trúc lồng nhau bởi Outer_Structure.Nested_Structure.member như dưới đây:

emp1.birthday.day
emp1.birthday.month
emp1.birthday.year

Ví dụ về cấu trúc lồng nhau trong C

#include <stdio.h>
#include <string.h>
 
/**
 * dinh nghia cau truc Employee
 */
struct Employee {
    int id;
    char name[20];
    struct Date {
        int day;
        int month;
        int year;
    } birthday;
} e1;
 
/**
 * ham main
 */
int main() {
    // luu tru thong tin employee
    e1.id = 101;
    strcpy(e1.name, "Vinh Tran"); // chuyen doi chuoi thanh mang char
    e1.birthday.day = 10;
    e1.birthday.month = 11;
    e1.birthday.year = 2001;
 
    // hien thi thong tin sinh vien ra man hinh
    printf("employee id: %d\n", e1.id);
    printf("employee name: %s\n", e1.name);
    printf("employee birthday (dd/mm/yyyy): %d/%d/%d\n", e1.birthday.day,
            e1.birthday.month, e1.birthday.year);
    return 0;
}

Kết quả:

employee id: 101
employee name: Vinh Tran
employee birthday (dd/mm/yyyy): 10/11/2001

 

Union trong C

Cũng giống như structure, union trong C là kiểu dữ liệu do người dùng định nghĩa được sử dụng để chứa các loại phần tử khác nhau.

Nhưng nó không chiếm tổng bộ nhớ của các thành viên cộng lại, mà nó chỉ chiếm bộ nhớ của thành viên có lớn nhất.


Ưu điểm của Union so với Structure
Nó chiếm bộ nhớ ít hơn vì nó chiếm bộ nhớ của thành viên lớn nhất mà thôi.

Nhược điểm của Union so với Structure
Nó chỉ có thể lưu trữ dữ liệu trong một thành viên.


Định nghĩa Union trong C
Từ khóa union được sử dụng để định nghĩa một union.

union union_name {
    data_type member1;
    data_type member2;
    ...
    data_type memeberN;
};

Ví dụ:

union employee {
    int id;
    char name[50];
    float salary;
};

Ví dụ Union trong C

#include <stdio.h>
#include <string.h>
 
/**
 * dinh nghia union Employee
 */
union Employee {
    int id;
    char name[50];
} e1; // khai bao bien e1 cho Employee
 
/**
 * ham main
 */
int main() {
    // luu tru thong tin employee e1
    e1.id = 101;
    strcpy(e1.name, "Vinh Tran"); // chuyen doi chuoi thanh mang char
    // hien thi thong tin e1 ra man hinh
    printf("employee e1 id: %d\n", e1.id);
    printf("employee e1 name: %s\n", e1.name);
    return 0;
}

Kết quả:

employee e1 id: 1752066390
employee e1 name: Vinh Tran

Như bạn thấy, id lấy giá trị rác vì tên có kích thước bộ nhớ lớn. Vì vậy, chỉ tên sẽ có giá trị thực tế.
 


 

Chuỗi (String) trong C

Chuỗi (String) trong C là một mảng ký tự được kết thúc bởi \0 (ký tự null).

Có hai cách để khai báo chuỗi trong C.

  1. Mảng ký tự.
  2. Chuỗi chữ.

Khai báo chuỗi bằng mảng ký tự (char)

Ví dụ khai báo chuỗi trong C bằng mảng char.

char ch[12] = {'h', 'i', 'e', 'p', 's', 'i', 'i', 't', '.', 'c', 'o','m', '\0'};

 Như bạn đã biết, chỉ số mảng bắt đầu từ 0, vì vậy nó sẽ được biểu diễn như trong hình dưới đây.


Khai báo chuỗi bằng chuỗi chữ

char ch[12] = "hiepsiit.com";

Trong trường hợp này, ký tự ‘\0’ sẽ được trình biên dịch thêm vào cuối chuỗi.

Khi khai báo chuỗi, kích thước là không bắt buộc nên bạn có thể khai báo như sau:

char ch[12] = {'h', 'i', 'e', 'p', 's', 'i', 'i', 't', '.', 'c', 'o','m', '\0'};
char ch[12] = "hiepsiit.com";

Sự khác biệt giữa mảng char và chuỗi chữ

Sự khác biệt duy nhất là chuỗi chữ không thể thay đổi trong khi chuỗi tuyên bố bởi mảng char có thể được thay đổi.


Ví dụ chuỗi trong C

#include<stdio.h>
#include <math.h>
 
int main() {
    char ch1[] = {'h', 'i', 'e', 'p', 's', 'i', 'i', 't', '.', 'c', 'o','m', '\0'};
    char ch2[] = "hiepsiit.com";
 
    printf("Mang char la: %s\n", ch1);
    printf("Chuoi chu la: %s\n", ch2);
    return 0;
}

Kết quả: 

Mang char la: hiepsiit.com
Chuoi chu la: hiepsiit.com

 

Nhập chuỗi từ bàn phím trong C

Hàm gets() được sử dụng để đọc chuỗi từ bàn phím trong C và hàm puts() được sử dụng để in chuỗi ra màn hình. Cả hai chức năng được định nghĩa trong tập tin tiêu đề <stdio.h>.

Hãy xem một chương trình đơn giản để đọc và in chuỗi sử dụng các hàm gets() và puts().

#include<stdio.h>
 
int main() {
    char name[50];
    // doc chuoi tu ban phim
    printf("Enter your name: ");
    gets(name);
    // hien thi chuoi
    printf("Your name is: ");
    puts(name);
    return 0;
}

Kết quả:

Enter your name: Thich Hoc Gioi
Your name is: Thich Hoc Gioi

 

Các hàm xử lý chuỗi trong C

Có rất nhiều phương thức xử lý chuỗi quan trọng được định nghĩa trong thư viện <string.h>.

No. Phương thức Mô tả
1. strlen(string_name) trả về chiều dài của chuỗi string_name.
2. strcpy(destination, source) sao chép nội dung của chuỗi source tới chuỗi destination.
3. strcat(first_string, second_string) nối chuỗi đầu tiên với chuối thứ hai. Kết quả được lưu vào chuỗi đầu tiên.
4. strcmp(first_string, second_string) so sánh chuỗi đầu tiên với chuỗi thứ hai. Nếu cả hai chuỗi đều giống nhau, nó sẽ trả về 0.
5. strrev(string) trả về chuỗi được đảo ngược.
6. strlwr(string) trả về chuỗi ký tự chữ thường.
7. strupr(string) trả về chuỗi ký tự chữ hoa.

 

Hàm strlen() trong ngôn ngữ C

Hàm strlen() trả về chiều dài của chuỗi, nó không đếm ký tự null '\0'.

Cú pháp:

 int strlen(const char* s)

 Ví dụ:

#include<stdio.h>  
#include <string.h>    
int main(){    
char ch[20]={'h', 'i', 'e', 'p', 's', 'i', 'i', 't', '.', 'c','o','m', '\0'};    
   printf("Length of string is: %d",strlen(ch));    
 return 0;    
}    

Kết quả 

Length of string is: 12

 

Sao chép chuỗi trong C: strcpy()

Hàm strcpy(* destination, *source) sao chép nội dung của chuỗi source tới chuỗi destination.

Cú pháp:

 char *strcpy(char *destination, const char *source) 

Ví dụ:

#include<stdio.h>  
#include <string.h>    
int main(){    
 char ch[20]={'h', 'i', 'e', 'p', 's', 'i', 'i', 't', '.', 'c','m', '\0'};    
   char ch2[20];    
   strcpy(ch2,ch);    
   printf("Gia tri chuoi thu 2 la: %s",ch2);    
 return 0;    
}    

Kết quả:

Gia tri chuoi thu 2 la: hiepsiit.com

 

Hàm strcpy chỉ sao chép dữ liệu từ mảng B[ ] sang mảng A[ ], nếu mảng A[ ] có kích thước nhỏ hơn mảng B[ ]thì sẽ xảy ra việc tràn dữ liệu của mảng A[ ].

Nối chuỗi trong C : strcat(first_string, second_string)

Hàm char *strcat(char *des, const char *source) dùng để nối 2 chuỗi. Kết quả được lưu vào chuỗi đầu tiên.

Cú pháp: 

char *strcat(char *des, const char *source) 

 

Ví dụ:

#include<stdio.h>  
#include <string.h>    
int main(){    
  char ch[10]={'h', 'e', 'l', 'l', 'o', '\0'};    
   char ch2[10]={'c', '\0'};    
   strcat(ch,ch2);    
   printf("Gia tri cua chuoi dau tien la: %s",ch);    
 return 0;    
}    

Kết quả:

Gia tri cua chuoi dau tien la: helloc

 

So sánh 2 chuỗi trong C: strcmp()

Hàm int strcmp(const char*s1, const char *s2) là hàm dùng để so sánh hai chuỗi với nhau. Hàm sẽ so sánh hai chuỗi với nhau và trả về các giá trị tương ứng.

Cú pháp:

int strcmp(const char*s1, const char *s2)

Ta có A[] và B[]

  • Nếu A[] > B[], kết quả trả về là 1
  • Nếu A[] == B[], kết quả trả về là 0
  • Nếu A[] < B[], kết quả trả về là -1

Hàm strcmp sẽ so sánh từng hai phần tử của hai chuỗi có cùng vị trí với nhau.

Cách so sánh giống với các so sánh 2 số thực. Tức là chỉ cần 1 phần tử của mảng A[] lớn hơn phần tử cùng vị trí của mảng B[] thì mảng A[] sẽ lớn hơn mảng B[]. Ví dụ  X = 3.14160 và Y = 3.14159 thì ta có X > Y.

Ví dụ:

#include<stdio.h>  
#include <string.h>    
int main(){    
  char str1[20],str2[20];    
  printf("Nhap chuoi 1: ");    
  gets(str1);//reads string from console    
  printf("Nhap chuoi 2: ");    
  gets(str2);    
  if(strcmp(str1,str2)==0)    
      printf("2 chuoi bang nhau");    
  else    
      printf("2 chuoi khong bang nhau");    
 return 0;    
}    

Kết quả:

Nhap chuoi 1 : hello
Nhap chuoi 2 : hello
2 chuoi bang nhau

 

Hàm đảo chuỗi trong C: strrev()

Hàm strrev(string) trả về một chuỗi  được đảo ngược

Ví dụ:

#include<stdio.h>  
#include <string.h>    
int main(){    
  char str[20];    
  printf("Nhap vao mot chuoi: ");    
  gets(str);//reads string from console    
  printf("Chuoi la: %s",str);    
  printf("\nChuoi bi dao nguoc la: %s",strrev(str));    
 return 0;    
}    

Kết quả:

Nhap vao mot chuoi : hiepsiit
Chuoi la: hiepsiit
Chuoi bi dao nguoc la: tiispeih

 

Đổi chuỗi chữ hoa thành chuỗi chữ thường

Hàm strlwr(): Muốn chuyển đổi chuỗi chữ hoa thành chuỗi toàn chữ thường, ta sử dụng hàm strlwr(), các tham số của hàm tương tự như hàm strupr().

Cú pháp:

char *strlwr(char *s) 

Ví dụ: 

#include<stdio.h>  
#include <string.h>    
int main(){    
  char str[20];    
  printf("Nhap chuoi: ");    
  gets(str);//reads string from console    
  printf("Chuoi vua nhap: %s",str);    
  printf("\nChuyen sang chu thuong: %s",strlwr(str));    
 return 0;    
}    

Kết quả:

Nhap chuoi : HIEPsiit
Chuoi vua nhap: HIEPsiit
Chuyen sang chuoi thuong: hiepsiit

 

Đổi chuỗi chữ thường thành chuỗi chữ hoa

Hàm strupr(): Hàm struppr() được dùng để chuyển đổi chuỗi chữ thường thành chuỗi chữ hoa, kết quả trả về của hàm là một con trỏ chỉ đến địa chỉ chuỗi được chuyển đổi.

Cú pháp:

char *strupr(char *s)

Ví dụ:

#include<stdio.h>  
#include <string.h>    
int main(){    
  char str[20];    
  printf("Nhap chuoi: ");    
  gets(str);//reads string from console    
  printf("Chuoi vua nhap: %s",str);    
  printf("\nChuyen sang chu hoa: %s",strupr(str));    
 return 0;    
}    

Kết quả:

Nhap chuoi : HIEPsiit
Chuoi vua nhap: HIEPsiit
Chuyen sang chuoi thuong: HIEPSIIT

 

Tìm kiếm nội dung chuỗi

Hàm strstr(): Hàm strstr() được sử dụng để tìm kiếm sự xuất hiện đầu tiên của chuỗi s2 trong chuỗi s1.

Cú pháp: 

char *strstr(const char *s1, const char *s2) 

Kết quả trả về của hàm là một con trỏ chỉ đến phần tử đầu tiên của chuỗi s1 có chứa chuỗi s2 hoặc giá trị NULL nếu chuỗi s2 không có trong chuỗi s1.

Ví dụ: Viết chương trình sử dụng hàm strstr() để lấy ra một phần của chuỗi gốc bắt đầu từ chuỗi “hoc”.

#include<conio.h> 
#include<stdio.h>  
#include<string.h> 
 
void main() 
 
{ 
    char Chuoi[255],*s;      
    printf("Nhap chuoi: ");     
    gets(Chuoi);      
    s=strstr(Chuoi,"hoc");      
    printf("Chuoi trich ra: ");
    puts(s);      
    getch();     
}

Kết quả:

Nhap chuoi : Tien hoc le
Chuoi trich ra: hoc le

 

Bài tập về chuỗi

Viết chương trình nhập một chuỗi ký tự từ bàn phím, xuất ra màn hình mã Ascii của từng ký tự có trong chuỗi.

2. Viết chương trình nhập một chuỗi ký tự từ bàn phím, xuất ra màn hình chuỗi đảo ngược của chuỗi đó. Ví dụ đảo của "abcd egh" là "hge dcba".

3. Viết chương trình nhập một chuỗi ký tự và kiểm tra xem chuổi đó có đối xứng không.

Ví dụ : Chuỗi ABCDEDCBA là chuỗi đối xứng....

4. Nhập vào một chuỗi bất kỳ, hãy đếm số lần xuất hiện của mỗi loại ký tự.

5. Viết chương trình nhập vào một chuỗi.

  • In ra màn hình từ bên trái nhất và phần còn lại của chuỗi. Ví dụ: "Lê Quang Nam" in ra thành:
Lê
Quang Nam
  • In ra màn hình từ bên phải nhất và phần còn lại của chuỗi. Ví dụ: "Nguyễn Văn Minh" in ra thành:
Minh
Nguyễn Văn

6. Viết chương trình nhập vào một chuỗi rồi xuất chuỗi đó ra màn hình dưới dạng mỗi từ một dòng.

Ví dụ: "Nguyễn Văn Minh"

In ra :

Nguyễn
Văn
Minh 

7. Viết chương trình nhập vào một chuỗi, in ra chuỗi đảo ngược của nó theo từng từ.

Ví dụ : chuỗi "Nguyễn Văn Minh" đảo thành "Minh Văn Nguyễn"

8. Viết chương trình đổi số tiền từ số thành chữ.

9. Viết chương trình nhập vào họ và tên của một người, cắt bỏ các khoảng trống không cần thiết (nếu có), tách tên ra khỏi họ và tên, in tên lên màn hình. Chú ý đến trường hợp cả họ và tên chỉ có một từ.

10. Viết chương trình nhập vào họ và tên của một người, cắt bỏ các khoảng trắng bên phải, trái và các khoảng trắng không có nghĩa trong chuỗi. In ra màn hình toàn bộ họ tên người đó dưới dạng chữ hoa, chữ thường.

11. Viết chương trình nhập vào một danh sách họ và tên của n người theo kiểu chữ thường, đổi các chữ cái đầu của họ, tên và chữ lót của mỗi người thành chữ hoa. In kết quả lên màn hình.

12. Viết chương trình nhập vào một danh sách họ và tên của n người, tách tên từng người ra khỏi họ và tên rồi sắp xếp danh sách tên theo thứ tự từ điển. In danh sách họ và tên sau khi đã sắp xếp.

Hàm Math cơ bản trong C

Ngôn ngữ C cho phép chúng ta thực hiện các phép toán thông qua các hàm được định nghĩa trong tập tin tiêu đề <math.h>. File tiêu đề <math.h> chứa các phương thức khác nhau để thực hiện các phép toán như sqrt(), pow(), ceil(), floor(), vv

Bài này cung cấp cho bạn các hàm Math cơ bản trong C.


Hàm Math cơ bản trong C

Có nhiều phương thức trong tập tin tiêu đề math.h. Các phương thức cơ bả và thường được sử dụng của tập tin tiêu đề math.h được đưa ra dưới đây.

No. Phương thức Mô tả
1. ceil(number) làm tròn lên một số đã cho. Nó trả về giá trị số nguyên lớn hơn hoặc bằng với số đã cho.
2. floor(number) làm tròn xuống một số đã cho. Nó trả về giá trị số nguyên nhỏ hơn hoặc bằng số đã cho.
3. sqrt(number) trả về căn bậc hai của số đã cho.
4. pow(base, exponent) trả về số mũ của số đã cho.
5. abs(number) trả về giá trị tuyệt đối của số đã cho.

Ví dụ hàm Math cơ bản trong C

#include<stdio.h>
#include <math.h>
 
/**
 * ham main
 */
int main() {
    printf("%f", ceil(3.6));
    printf("\n%f", ceil(3.3));
    printf("\n%f", floor(3.6));
    printf("\n%f", floor(3.2));
    printf("\n%f", sqrt(16));
    printf("\n%f", sqrt(7));
    printf("\n%f", pow(2, 4));
    printf("\n%f", pow(3, 3));
    printf("\n%d", abs(-12));
    return 0;
}

Kết quả:

4.000000
4.000000
3.000000
3.000000
4.000000
2.645751
16.000000
27.000000
12

 

Xử lý tập tin (file) trong C

Xử lý tập tin trong ngôn ngữ C thường được sử dụng mở, đọc, ghi, tìm kiếm hoặc đóng tập tin.  Thường được dùng để lưu trữdữ liệu.


Tiện lợi của tập tin

Dùng để lưu dữ liệu khi thoát chương trình. Thường thì để chứa dữ liệu chúng ta dùng các biến hoặc mảng, nhưng dữ liệu sẽ bị mất khi thoát chương trình. 


Các hàm trong xử lý tập tin

Có nhiều hàm trong thư việc C :

STT. Hàm Mô tả
1 fopen() Mở tập tin mới hoặc tạo mới tập tin
2 fprintf() Ghi dữ liệu vào tập tin
3 fscanf() Đọc dữ liệu vào tập tin
4 fputc() Ghi một ký tự vào tập tin
5 fgetc() Đọc một ký tự từ tập tin
6 fclose() Đóng tập tin
7  fseek() để thay đổi vị trí trỏ đến vị trí trong tập tin 
8 fputw() Ghi số nguyên vào tập tin
9 fgetw() Đọc số nguyên từ tập tin
10 ftell() Hàm này sẽ trả về vị trí của file indicator đang trỏ đến trong file
11 rewind() sẽ đặt lại vị trí con trỏ nội bộ của tập tin về đầu tập tin.

Mở tập tin: fopen()

Để mở tập tin dùng hàm fopen()

Cú pháp:

FILE *fopen( const char * filename, const char * mode );  

Chúng ta có thể sử dụng một trong các mode trong hàm fopen() sau:

Mode Mô tả
r Mở một tập tin  văn bản để đọc
w Mở một tập tin văn bản để ghi
a Nối vào một tập tin văn bản
r+ Mở một tập tin văn bản để đọc/ghi
w+ Tạo một tập tin văn bản để đọc/ghi
a+ Nối hoặc tạo một tập tin văn bản để đọc/ghi
rb Mở một tin nhị phân để đọc
wb Mở một tập tin nhị phân để ghi
ab Nối vào một tập tin nhị phân
rb+ Mở một tập tin nhị phân để đọc/ghi
wb+ Tạo một tập tin nhị phân để đọc/ghi
ab+ Nối vào tập tin nhị phân để đọc/ghi

Đóng tập tin : fclose()
Để đóng tập tin dùng hàm fclose()
Cú pháp:

int fclose( FILE *fp );  

Các hàm xử lý tập tin

  1. C fprintf() và fscanf()
  2. C fputc() và  fgetc()
  3. C fputs() và fgets()
  4. C fseek()

 

C fprintf() and fscanf()


Ghi tập tin : fprintf() 

Hàm fprintf()  thường được sử dụng ghi dữ liệu vào tập tin.

Cú pháp:

int fprintf(FILE *stream, const char *format [, argument, ...])  

Ví dụ:

#include <stdio.h>  
main(){  
   FILE *fp;  
   fp = fopen("file.txt", "w");//Mở tập tin
   fprintf(fp, "Hello file by fprintf...\n");//Ghi dữ liệu vào tập tin
   fclose(fp);//Đóng tập tin  
}  

Đọc tập tin : fscanf() 

Hàm fscanf() thường được sử dụng để đọc dữ liệu từ tập tin. Nó đọc từng từ trong tập tin cho đến khi EOF tập tin

Cú pháp:

int fscanf(FILE *stream, const char *format [, argument, ...])  

Ví dụ:

#include <stdio.h>  
main(){  
   FILE *fp;  
   char buff[255];//creating char array to store data of file  
   fp = fopen("file.txt", "r");  
   while(fscanf(fp, "%s", buff)!=EOF){  
   printf("%s ", buff );  
   }  
   fclose(fp);  
}  

Kết quả:

Hello file by fprintf...

Ví dụ về tập tin: Lưu trữ thông tin nhân viên

Thông tin  nhân viên được người sử dụng nhập từ bàn phím. Sau đó chúng ta sẽ lưu vào tập tin: tên và lương.

#include <stdio.h>  
void main()  
{  
    FILE *fptr;  
    int id;  
    char name[30];  
    float salary;  
    fptr = fopen("D:\\emp.txt", "w+");/*  open for writing */  
    if (fptr == NULL)  
    {  
        printf("File does not exists \n");  
        return;  
    }  
    printf("Enter the id\n");  
    scanf("%d", &id);  
    fprintf(fptr, "Id= %d\n", id);  
    printf("Enter the name \n");  
    scanf("%s", name);  
    fprintf(fptr, "Name= %s\n", name);  
    printf("Enter the salary\n");  
    scanf("%f", &salary);  
    fprintf(fptr, "Salary= %.2f\n", salary);  
    fclose(fptr);  
}  

Kết quả:

Enter the id 
1
Enter the name 
sonoo
Enter the salary
120000 

Mở tập tin D:\emp.txt chúng ta sẽ thấy thông tin:

Id= 1
Name= sonoo
Salary= 120000 

 

C fputc() and fgetc()


Ghi tập tin : fputc() 

Hàm fputc() ghi các ký tự với giá trị tham số c đến một luồng ra tham chiếu bởi con trỏ fp. Nó sẽ trả về ký tự được ghi nếu thành công hoặc EOF nếu có lỗi. Bạn có thể sử dụng hàm sau đây để ghi một chuỗi kết thúc bằng ký tự null đến một luồng:

Cú pháp:

int fputc(int c, FILE *stream)  

Ví dụ:

#include <stdio.h>  
main(){  
   FILE *fp;  
   fp = fopen("file1.txt", "w");//opening file  
   fputc('a',fp);//writing single character into file  
   fclose(fp);//closing file  
}  

Kết quả trong file1.txt:

a

Đọc tập tin :  fgetc()


Hàm fgetc() đọc một ký tự từ một file tham chiếu bởi con trở fp. Giá trị trả về là ký tự đọc được nếu thành công, và trong trường hợp lỗi trả về EOF. Hàm dưới đây cho phép bạn đọc chuỗi từ một luồng:

Cú pháp:

int fgetc( FILE * fp );

Ví dụ:

#include<stdio.h>  
#include<conio.h>  
void main(){  
FILE *fp;  
char c;  
clrscr();  
fp=fopen("myfile.txt","r");  
  
while((c=fgetc(fp))!=EOF){  
printf("%c",c);  
}  
fclose(fp);  
getch();  
}  

Kết quả: myfile.txt

this is simple text message

 

C fputs() and fgets()

Trong ngôn ngữ lập trình C hàm fputs() và fgets() thường được sử dụng đọc và ghi một chuỗi dữ liệu từ một luồng (stream).


Ghi tập tin : fputs ()

Hàm fputs() ghi chuỗi s đến một luồng ra tham chiếu bởi fp. Nó trả về một giá trị không âm nếu thành công và trả về ký tự EOF nếu xảy ra một lỗi. Bạn có thể sử dụng hàm int fprintf(FILE *fp,const char *format, ...) để ghi một chuỗi ra file 

Cú pháp:

int fputs(const char *s, FILE *stream)  

Ví dụ:

#include<stdio.h>  
#include<conio.h>  
void main(){  
FILE *fp;  
clrscr();  
  
fp=fopen("myfile2.txt","w");  
fputs("hello c programming",fp);  
  
fclose(fp);  
getch();  
}  

Kết quả: myfile2.txt

hello c programming

Đọc tập tin : fgets() 

Hàm fgets() đọc n-1 ký tự từ một luồng vào tham chiếu bởi fp. Nó copy chuỗi đọc đến bộ đệm buf, gán ký tự null vào kết thúc chuỗi.
Nếu hàm gặp phải một ký tự newline (xuống dòng) '\n' hoặc ký tự EOF trước khi đọc được số lượng tối đa các ký tự, nó sẽ chỉ trả về các ký tự cho đến ký tự xuống dòng và ký tự xuống dòng mới. Bạn có thể sử dụng hàm int fscanf(FILE *fp, const char *format, ...) để đọc chuỗi từ một file, nhưng dừng việc đọc ở khoảng trắng đầu tiên gặp phải:

Cú pháp:

char* fgets(char *s, int n, FILE *stream)  

Ví dụ:

#include<stdio.h>  
#include<conio.h>  
void main(){  
FILE *fp;  
char text[300];  
clrscr();  
  
fp=fopen("myfile2.txt","r");  
printf("%s",fgets(text,200,fp));  
  
fclose(fp);  
getch();  
}  

Kết quả:

hello c programming

 


 

Hàm fseek() 

Hàm fseek thay đổi vị trí trỏ đến vị trí trong tập tin. Nó thường sử dụng để ghi dữ liệu vào vị trí mong muốn

Cú pháp:

int fseek(FILE *stream, long int offset, int whence)  

Có 3 hằng số được sử dụng trong hàm fseek () : SEEK_SET, SEEK_CUR and SEEK_END.

Ví dụ:

#include <stdio.h>  
void main(){  
   FILE *fp;  
  
   fp = fopen("myfile.txt","w+");  
   fputs("This is hiepsiit", fp);  
    
   fseek( fp, 7, SEEK_SET );  // tìm vị trí ký tự thứ 7
   fputs("hello world", fp);  
   fclose(fp);  
}  

Kết quả: myfile.txt

this is hello world

 

Hàm rewind() 

Hàm rewind() sẽ đặt lại vị trí con trỏ nội bộ của tập tin về đầu tập tin.

Cú pháp:

void rewind(FILE *stream)  

Ví dụ: trong tập tin file.txt có nội dung sau:

this is a simple text  

Code chương trình sau:

#include<stdio.h>  
#include<conio.h>  
void main(){  
FILE *fp;  
char c;  
clrscr();  
fp=fopen("file.txt","r");  
  
while((c=fgetc(fp))!=EOF){  
printf("%c",c);  
}  
  
rewind(fp);//Di chuyển con trỏ đến đầu tập tin 
  
while((c=fgetc(fp))!=EOF){  
printf("%c",c);  
}  
  
fclose(fp);    
getch();    
}    

Kết quả:

this is a simple textthis is a simple text

Như đã thấy. Hàm rewind() di chuyển con trỏ lên đầu tập tin để print chuỗi "this is simple text"  2 lần. Nếu không gọi hàm rewind thì chỉ print ""this is simple text"  một lần


 

Hàm ftell() 

Hàm ftell() trả về vị trí hiện tại của tập tin. Chúng ta sử dụng hàm ftell() lấy kích thước của một tập tin, sau đó di chuyển con trỏ đến cuối tập tin. Chúng ta có thể sử dụng hằng số SEEK_END để di chuyển con trỏ đến cuối tập tin.

Cú pháp:

long int ftell(FILE *stream)  

Ví dụ:

#include <stdio.h>  
#include <conio.h>  
void main (){  
   FILE *fp;  
   int length;  
   clrscr();  
   fp = fopen("file.txt", "r");  
   fseek(fp, 0, SEEK_END);  
  
   length = ftell(fp);  
  
   fclose(fp);  
   printf("Size of file: %d bytes", length);  
   getch();  
}  

Kết quả:

Size of file: 21 bytes

 

Chỉ thị tiền xử lý (preprocessor directives)

Chỉ thị tiền xử lý là những chỉ thị cung cấp cho trình biên dịch để xử lý những thông tin trước khi bắt đầu quá trình biên dịch. Tất cả các chỉ thị tiền xử lý đều bắt đầu với với # và các chỉ thị tiền xử lý không phải là lệnh C/C++ vì vậy không có dấu ; khi kết thúc. Để cho dễ chúng ta chia thành 3 nhóm chính đó là:

  • Chỉ thị bao hàm tệp (#include).
  • Chỉ thị định nghĩa cho tên (#define macro).
  • Chỉ thị biên dịch có điều kiện (#if, #else, #elif, #endif, ...).

Danh sách chỉ thị tiền xử lý

  • #include
  • #define
  • #undef
  • #ifdef
  • #ifndef
  • #if
  • #else
  • #elif
  • #endif
  • #error
  • #pragma

 


 

Khái niệm macro 

Macro - một cái tên nghe khá hổ báo, được dùng để chỉ những hàm được viết ở phần Preprocessor, thay vì đặt nó vào trong phần thực thi của file nguồn. Ngoài ra khi nói đến macro có 1 nghĩa khác nữa, ám chỉ đến tất cả những phần định nghĩa được viết trong phần Preprocessor. Trong bài viết này thì mình dùng macro với cách dùng đầu tiên. Ví dụ đơn giản về macro như sau

#define PRINT_HELLO_WORLD printf("Hello world")

Macro trên không tham số, chỉ một dòng duy nhất, và compiler sẽ đơn giản là thay thế bất cứ chỗ nào có PRINT_HELLO_WORLD ở trong source code bằng câu lệnh print("Hello world). Đây là để làm ví dụ thôi chứ mình không có khuyến khích ai thực hành đoạn code trên cả.

Sau khi không gặp bất cứ vấn đề gì với đồng chí PRINT_HELLO_WORLD ở trên. Chúng ta xét tiếp 1 ví dụ về macro có tham số.

#define ADD_TWO_NUMBER(x, y) ((x) + (y))

Và dùng nó ở đoạn code dưới đây

int z_1 = ADD_TWO_NUMBER(10, 3);
float z_2 =  ADD_TWO_NUMBER(10.1, 3.7);

Macro trên sẽ khớp với bất cứ đoạn code nào có dạng ADD_TWO_NUMBER(param_1, param_2)và thay nó bằng param_1 + param_2 và nó không (thể) biết param_1 và param_2 là gì, có thể là biểu thức có thể là biến, có thể là string mà cũng có thể là int. Đó cũng chính là điểm mạnh và cũng là điểm yếu của macro, bạn có thể dùng hàm trên để cộng 2 biến kiểu int hay float như trên. Tuy nhiên nó cũng tiềm tàng nhiều mối nguy hiểm mà mình sẽ đề cập ở 1 bài khác.

Các thao tác với macro

Toán tử ##

Cái này làm mình gặp chút khó khăn trong lúc viết vì nó xung đột với kí pháp của markdown. Toán tử ## có tác dụng nối 2 token lại với nhau (mình gặp rắc rối với việt hoá từ token này, hy vọng các bạn không quá khó hiểu), tương tự như các bạn nối string thôi, không có gì phức tạp cả.
Ví dụ:

#define float_type fl##oat
...
float_type a = 10.0;

Về ứng dụng thực tế của ## thì thường được dùng trong để đặt tên cho biến, hàm hoặc class. Ví dụ như bạn muốn khai báo 3 biến là normal_bike_pricepremium_bike_pricelow_bike_price, thì thay vì khai báo thủ công, bạn có thể dùng macro như sau.

#define DECLARE_VARIABLES(type, name) type normal_##name, premium_##name, low_##name
...
DECLARE_VARIABLES(int, bike_price);

Câu lệnh trên sẽ được chuyển thành đoạn code sau khi chạy chương trình:

int normal_bike_price, premium_bike_price, low_bike_price;

Macro nhiều dòng (multi line macro)

Để khai báo một function (tầm cỡ vài chục câu lệnh) thì ý tưởng viết tất cả chúng vào tất cả 1 dòng là không sáng sủa tí nào. Và để xuống dòng trong macro thì bạn sẽ dùng ký tự \. Như trong ví dụ sau đây chúng ta sẽ sửa lại đoạn code trên 1 chút để nó thành 1 macro có nhiều dòng nhằm cho thấy tác dụng của kí tự \.

#define DECLARE_VARIABLES(type, name) type normal_##name;\
type premium_##name;\
type low##_name;

Toán tử #

# dùng để chuyển 1 token nào đó thành chuỗi. Ví dụ như sau.

#define print_variable_name_and_value(x) printf(#x " value is: %d", x)
...
int x = 10;
print_variable_name_and_value(x);

câu lệnh print_variable_name_and_value(x); sẽ được chuyển thành printf("x" " value is: %d", x); và kết quả câu lệnh trên sẽ là

x value is: 10 

 Macro tiền định nghĩa trong C++

C++ cung cấp một số macro được định nghĩa trước như liệt kê dưới đây:

Macro Mô tả
__LINE__ Chứa số dòng hiện tại của chương trình khi nó đang được biên dịch
__FILE__ Chứa tên file hiện tại của chương trình khi nó đang được biên dịch
__DATE__ Chứa một chuỗi month/day/year là ngày source code được biên dịch
__TIME__ Chứa một chuỗi hour:minute:second là thời gian chương trình được biên dịch

Dưới đây là ví dụ cho tất cả macro ở trên trong C:

#include<stdio.h>  
 int main(){    
   printf("File :%s\n", __FILE__ );    
   printf("Date :%s\n", __DATE__ );    
   printf("Time :%s\n", __TIME__ );    
   printf("Line :%d\n", __LINE__ );    
   printf("STDC :%d\n", __STDC__ );      
   return 0;  
 }    

 Kết quả:

File :simple.c
Date :Dec 6 2015
Time :12:28:46
Line :6
STDC :1

 

Chỉ thị tiền xử lý #include 

Chúng ta đặc biệt dùng #include để thêm vào file.c các nội dung từ những file.h của các thư viện (stdio.h, stdlib.h, string.h, math.h) và cũng có thể là từ những file.h của riêng bạn. 
 
Để thêm nội dung những file.h có trong thư mục cài đặt IDE của bạn, bạn cần sử dụng những ngoặc nhọn < > 

Cú pháp:

#include <stdlib.h>

Để thêm nội dung những file.h có trong thư mục chứa project của bạn, bạn cần sử dụng những dấu ngoặc kép: 
Cú pháp:

#include "myfile.h"

Cụ thể hơn, những chương trình tiền xử lý sẽ bắt đầu trước khi compile. Nó sẽ quét các tập tin của bạn để tìm ra những chỉ thị tiền xử lý trước, tất cả những dòng bắt đầu bằng #.  
Khi nó gặp directive #include, nó sẽ đặt nội dung của file được chỉ định vào vị trí #include.  
Giả sử tôi có một « file.c » chứa code của các function và « file.h » chứa các prototypes của các function trong file.c  
Để đơn giản hơn bạn có thể xem biểu đồ sau : 
 
 

Tất cả nội dung của file.h sẽ được đặt vào trong file.c, ngay tại vị trí đặt directive #include file.h    
Dưới đây là những gì ta có trong file.c :  

#include "file.h" 
long myFunction(int cai_nay, double cai_kia) { 
/* Source code of function */ 
} 
void otherFunction(long value) {
 /* Source code of function */ 
} 
 

Trong file.h :

long myFunction(int cai_nay, double cai_kia);
void otherFunction(long value); 

Khi chương trình tiền xử lý chạy đến đây, trước khi biên dịch file.c, nó sẽ đặt file.h vào trong file.c. Cuối cùng, mã nguồn của file.c trước khi biên dịch sẽ giống như sau:  

long myFunction(int cai_nay, double cai_kia); 
void otherFunction(long value); 
 
long myFunction(int cai_nay, double cai_kia) { 
/* Source code of function */
 }
 void otherFunction(long value) { 
/* Source code of function */
} 

Nội dung của file.h đã được đặt tại vị trí của dòng #include.  
Thật sự không có gì quá khó hiểu đúng không? Tôi nghĩ rằng đã có khá nhiều bạn biết cách thức hoạt động của nó như thế nào.  
Chức năng của các #include không có gì khác ngoài hành động chèn file này vào file khác, và các bạn phải biết rằng việc hiểu vấn đề này rất quan trọng. 

Lưu ý: Thay vì đặt tất cả các prototype vào trong các file.c, chúng ta nên chọn cách đặt những prototypes trong các file.h, việc này gần như được xem là một nguyên tắc cơ bản khi lập trình. Ta có thể ưu tiên để những prototypes này lên đầu file.c (thường gặp trong những file chương trình nhỏ), nhưng để tiện cho việc sắp xếp, tôi khuyên bạn hãy đặt những prototype này trong những file.h.  
Khi chương trình bạn viết ngày càng phức tạp và có quá nhiều file.c, chỉ cần sử dụng #include để giúp chúng sử dụng chung 1 file.h, bạn sẽ cảm thấy mình thật may mắn khi không phải tốn quá nhiều thời gian để copy & paste lại những prototype có cùng 1 chức năng. 
 
 .


 
 

 

Chỉ thị tiền xử lý  #define

Lệnh #define này cho phép khai báo một hằng số (constant) của tiền xử lý (preprocessor). Nó cho phép đưa giá trị số vào một từ.  

Cú pháp:

#define TEN giá trị  

Cần chú ý một chút về cách viết: tên của constant này thường được viết hoa toàn bộ, chủ yếu là để phân biệt với những constant mà ta được học trước đó : 
Ví dụ: 

const long MANG_SONG_NHAN_VAT_BAN_DAU = 3;

Những constant sẽ chiếm lấy một chỗ trong bộ nhớ, ngay cả khi giá trị không đổi, số « 3 » sẽ được lưu trữ đâu đó trong bộ nhớ. Không giống như trường hợp của các constant của preprocessor  
Vậy nó hoạt động như thế nào ? Đó là, #define sẽ thay thế tất cả những từ trong mã nguồn bởi giá trị tương ứng. Tương tự như chức năng « find/replace » trong word bạn thường sử dụng. 
Ví dụ:

#define MANG_SONG_NHAN_VAT_BAN_DAU 3 

Sẽ thay thế tất cả từ MANG_SONG_NHAN_VAT_BAN_DAU có trong file bằng giá trị 3 Và đây là một ví dụ :  
Một file.c trước khi qua preprocessor : 

Code C:

#define MANG_SONG_NHAN_VAT_BAN_DAU 3 
int main(int argc, char *argv[]) { 
long mang_song = MANG_SONG_NHAN_VAT_BAN_DAU; /* Code ...*/ 
 

Sau khi qua preprocessor : 
Code C : 

int main(int argc, char *argv[]) { 
long mang_song = 3; /* Code ...*/ 
 

Trước khi biên dịch, tất cả những  #define sẽ được thay thế bằng các giá trị tương ứng. Compiler sẽ thấy trong file sau khi qua tiền xử lý, trong đó tất các những chỗ cần thay thế đều đã được thực hiện  
Vậy đến thời điểm này, đâu là lợi ích của việc sử dụng những constant ?  
Ok, như tôi đã giải thích với bạn là nó không chiếm thêm bộ nhớ máy tính. Điều này có nghĩa là, đến giai đoạn compilation thì trong đó chỉ còn những con số trong mã nguồn của bạn.  
Một lợi ích khác khi sử dụng #define là việc thay thế sẽ được thực hiện trong tất cả các file chứa dòng #define. Khác với khi bạn khai báo một constant trong một function, nó chỉ có hiệu lực trong function đó, sau đó nó sẽ bị xóa đi.  
Nhưng đối với #define, nó sẽ tác động lên tất cả các function có trong file đó, và điều này thật sự rất tiện lợi cho những người lập trình.  
Bạn muốn một ví dụ cụ thể về việc sử dụng #define ?  
Đây là một ví dụ mà bạn có thể ứng dụng ngay. Khi bạn mở một cửa sổ chương trình bằng C, hẳn là bạn muốn xác định những constant của tiền xử lý đề chỉ ra kích thước của cửa sổ : 
Code C:

#define CHIEUDAI_CUASO 800 
#define CHIEURONG_CUASO 600 

Ưu điểm của việc này là nếu về sau bạn có ý định thay đổi kích thước của các cửa sổ (chẳng hạn như vì lý do chúng quá nhỏ), bạn chỉ cần thay đổi lại những dòng #define và sau đó biên dịch lại.  
Viết thêm rằng: những dòng #define thường được đặt trong những file.h, bên cạnh các prototype (Bạn có thể xem những file.h của các thư viện như stdio.h, bạn sẽ thấy ở đó luôn có những dòng #define !).  
Những #define giống như « cách thức đơn giản », giúp bạn thay đổi kích thước cửa sổ bằng việc thay đổi những #define, thay vì phải rà soát lại toàn bộ nội dung file tìm nơi mà bạn mở cửa sổ để thay đổi lại kích thước. Việc này sẽ tiết kiệm rất nhiều thời gian cho bạn trong việc lập trình.  
Tóm tắt lại, những constants của preprocessor cho phép « chỉnh sửa » chương trình của bạn trước việc compilation. Giống như một dạng mini-configuration. 


Define cho kích thước mảng

Ta thường dùng các define để xác định kích thước các table. Đây là ví dụ :  
Code  C :  

#define KICH_THUOC_TOI_DA 1000 
int main(int argc, char *argv[]) { 
char line1[KICH_THUOC_TOI_DA], line2[KICH_THUOC_TOI_DA]; 

Nhưng… tôi nghĩ rằng chúng ta không thể đặt biến số (KICH_THUOC_TOI_DA) giữa những dấu ngoặc [ ] khi khởi tạo table (line1[], line2[]) ?  
Đúng vậy, nhưng < KICH_THUOC_TOI_DA > KHÔNG phải là một biến số. Giống như tôi đã nói, preprocessor sẽ thay đổi nội dung của file trước khi compilation, như sau : 

Code C:

int main(int argc, char *argv[]) {
 char line1[1000], line2[1000]; 

...và đoạn code này là chính xác. Bằng cách xác định giá trị của KICH_THUOC_TOI_DA, các bạn có thể sử dụng nó để tạo những table có kích thước khác nhau. Nếu trường hợp sau này table đang sử dụng không đủ lớn, bạn chỉ cần thay đổi giá trị ở dòng #define, sau đó compile lại, và table dạng char của bạn đã sẽ nhận kích thước mới mà bạn vừa thay đổi. 


Tính toán trong define 

Chúng ta có thể thực hiện một vài phép tính trong define.  
Ví dụ, đoạn code sau sẽ tạo constant CHIEUDAI_CUASO và CHIEURONG_CUASO, sau đó là SOLUONG_PIXELS chứa số lượng pixel hiển thị trong cửa sổ. (việc tính toán khá đơn giản: chiều rộng*chiều dài) : 
Code C:  

#define CHIEUDAI_CUASO 800 
#define CHIEUCAO_CUASO 600 
#define SOLUONG_PIXELS (CHIEUDAI_CUASO * CHIEUCAO_CUASO) 

 
Giá trị của SOLUONG_PIXELS được thay đổi trước khi compile bằng giá trị của (CHIEUDAI_CUASO * CHIEUCAO_CUASO), có nghĩa là (800*600), 480000.  
Hãy luôn đặt phép tính của bạn trong những dấu ngoặc đơn như cách tôi đã làm.  
Bạn có thể thực hiện tất cả các phép toán cơ bản mà bạn biết: phép cộng (+), phép trừ (-), phép nhân (*), phép chia (/) và modulo (%).  


 

Chỉ thị tiền xử lý #undef

Khi ta cần định nghĩa lại một tên mà ta đã định nghĩa trước đó thì ta sử dụng #undef để hủy bỏ định nghĩa đó và sử dụng #define định nghĩa lại cho tên đó.

Cú pháp:

#undef identifier 

Ví dụ:

#include <stdio.h>  
#define PI 3.14  
#undef PI  
main() {  
   printf("%f",PI);  
}  

Kết quả:

Compile Time Error: 'PI' undeclared

Chỉ thị #undef được sử dụng định nghĩa lại hằng số PI

Ví dụ sau chúng ta định nghĩa biến number, nó được sử dụng trước khi xóa định nghĩa nó.

#include <stdio.h>  
#define number 15  
int square=number*number;  
#undef number  
main() {  
   printf("%d",square);  
}  

Kết quả:

225

 

Chỉ thị tiền xử lý #ifdef

Chỉ thị #ifdef kiểm tra một macro được định nghĩa trong #define. nếu đúng thì nó thực thi code ngược lại thực thi code trong #else

Cú pháp:

#ifdef MACRO
     //Đoạn chương trình 1
 
#else
     //Đoạn chương trình 2
 
#endif

Nếu MACRO đã được định nghĩa thì đoạn chương trình 1 sẽ được thực hiện. Ngược lại nếu MACRO chưa được định nghĩa thì đoạn chương trình 2 sẽ được thực hiện.

Ví dụ về chỉ thị #ifdef:

#include <stdio.h>  
#include <conio.h>  
#define NOINPUT  
void main() {  
int a=0;  
#ifdef NOINPUT  
a=2;  
#else  
printf("Enter a:");  
scanf("%d", &a);  
#endif         
printf("Value of a: %d\n", a);  
getch();  
}  

Kết quả:

Value of a: 2

Nhưng nếu không định nghĩa  NOINPUT, Nó yêu cầu người sử dụng: Enter a:

#include <stdio.h>  
#include <conio.h>  
void main() {  
int a=0;  
#ifdef NOINPUT  
a=2;  
#else  
printf("Enter a:");  
scanf("%d", &a);  
#endif         
  
printf("Value of a: %d\n", a);  
getch();  
}  

Kết quả:

Enter a:5
Value of a: 5

 

Chỉ thị tiền xử lý #ifndef

Chỉ thị tiền xử lý #ifdef kiểm tra một macro không được định nghĩa trong #define. nếu đúng thì nó thực thi code ngược lại thực thi code trong #else

#ifndef MACRO
     //Đoạn chương trình 1 
 
#else 
     //Đoạn chương trình 2 
 
#endif

Nếu MACRO không được định nghĩa thì đoạn chương trình 1 sẽ được thực hiện. Ngược lại nếu MACRO chưa được định nghĩa thì đoạn chương trình 2 sẽ được thực hiện.

Ví dụ về chỉ thị #ifndef:

#include <stdio.h>  
#include <conio.h>  
#define INPUT  
void main() {  
int a=0;  
#ifndef INPUT  
a=2;  
#else  
printf("Enter a:");  
scanf("%d", &a);  
#endif         
printf("Value of a: %d\n", a);  
getch();  
}  

Kết quả:

Enter a:5
Value of a: 5

Nêu không #define INPUT . Nó sẽ thực thi code của #ifndef

#include <stdio.h>  
#include <conio.h>  
void main() {  
int a=0;  
#ifndef INPUT  
a=2;  
#else  
printf("Enter a:");  
scanf("%d", &a);  
#endif         
printf("Value of a: %d\n", a);  
getch();  
}  

Kết quả:

Value of a: 2

 

Chỉ thị tiền xử lý #if

Chỉ thị tiền xử lý #if đánh giá biểu thức hoặc điều kiện. Nếu điều kiện là đúng, nó thực thi mã nếu không thực thi mã trong  #elseif hoặc #else hoặc #endif được thực thi..

Cách 1:

#if bieu_thuc  
//code  
#endif  

Cách 2:

#if bieu_thuc  
//if code  
#else  
//else code  
#endif  

Cách 3:

#if bieu_thuc  
//if code  
#elif bieu_thuc  
//elif code  
#else  
//else code  
#endif  

Ví dụ #if:

#include <stdio.h>  
#include <conio.h>  
#define NUMBER 0  
void main() {  
#if (NUMBER==0)  
printf("Value of Number is: %d",NUMBER);  
#endif         
getch();  
}  

Kết quả:

Value of Number is: 0

Xem thêm ví dụ về #if

#include <stdio.h>    
#include <conio.h>    
#define NUMBER 1  
void main() {  
clrscr();  
#if (NUMBER==0)  
printf("1 Value of Number is: %d",NUMBER);  
#endif  
  
#if (NUMBER==1)  
printf("2 Value of Number is: %d",NUMBER);  
#endif  
getch();  
}  

Kết quả:

2 Value of Number is: 1

 

Chỉ thị tiền xử lý  #else

Chỉ thị tiền xử lý #else đánh giá biểu thức hoặc điều kiện nếu điều kiện của #if là sai. Nó có thể được sử dụng với các chỉ thị #if, #elif, #ifdef và #ifndef.

Cách 1:

#if expression  
//if code  
#else  
//else code  
#endif  

Cách 2: có #elif

#if expression  
//if code  
#elif expression  
//elif code  
#else  
//else code  
#endif  

Ví dụ sử dụng chỉ thị tiền xử lý #else:

#include <stdio.h>  
#include <conio.h>  
#define NUMBER 1  
void main() {  
#if NUMBER==0  
printf("Value of Number is: %d",NUMBER);  
#else  
print("Value of Number is non-zero");  
#endif         
getch();  
}  

Kết quả:

Value of Number is non-zero

 

Chỉ thị tiền xử lý #error

Chỉ thị tiền xử lý #error  chỉ ra lỗi. Trình biên dịch gây ra lỗi nghiêm trọng nếu chỉ thị #error được tìm thấy và bỏ qua quá trình biên dịch tiếp theo.

Ví dụ sau chúng ta dùng hàm sqrt trong thư viện math.h chưa include nó vào chương trình

#include<stdio.h>  
#ifndef __MATH_H  
#error First include then compile  
#else  
void main(){  
    float a;  
    a=sqrt(7);  
    printf("%f",a);  
}  
#endif  

Kết quả:

Compile Time Error: First include then compile

#include <math.h> vào chương trình, sẽ không còn lỗi

#include<stdio.h>  
#include<math.h>  
#ifndef __MATH_H  
#error First include then compile  
#else  
void main(){  
    float a;  
    a=sqrt(7);  
    printf("%f",a);  
}  
#endif  

Kết quả:

2.645751

 

C #pragma

Chỉ thị tiền xử lý #pragma là một chỉ thị cho compiler biết cách dịch chương trình theo một số “tùy chọn” đặc biệt, tùy thuộc vào từng trình biên dịch.

Cú pháp:

#pragma token  

Ví dụ:  Khai báo struct với kích thước không đổi với mọi trình dịch:

#pragma pack (push)
	#pragma pack (1)

	struct NewStruct	{
		int a;
		int b;
		char c;
	};

	#pragma pack (pop)

Thông thường trình biên dịch sẽ làm tròn để kích thước struct là số chia hết cho 4, (hoặc 2, 8, 16… tùy vào cấu hình build). Với cách khai báo trên trong VC++ và gcc, kích thước cấu trúc sẽ luôn luôn không đổi với mọi trình biên dịch, mọi cấu hình


Các trình biên dịch khác nhau có thể cung cấp cách sử dụng các chỉ thị tiền xử lý khác nhau.

Trình biên dịch C++ hỗ trợ các chỉ thị tiền xử lý:

#pragma argsused  
#pragma exit  
#pragma hdrfile  
#pragma hdrstop  
#pragma inline  
#pragma option  
#pragma saveregs  
#pragma startup  
#pragma warn  

Ví dụ :

#include<stdio.h>  
#include<conio.h>  
  
void func() ;  
  
#pragma startup func  
#pragma exit func  
  
void main(){  
printf("\nI am in main");  
getch();  
}  
  
void func(){  
printf("\nI am in func");  
getch();  
}  

Kết quả:

I am in func
I am in main
I am in func

 

Tham số dòng lệnh là gì?

Đối số dòng lệnh là các đối số chuỗi tùy ý mà người dùng có thể cung cấp cho một chương trình khi thực thi. Các đối số được truyền thông qua hệ điều hành của chương trình và chương trình có thể sử dụng nó như input. Để sử dụng các đối số dòng lệnh trong chương trình, bạn phải khai báo đầy đủ trong hàm main bao gồm hai đối số: số đối số dòng lệnh và danh sách các đối số dòng lệnh.

Để sử dụng tham số dòng lệnh thì cấu hàm main sau:

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

argc số lượng tham số, tên tập tin là tham số đầu tiên.

argv[] chứa tổng số tham số, tham số đầu tiên luôn luôn là tập tin.


Làm thế nào để sử dụng nó?

Sau đây sẽ là 2 ví dụ minh họa để các bạn có thể hiểu rõ hơn về đối số dòng lệnh.

Ví dụ 1:

#include <stdio.h>  
void main(int argc, char *argv[] )  {  
  
   printf("Program name is: %s\n", argv[0]);  
   
   if(argc < 2){  
      printf("No argument passed through command line.\n");  
   }  
   else{  
      printf("First argument is: %s\n", argv[1]);  
   }  
}  
  • Bước 1: Debug chương trình.
  • Bước 2: Về màn hình desktop ấn tổ hợp phím Windows + R để mở của sổ Run.
  • Bước 3: Gõ cmd chọn OK để mở cửa sổ Command Line.
  • Bước 4: Đưa đường dẫn chứa file program.exe và nhập đối số, mỗi đối số cách nhau bằng một khoảng trắng . Ở đây, tôi sẽ nhập "program.exe" để Command line chạy file này và nhập các đối số “Hello world”. Ngoài ra, bạn cũng có thể nhập “program“ vì command line sẽ hiểu rằng bạn muốn chạy file program.exe.

Kết quả:
 

Program name is: program
First argument is: Hello

Kết quả chương trình sẽ in ra: “program.exe Hello World”. Lúc này số đối số sẽ là argc bằng 3, tương ứng với 2 đối số mà tôi vừa nhập vào và tên của file .exe trong thư mục debug. Lúc này, tên file program.exe chính là argv[0]argv[1] =”Hello”, argv[2] = “World”. 

Nếu bạn truyền nhiều tham số nó chỉ print một

program.exe Hello how are you?  

Kết quả:

Program name is: program
First argument is: Hello

Nếu muốn truyền nhiều tham số thêm dấu nháy đôi:

program.exe "Hello how are you? " 

Kết quả:

Program name is: program
First argument is: Hello how are you?

Chúng ta có thể print nhiều tham số trong chương trình, trong ví dụ trên chỉ print 1 tham số argv[1].


 

Cảnh giới lập trình

Nhằm đơn giản hóa vấn đề, mọi code minh họa trong bài sử dụng ngôn ngữ C/C++.

Cảnh giới 1. Nhập môn (beginner)

Mới bước vào ngành CNTT và lập trình thì ai ai cũng phải “nhập môn”, làm quen. Vì vậy mà nhiều khi code rất là trẻ trâu. Code đọc khó hiểu, tệ hơn là thụt dòng loạn xạ không có quy tắc.

Code minh họa

Cảnh giới 2. Biết sử dụng hàm, thư viện chuẩn có sẵn

Có một điều trớ trêu thay là dù bạn học các ngành về khoa học kĩ thuật hay là về khoa học xã hội, thì vẫn len lỏi đâu đây một yếu tố gọi là “học thuộc lòng”.

Tất nhiên, với các ngành khoa học xã hội thì điều đó dễ dàng nhận ra, môn Văn chẳng hạn, học bài phát điên luôn. Còn với khoa học kĩ thuật thì sao ? Liệu có học bài không ?

Với quan điểm của tôi, một trong những bước đệm để bạn giỏi lên là phải học thuộc càng nhiều hàm, càng nhiều thư viện càng tốt, giống như học từ vựng tiếng Anh ấy. Điều này đôi khi nghe có vẻ phi lý, vì sao ta lại học thuộc lòng ?

Đơn giản vì ta đang muốn giải quyết nhanh một vấn đề, sao ta lại tốn công sức viết thủ công các hàm trong khi thư viện đã có sẵn, gọi 1 phát là xong ? Ta sẽ tiết kiệm được thời gian, công sức để tập trung vào vấn đề chính nhiều hơn. Nhiều khi mình lo viết hàm phụ mà hàm phụ bị lỗi, gây rối, mất tập trung, xuống tinh thần.

Ghi chú: chỉ khi bạn vững thuật toán cơ bản thì mới xài hàm để tiết kiệm thời gian.

Lấy ví dụ minh họa: kiểm tra xem một số nguyên dương có phải số đối xứng hay không. Ví dụ như số 121 là số đối xứng, số 123 thì không phải, số 9009 là số đối xứng, v.v

Làm bình thường chưa biết gì cả

Khi biết sử dụng hàm, bài toán giải quyết “ngọt” hơn

Cảnh giới 3. Tinh thông hàm, thư viện, nguyên lý

“Tinh thông” hoàn toàn khác với chuyện “biết biết một chút”.

Khi bạn hiểu rõ được cú pháp các hàm xử lý, bạn sẽ dễ dàng ứng dụng nó để xử lý bài toán tốt nhất. Lấy lại ví dụ “xác định số đối xứng”. Khi bạn chưa hiểu rõ hàm strcmp, strrev, strcpy thì bạn chỉ hiểu đơn giản là nó giúp mình làm cái này, cái kia. Nhưng khi bạn hiểu rõ được cú pháp của hàm đó, nguyên lý xử lý của hàm đó, thì bạn có thể áp dụng để làm cho code mượt mà hay hơn như hình ở trên.

Cảnh giới 4. Cấu trúc dữ liệu và thuật toán

Đây là một lợi thế của những bạn từng học “đội tuyển Tin học” đi thi Học sinh giỏi cấp tỉnh, thành phố/quốc gia/Olympic. Bạn sẽ ứng dụng những cấu trúc dữ liệu & thuật toán để giải quyết một vấn đề ở mức độ tối ưu (tối ưu về tốc độ là chính).

Có những thứ ở cuộc sống rất là trừu tượng, khi mang nó vào biểu diễn trong lập trình thì phải nói là 1 thảm họa khủng khiếp, vì bình thường ta chỉ khai báo các biến, sử dụng các hàm có sẵn để xài, vậy thôi.

Ví dụ: hệ thống bản đồ. Làm sao mà các lập trình viên có thể mô phỏng lại bản đồ trên máy tính, và có thể giúp ta tìm đường đi ngắn nhất giữa 2 địa điểm nào đó ? Google Maps là 1 ví dụ rất điển hình. Nếu ta chỉ khai báo biến, sử dụng các hàm có sẵn như nhập số, tách chuỗi, ghép chuỗi, v.v thì liệu có thể làm được điều này ?

Nhờ những cấu trúc, dữ liệu cơ bản như số nguyên, số thực, mảng, v.v người ta kết nối chúng, tập hợp lại (trong struct, class) rồi áp dụng một quy tắc hoạt động đặc biệt, vậy là có thể hình thành nên 1 cấu trúc dữ liệu. Từ đó giúp ta giải quyết vấn đề cực kì hay và ngọt, mà lại hiệu quả nữa.

Đi kèm với cấu trúc dữ liệu, đó là thuật toán. Cấu trúc dữ liệu quyết định thuật toán. Thuật toán giúp bạn tư duy tốt hơn. Bạn cần phải luyện tập nhiều với thuật toán.

Cấu trúc dữ liệu thường hay gặp: Stack

Vì vậy nên, để đạt đến một cảnh giới cao hơn, nhìn mọi vật, mọi sự việc khác người bình thường, thì nhất định bạn phải tinh thông cấu trúc dữ liệu và thuật toán 

Cảnh giới 5. Phương pháp lập trình Hướng đối tượng

Cảnh giới được nâng lên tối thượng hay không cũng là nhờ phương pháp lập trình Hướng đối tượng.

Tư duy cũ: lập trình hướng thủ tục/hàm (hàm là trung tâm của việc lập trình)

Minh họa tư duy lập trình với hàm: hàm TinhTong

Tư duy Hướng đối tượng: đối tượng là trung tâm của việc lập trình, hàm chỉ là phụ

Minh họa tư duy Hướng đối tượng

Khi có tư duy lập trình Hướng đối tượng, bạn sẽ nhìn mọi vật, mọi sự việc lên 1 tầm cao mới, khác xa với con mắt của người bình thường (giống như cảnh giới trước đó á).

Phương pháp lập trình Hướng đối tượng (PP LT HĐT) giúp bạn tiết kiệm thời gian, công sức, tái sử dụng code, mở rộng phần mềm. Nếu áp dụng tốt phương pháp lập trình HĐT và cấu trúc dữ liệu/thuật toán thì bạn có thể nói là rất vững cơ bản rồi đó 

P/S: những thứ bạn học PP LT HĐT từ nhà trường, hay là từ video dạy học trên mạng đa số đều rất là tầm thường (nói hơi xúc phạm tí nhưng thực tế là vậy). Bạn đừng nghĩ rằng chỉ học mỗi hàm thành viên (phương thức), kế thừa, rồi đa hình, virtual này nọ thì đã gọi là học xong, nhưng thứ đó đều rất cơ bản. Những cảnh giới cao ở PP LT HĐT còn rất nhiều, cố gắng nhìn lên trên và áp dụng vào những project lớn thì mới nâng tầm được.

Cảnh giới 6. Engine, framework, thư viện, đa nền tảng

Khi học, bạn học từ dưới đáy lên cao thì mới có thể đạt được cảnh giới. Khi bạn học ở trên rồi bạn đào sâu xuống dưới thì thường rất khó và gần như không thể.

5 cảnh giới trước là bạn đang ở đáy, và đến cảnh giới này là bạn bắt đầu học lên mức “ứng dụng thực tế”. Bạn sử dụng các engine, framework, thư viện có sẵn để làm nên 1 chương trình hoàn thiện, có giao diện đàng hoàng, tung ra ngoài thị trường. Bạn có thể va chạm nhiều với MVC, MVVM, XML, database, Windows Form, WPF, Java Swing, v.v

Tưởng tượng như 5 cảnh giới trước là bạn luyện nội công vững vàng, thì ở cảnh giới này bạn học ngoại công để thể hiện ra ngoài. Khi có nội công vững, ngoại công tốt thì thiên hạ nhìn vào biết bạn là cao thủ, thiên hạ khiếp sợ.

Chương trình vẽ MyPaint – niềm tự hào của mình giúp mình đạt điểm cao. https://www.youtube.com/watch?v=A7lbKdudqQY

Game bắn máy bay – https://www.youtube.com/watch?v=4H66-Sf8aE0

Còn với những bạn chưa có nội công tốt mà đã lo vội thể hiện thì thật là thảm họa. Ví dụ như có những bạn lo làm game Flappy Bird, bạn dễ dàng làm được game này nhưng chỉ là phần đồ họa bên ngoài. Chỉ khi bạn học Vật lý, hiểu được công thức rơi tự do (của con chim) thì bạn mới mô phỏng được chính xác chim đang bay, đó là nội công đó bạn. Hay hơn nữa là bạn lập trình trí tuệ nhân tạo cho con chim tự bay, né các ống cống, đây mới gọi là giỏi.

Tưởng tượng: một người chưa có nội lực, nhưng mà được học chút võ công bên ngoài (ngoại công), khi múa võ sẽ làm cho nhiều kẻ sĩ sợ hãi, nhưng mà khi gặp cao thủ chưởng 1 phát là bẹp dí luôn. Còn nếu một người có nội lực mà chưa có ngoại công, lỡ bị cao thủ chưởng thì có thể “ráng chịu đựng đi gặp thầy thuốc chữa trị”. Có nội lực mà còn thêm ngoại công pro thì thôi khỏi nói rồi.

Một số bạn học sâu thì lại có quan niệm khác. Các bạn học sâu thì đào xuống phía dưới chớ không lên trên, bạn sử dụng các thư viện xử lý thread, xử lý va chạm Vật lý chẳng hạn. Đó cũng là một điều tốt. Xa hơn nữa là bạn tính toán chuyện đa nền tảng. Làm sao bạn viết code 1 lần mà biên dịch được trên nhiều nền tảng Windows, Android, iOS, Linux,… (với ngôn ngữ C/C++ chẳng hạn) ???

Cơ bản nhất là sử dụng macro. Sau đây tôi sẽ minh họa khi bạn đạt cảnh giới macro. Tôi sẽ lấy lại ví dụ về việc “nhập vào một số nguyên dương, kiểm tra xem đó là số đối xứng hay không”.

Sử dụng macro trong tiền xử lý (preprocessor) và tùy biến code

Nâng cấp thêm 1 chút

Ở cảnh giới này thì đồng thời bạn đã biết sử dụng các thư viện bên ngoài, biết cách link thư viện với project, biết tạo DLL, LIB và sử dụng chúng. Thường bạn sẽ chìm đắm rất lâu trong cảnh giới này vì ham mê thể hiện và học quá nhiều thứ =))

Cảnh giới 7. Phong cách lập trình

Lên đến cảnh giới này, bạn bắt đầu chăm chú cho code mình được đẹp hơn, ưu việt hơn, dễ đọc hơn. Tưởng tượng: bạn viết 1 đống code cả ngàn dòng rất là cao siêu, sau 1 năm bạn đọc lại code mình bạn còn hiểu không ?

Khoảng trắng giữa các thành phần là quan trọng. Bạn cần tách ra rõ ra phần nào ra phần đó. Ví dụ bạn khai báo biến, sau đó nhập dữ liệu, sau đó xử lý, và xuất ra kết quả. Vậy thì: nên có thêm khoảng trắng giữa 4 thành phần trên.

Đó là chưa kể có cách viết code như sau:

Cách 1: if (x == 0) In_ra_dòng_chữ(“Hello”);

Cách 2: if (0 == x) In_ra_dòng_chữ(“Hello”);

Câu hỏi: liệu có sự khác biệt nào giữa 2 đoạn code trên không ?

Xét về mặt vật lý thì câu trả lời là KHÔNG, đều giống như nhau hoàn toàn. Xét về mặt tư duy: có 1 sự khác biệt rất lớn về đẳng cấp. Vì sao vậy ?

Giả sử ta quên đi 1 dấu ‘=’ trong biểu thức ở lệnh if.

Với cách 1 ta có thể nhầm lẫn if (x = 0) (thiếu đi 1 dấu ‘=’). Và code vẫn hợp lệ với C/C++, vì đó là việc “gán x = 0” nằm bên trong lệnh if, nhưng nó mang 1 ý nghĩa khác hoàn toàn và dẫn đến code sai.

Với cách 2 thì if (0 = x) là câu lệnh vô lý, làm sao mà hằng số gán giá trị được ? IDE sẽ gạch đỏ và báo lỗi ngay cho ta biết ===> “Code tự định nghĩa, tự né tránh lỗi vô lý”.

Một vấn đề nữa đó là vấn đề đặt tên cho class/truct, tên hàm, tên biến, v.v (mặc định ta bàn tới tên biến cho dễ hiểu). Bạn sẽ phải mất nhiều thời gian để đặt tên biến sao cho hay và đúng quy tắc, dễ nhớ. Chỉ có những cao thủ họ mới hiểu được chuyện này. Khi bạn học cơ bản thì bạn chỉ quan tâm “tạo ra biến để xài” chứ ít quan tâm “tên biến như thế nào”. Đơn giản thôi, code vài dòng thì nhìn biến a, biến c, biến x biến y dễ dàng hiểu được. Còn code 10000 dòng thì nhìn vào x, y, z xem có hiểu nó là gì không ?

Cảnh giới 8. Hacking/cracking

Cảnh giới này dành cho những bạn nào thích học sâu về hệ thống bên dưới, có thể sâu đến mức nghiên cứu về hợp ngữ (asm).

Bạn sẽ học với Windows API, shell (Windows). Với Linux bạn có thể tìm hiểu về system calls, kernel, shell, v.v Tôi không xài Linux nhiều nên chỉ chém vậy thôi.

Chương trình “SimpleGame”: tính tổng 2 số, nhập tổng đúng thì tăng level.

Minh họa công cụ “SuperPointer” giúp bạn hack game đơn giản. SuperPointer là một class nhỏ được lập trình bởi tôi – Nguyễn Trung Thành (abcxyz tcIT)

2 hình trên là minh họa việc sử dụng Windows API để hack 1 game nho nhỏ. Bạn sẽ được demo thử công cụ “SuperPointer” của tôi khi học khóa học “Kỹ thuật lập trình & PP lập trình Hướng đối tượng cơ bản” của tôi (PR xíu, hihi).

Ở cảnh giới này, bạn sẽ đi rất sâu về bên dưới, hiểu rõ đươc cơ chế hoạt động của hệ điều hành, ví dụ bạn tiêm DLL, ghi đè dữ liệu lên không gian bộ nhớ của tiến trình để hack, viết ra [virus] keylog, trojan, backdoor; hoặc bạn có thể nghiên cứu về cơ chế hook, message để từ đó mô phỏng lại quá trình test phần mềm tự động (test automation), v.v

Cảnh giới 9. Vô chiêu thắng hữu chiêu

Đến cảnh giới này thì có thể nói bạn đã bước chân đến mức master rồi.

Ở cảnh giới này thì tôi đoán là nhìn code cũng chạy được code trong đầu, khỏi cần chạy trên IDE luôn haha. Bạn có thể tự viết thư viện riêng cho mình mà thậm chí còn hay hơn những thư viện bên ngoài.

Nói vậy thôi, chớ tôi nghĩ rằng khi đạt đến mức độ này thì thường bạn sẽ đi nghiên cứu khoa học và công nghệ, về Big Data, Data Mining, Machine Learning, hay là Virtual Reality, v.v

Và dĩ nhiên còn nhiều cảnh giới cao hơn, tầm mắt của tôi chỉ đạt tới mức này thôi.

========================================================

Ghi chú: trong nhà trường, bạn học theo hướng dẫn thầy cô thì cùng lắm bạn chỉ học được một chút ở mỗi cảnh giới chứ bạn chưa thật sự tinh thông. Chỉ có sự tự học mới đưa bạn được tới đỉnh cao thôi :).

Một điều quan trọng nữa là: – Nếu bạn chỉ biết ở mỗi cảnh giới một chút chút, thì tương đương bạn vẫn là con số 0 (biết 10 ngôn ngữ lập trình nhưng ở mỗi ngôn ngữ chỉ viết được chương trình Hello World). – Nếu bạn tinh thông đầy đủ mỗi cảnh giới, thì bạn vẫn có thể đạt đỉnh cao (chỉ biết 1, 2 ngôn ngữ lập trình nhưng tạo ra được sản phẩm hay). ===> Nếu đã xác định mình đã đam mê, hãy học tới nơi tới chốn, học cho kĩ cho sâu, phóng 1 mũi tên tựa như lao đến được đích cuối cùng.

========================================================

Bài này được viết với quan niệm của 1 junior(er), nên mang tính chủ quan cao. Trong quá trình tiếp xúc, giao lưu, đào tạo với nhiều học sinh, sinh viên, cao thủ khắp cả nước thì tôi rút trích lại và chia sẻ cho các bạn.

P/S: junior(er) đối với tôi là kiến thức chuyên môn CNTT, kỹ năng IT và lập trình ở mức độ “biết nhiều hơn beginner, có khả năng làm ra sản phẩm ở mức độ cơ bản”, tôi vẫn chưa đạt cảnh giới của 1 senior, vẫn còn nhiều điều phải học hỏi từ nhiều cao thủ ẩn danh.

Nguồn:https://techtalk.vn/

Dãy số Fibonacci trong C

Quy luật của dãy số Fibonacci: số tiếp theo bằng tổng của 2 số trước, 2 số đầu tiên của dãy số là 0, 1. Ví dụ: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, …

Có 2 cách để viết chương trình dãy số Fibonacci trong C

  • Tính dãy số Fibonacci trong C không dùng phương pháp đệ quy
  • Tính dãy số Fibonacci trong C sử dụng phương pháp đệ quy

Tính dãy số Fibonacci không dùng phương pháp đệ quy

Ví dụ chương trình tính dãy số Fibonacci không sử dụng phương pháp đệ quy:

File: FibonacciExample1.c

/**
 * Tinh day so Fibonacci KHONG dung phuong phap de quy
 *  
 */

 #include<stdio.h>

/**
 * Tinh so Fibonacci thu n
 * 
 * @param n: chi so cua so Fibonacci tinh tu 0 
 *           vd: F0 = 0, F1 = 1, F2 = 1, F3 = 2
 * @return So Fibonacci thu n
 */
int fibonacci(int n) {
    int f0 = 0;
    int f1 = 1;
    int fn = 1;
    int i;

    if (n < 0) {
        return -1;
    } else if (n == 0 || n == 1) {
        return n;
    } else {
        for (i = 2; i < n; i++) {
            f0 = f1;
            f1 = fn;
            fn = f0 + f1;
        }
    }
    return fn;
}

/**
 * Ham main
 */
int main() {
	int i;
    printf("10 so dau tien cua day so Fibonacci: \n");
    for (i = 0; i < 10; i++) {
        printf("%d ", fibonacci(i));
    }
}

Kết quả:

10 so dau tien cua day so Fibonacci: 
0 1 1 2 3 5 8 13 21 34 

Tính dãy số Fibonacci sử dụng phương pháp đệ quy

Ví dụ chương trình tính dãy số Fibonacci sử dụng phương pháp đệ quy:

File: FibonacciExample2.c

/**
 * Tinh day so Fibonacci bang phuong phap de quy
 *  
 */
#include<stdio.h>

/**
 * Tinh so Fibonacci thu n
 * 
 * @param n: chi so cua so Fibonacci tinh tu 0 
 *           vd: F0 = 0, F1 = 1, F2 = 1, F3 = 2
 * @return So Fibonacci thu n
 */
int fibonacci(int n) {
    if (n < 0) {
        return -1;
    } else if (n == 0 || n == 1) {
        return n;
    } else {
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
}

/**
 * Ham main
 */
int main() {
	int i;
    printf("10 so dau tien cua day so Fibonacci: \n");
        for (i = 0; i < 10; i++) {
        printf("%d ", fibonacci(i));
    }
}

Kết quả:

10 số đầu tiên của dãy số fibonacci: 
0 1 1 2 3 5 8 13 21 34 

 

Kiểm tra số nguyên tố trong C

Định nghĩa: số nguyên tố là số lớn hơn 1 và chỉ chia hết cho 1 và chính nó.

Ví dụ: 2, 3, 5, 7, 11, 13, 17, … là những số nguyên tố.

Chú ý: Số 0 và 1 không phải là số nguyên tố. Chỉ có số 2 là số nguyên tố chẵn, tất cả các số chẵn khác không phải là số nguyên tố vì chúng chia hết cho 2.
 


Ví dụ check số nguyên tố trong C

Chương trình sau kiểm tra một số có phải là số nguyên tố hay không:

File: CheckNguyenTo.c
 

#include<stdio.h>
 
/**
 * check so nguyen to trong C
 * 
 * @param n: so nguyen duong
 * @return 1 la so nguyen so, 
 *         0 khong la so nguyen to
 */
int isPrimeNumber(int n) {
    // so nguyen n < 2 khong phai la so nguyen to
    if (n < 2) {
        return 0;
    }
    // check so nguyen to khi n >= 2
    int squareRoot = (int) sqrt(n);
    int i;
    for (i = 2; i <= squareRoot; i++) {
        if (n % i == 0) {
            return 0;
        }
    }
    return 1;
}

/**
 * Ham main
 */
int main() {
	int i;
    printf("Cac so nguyen to nho hon 100 la: \n");
    for (i = 0; i < 100; i++) {
        if (isPrimeNumber(i)) {
            printf("%d ", i);
        }
    }
}

Kết quả:

Cac so nguyen to nho hon 100 la: 
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 

 

Tính giai thừa trong C

Định nghĩa giai thừa: giai thừa của 1 số là tích các số liên tiếp từ 1 đến số đó. Trường hợp đặc biệt, giai thừa của 0 và 1 là 1.

Ví dụ: giai thừa của 5 là 1*2*3*4*5 = 120

Có 2 cách để viết chương trình tính giai thừa trong C:

  • Tính giai thừa không sử dụng đệ quy.
  • Tính giai thừ có sử dụng đệ quy.

Tính giai thừa không sử dụng đệ quy

Ví dụ chương trình tính giai thừa trong C không sử dụng phương pháp đệ quy:

/**
 * Tinh giai thua KHONG dung phuong phap de quy
 *  
 
 */
 
#include<stdio.h>
 
/**
 * tinh giai thua
 * 
 * @author viettuts.vn
 * @param n: so nguyen duong
 * @return giai thua cua so n
 */
long tinhGiaithua(int n) {
    int i;
    long giai_thua = 1;
    if (n == 0 || n == 1) {
        return giai_thua;
    } else {
        for (i = 2; i <= n; i++) {
            giai_thua *= i;
        }
        return giai_thua;
    }
}
 
/**
 * Ham main
 */
int main() {
    int a = 5;
    int b = 0;
    int c = 10;
    printf("Giai thua cua %d  la: %d \n",  a, tinhGiaithua(a));
    printf("Giai thua cua %d  la: %d \n",  b, tinhGiaithua(b));
    printf("Giai thua cua %d  la: %d",  c, tinhGiaithua(c));
}

Kết quả:

Giai thua cua 5  la: 120
Giai thua cua 0  la: 1
Giai thua cua 10  la: 3628800

Tính giai thừa có sử dụng đệ quy

Ví dụ chương trình tính giai thừa trong C có sử dụng phương pháp đệ quy:
 

/**
 * Tinh giai thua su dung phuong phap de quy
 *  
 
 */

#include<stdio.h>

/**
 * tinh giai thua
 * 
 * @author viettuts.vn
 * @param n: so nguyen duong
 * @return giai thua cua so n
 */
long tinhGiaithua(int n) {
    if (n > 0) {
        return n * tinhGiaithua(n - 1);
    } else {
        return 1;
    }
}

/**
 * Ham main
 */
int main() {
    int a = 5;
    int b = 0;
    int c = 10;
    printf("Giai thua cua %d  la: %d \n",  a, tinhGiaithua(a));
    printf("Giai thua cua %d  la: %d \n",  b, tinhGiaithua(b));
    printf("Giai thua cua %d  la: %d",  c, tinhGiaithua(c));
}

Kết quả:

Giai thua cua 5  la: 120
Giai thua cua 0  la: 1
Giai thua cua 10  la: 3628800

 

Chuyển đổi hệ cơ số trong C

Bài toán

1. Chuyển đổi số nguyên N từ hệ cơ số 10 sang hệ cơ số B bất kỳ. 
2. Chuyển đổi hệ cơ số B sang hệ cơ số 10 bất kỳ.


Cách chuyển đổi hệ cơ số

  • Chuyển đối hệ cơ số 10 sang hệ cơ số B
  • Chuyển đối hệ cơ số B sang hệ cơ số 10

Chuyển đối hệ cơ số 10 sang hệ cơ số B

Cách chuyển đổi số nguyên N từ hệ cơ số 10 sang hệ cơ số 2, trong ảnh dưới đây là ví dụ chuyển số 15 và số 6 sang hệ cơ số 2:

  1. Gán m = 15.
  2. Put phần dư m chia cho 2 (m % 2) vào stack.
  3. Gán m = m / 2.
  4. Nếu m > 0 quay lại bước 2.
  5. Đảo ngược lại stack ta được số cần tính.

Chuyển đổi hệ cơ số trong C

Các hệ số khác chuyển đổi tương tự.


Ví dụ chuyển đối hệ cơ số 10 sang hệ cơ số B

Giả sử hệ cơ số cần chuyển là 2 <= B <= 16. Số đại điện cho hệ cơ số B > 10 là A = 10, B = 11, C = 12, D = 13, E = 14, F = 15.

Chúng ta tạo ra một chương trình như sau để chuyển đổi hệ cơ số trong C:

/**
 * Chuong trinh chuyen doi he co so trong C
 * Bai tap nay su dung bang ASCII de chuyen doi so nguyen thanh kieu ky tu
 * Link tham khao: https://vi.wikipedia.org/wiki/ASCII
 
 */

#include<stdio.h>

const char CHAR_55 = 55;
const char CHAR_48 = 48;

/**
 * chuyen doi so nguyen n sang he co so b
 * 
 * @author viettuts.vn
 * @param n: so nguyen
 * @param b: he co so
 */
int convertNumber(int n, int b) {
    if (n < 0 || b < 2 || b > 16 ) {
        printf("He co so hoac gia tri chuyen doi khong hop le!");
        return 0;
    }
    int i;
    char arr[20];
    int count = 0;
    int m;
    int remainder = n;
    while (remainder > 0) {
        if (b > 10) {
            m = remainder % b;
            if (m >= 10) {
                arr[count] = (char) (m + CHAR_55);
                count++;
            } else {
                arr[count] = (char) (m + CHAR_48);
                count++;
            }
        } else {
            arr[count] = (char) ((remainder % b) + CHAR_48);
            count++;
        }
        remainder = remainder / b;
    }
    // hien thi he co so
    for (i = count - 1; i >= 0; i--) {
        printf("%c", arr[i]);
    }
    return 1;
}

/**
 * Ham main
 */
int main() {
    int n = 12;
    printf("So %d trong he co so 2 = ", n);
    convertNumber(n, 2);
    printf("\nSo %d trong he co so 16 = ", n);
	convertNumber(n, 16);
    return 1;
}

Kết quả:

So 12 trong he co so 2 = 1100
So 12 trong he co so 16 = C

Chuyển đối hệ cơ số B sang hệ cơ số 10

Trong ảnh dưới đây là ví dụ về chuyển đổi hệ cơ số 2 sang hệ cơ số 10.

Chuyển đổi hệ cơ số trong C

Các hệ cơ số khác tương tự.

Giải phương trình bậc 2 trong C

Đề bài

Viết chương trình giải phương trình bậc 2 trong C. Phương trình bậc 2 có dạng:

giải phương trình bậc 2 trong C


Lời giải

Lời giải của chúng tôi sử dụng phương thức sqrt() để tính căn bậc 2 của một số trong C. Sử dụng phương thức scanf(“%f”, &a) để đọc số thực từ bàn phím và gán cho biến a.

#include <stdio.h>
  
/**
 * giai phuong trinh bac 2: ax2 + bx + c = 0
 * 
 * @param a: he so bac 2
 * @param b: he so bac 1
 * @param c: so hang tu do
 */
void giaiPTBac2(float a, float b, float c) {
    // kiem tra cac he so
    if (a == 0) {
        if (b == 0) {
            printf("Phuong trinh vo nghiem!");
        } else {
            printf("Phuong trinh co mot nghiem: x = %f", (-c / b));
        }
        return;
    }
    // tinh delta
    float delta = b*b - 4*a*c;
    float x1;
    float x2;
    // tinh nghiem
    if (delta > 0) {
        x1 = (float) ((-b + sqrt(delta)) / (2*a));
        x2 = (float) ((-b - sqrt(delta)) / (2*a));
        printf("Phuong trinh co 2 nghiem la: x1 = %f va x2 = %f", x1, x2);
    } else if (delta == 0) {
        x1 = (-b / (2 * a));
        printf("Phong trinh co nghiem kep: x1 = x2 = %f", x1);
    } else {
        printf("Phuong trinh vo nghiem!");
    }
}
 
/**
 * ham main
 */
int main() {
    float a, b, c;
    printf("Nhap he so bac 2, a = ");
    scanf("%f", &a);
    printf("Nhap he so bac 1, b = ");
    scanf("%f", &b);
    printf("Nhap so hang tu do, c = ");
    scanf("%f", &c);
    giaiPTBac2(a, b, c);
    return 1;
}

Kết quả:

Nhap he so bac 2, a = 2
Nhap he so bac 1, b = 3
Nhap so hang tu do, c = 1
Phuong trinh co 2 nghiem la: x1 = -0.500000 va x2 = -1.000000

 

Tìm USCLN và BSCNN của 2 số

Đề bài: viết chương trình tìm ước số chung lớn nhất (USCLN) và bội số chung nhỏ nhất (BSCNN) của hai số nguyên dương a và b.


Định nghĩa

USCLN của 2 số nguyên dương a và b là một số k lớn nhất, sao cho a và b đều chia hết cho k.

BSCNN của 2 số nguyên dương a và b là một số h nhỏ nhất, sao cho h chia hết cho cả a và b.


Lời giải

Một phương pháp đơn giản đề tìm USCLN của a và b là duyệt từ số nhỏ hơn trong 2 số a và b cho đến 1, khi gặp số nào đó mà cả a và b đều chia hết cho nó thì đó chính là USCLN của a và b. Tuy vậy phương pháp này chưa phải là hiệu quả nhất.

Vào thế kỷ 3 TCN, nhà toán học Euclid (phiên âm tiếng Việt là Ơ-clit) đã phát minh ra một giải thuật tìm USCLN của hai số nguyên dương rất hiệu quả được gọi là giải thuật Euclid. Cụ thể về ý tưởng của bài toán, giả sử a lớn hơn b, khi đó việc tính UCSLN của a và b sẽ được đưa về bài toán tính USCLN của a mod b và b vì USCLN(a, b) = USCLN(a mod b, b).

Khi đã tìm được USCLN thì việc tìm BSCNN của hai số nguyên dương a và b khá đơn giản. Khi đó BSCNN(a, b) = (a * b) / UCSLN(a, b).


Tìm USCLN và BSCNN của 2 số a và b trong C

Ví dụ dưới đây sử dụng giải thuật Euclid để giải quyết bài toán tìm ước số chung lớn nhất (USCLN) và bội số chung nhỏ nhất (BSCNN) của hai số nguyên dương a và b.

/**
 * Chuong trinh tim uoc chung lon nhat (USCLN)
 * va boi so chung nho nhat (BSCNN) cua 2 so a và b
 *
 */
#include<stdio.h>

/**
 * Tim uoc so chung lon nhat (USCLN)
 */
int USCLN(int a, int b) {
    if (b == 0) return a;
    return USCLN(b, a % b);
}

/**
 * Tim boi so chung nho nhat (BSCNN)
 */
int BSCNN(int a, int b) {
    return (a * b) / USCLN(a, b);
}

/**
 * Ham main
 */
int main() {
	int a, b;
    printf("Nhap so nguyen duong a = ");
    scanf("%d", &a);
    printf("Nhap so nguyen duong b = ");
    scanf("%d", &b);
    // tinh USCLN cua a và b
    printf("USCLN cua %d va %d la: %d", a, b, USCLN(a, b));
    // tinh BSCNN cua a và b
    printf("USCLN cua %d va %d la: %d", a, b, BSCNN(a, b));
}

Kết quả:

Nhap so nguyen duong a = 3
Nhap so nguyen duong b = 4
USCLN cua 3 va 4 la: 1
USCLN cua 3 va 4 la: 12

 

Liệt kê tất cả các số nguyên tố nhỏ hơn n

Định nghĩa

Số nguyên tố là số lớn hơn 1 và chỉ chia hết cho 1 và chính nó. 
Ví dụ: 2, 3, 5, 7, 11, 13, 17, … là những số nguyên tố. 
Chú ý: Số 0 và 1 không phải là số nguyên tố. Chỉ có số 2 là số nguyên tố chẵn, tất cả các số chẵn khác không phải là số nguyên tố vì chúng chia hết cho 2.


Lời giải

/**
 * Chuong liet ke cac so nguyen to nho hon n.
 * 
 * @author viettuts.vn
 */
#include<stdio.h>
 
/**
 * check so nguyen to
 * 
 * @author viettuts.vn
 * @param n: so nguyen duong
 * @return 1: la so nguyen so, 
 *         0: khong la so nguyen to
 */
int isPrimeNumber(int n) {
    // so nguyen n < 2 khong phai la so nguyen to
    if (n < 2) {
        return 0;
    }
    // check so nguyen to khi n >= 2
    int i;
    int squareRoot = (int) sqrt(n);
    for (i = 2; i <= squareRoot; i++) {
        if (n % i == 0) {
            return 0;
        }
    }
    return 1;
}
 
/**
 * Ham main
 */
int main() {
    int i, n;
    printf("Nhap n = ");
    scanf("%d", &n);
    printf("Tat ca cac so nguyen to nho hon %d la: \n", n);
    if (n >= 2) {
        printf("%d ", 2);
    }
    for (i = 3; i < n; i+=2) {
        if (isPrimeNumber(i) == 1) {
            printf("%d ", i);
        }
    }
}

Kết quả:

Nhập n = 100
Tat ca cac so nguyen to nho hon 100 la: 
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

 

Liệt kê n số nguyên tố đầu tiên

Định nghĩa

Số nguyên tố là số lớn hơn 1 và chỉ chia hết cho 1 và chính nó. 
Ví dụ: 2, 3, 5, 7, 11, 13, 17, … là những số nguyên tố. 
Chú ý: Số 0 và 1 không phải là số nguyên tố. Chỉ có số 2 là số nguyên tố chẵn, tất cả các số chẵn khác không phải là số nguyên tố vì chúng chia hết cho 2.


Lời giải

/**
 * Chuong trinh liet ke n so nguyen to dau tien.
 * 
 */
 #include<stdio.h>
 #include<math.h>

/**
 * check so nguyen to
 * 
 * @author viettuts.vn
 * @param n: so nguyen duong
 * @return 1: la so nguyen so, 
 *         0: khong la so nguyen to
 */
int isPrimeNumber(int n) {
    // so nguyen n < 2 khong phai la so nguyen to
    if (n < 2) {
        return 0;
    }
    // check so nguyen to khi n >= 2
    int i;
    int squareRoot = sqrt(n);
    for (i = 2; i <= squareRoot; i++) {
        if (n % i == 0) {
            return 0;
        }
    }
    return 1;
}

/**
 * Ham main
 */
int main() {
	int n;
    printf("Nhap n = ");
    scanf("%d", &n);
    printf("%d so nguyen to dau tien la: \n", n);
    int dem = 0; // dem tong so nguyen to
    int i = 2;   // tim so nguyen to bat dau tu so 2
    while (dem < n) {
        if (isPrimeNumber(i)) {
            printf("%d ", i);
            dem++;
        }
        i++;
    }
}

Kết quả:

Nhập n = 10
10 so nguyen to dau tien la: 
2 3 5 7 11 13 17 19 23 29 

 

Liệt kê tất cả số nguyên tố có 5 chữ số

Định nghĩa

Số nguyên tố là số lớn hơn 1 và chỉ chia hết cho 1 và chính nó. 
Ví dụ: 2, 3, 5, 7, 11, 13, 17, … là những số nguyên tố. 
Chú ý: Số 0 và 1 không phải là số nguyên tố. Chỉ có số 2 là số nguyên tố chẵn, tất cả các số chẵn khác không phải là số nguyên tố vì chúng chia hết cho 2.


Lời giải

/**
 * Chuong trinh liet ke tat ca so nguyen to co 5 chu so.
 * 
 * @author viettuts.vn
 */
 
#include<stdio.h>

/**
 * check so nguyen to
 * 
 * @author viettuts.vn
 * @param n: so nguyen duong
 * @return 1: la so nguyen so, 
 *         0: khong la so nguyen to
 */
int isPrimeNumber(int n) {
    // so nguyen n < 2 khong phai la so nguyen to
    if (n < 2) {
        return 0;
    }
    // check so nguyen to khi n >= 2
    int i;
    int squareRoot = (int) sqrt(n);
    for (i = 2; i <= squareRoot; i++) {
        if (n % i == 0) {
            return 0;
        }
    }
    return 1;
}

/**
 * Ham main
 */
int main() {
    int count = 0;
    int i;
    printf("Liet ke tat ca cac so co 5 chu so:");
    for (i = 10001; i < 99999; i+=2) {
        if (isPrimeNumber(i)) {
            printf("%d\n", i);
            count++;
        }
    }
    printf("Tong cac so nguyen to co 5 chu so la: %d", count);
}

Kết quả:

Liet ke tat ca cac so co 5 chu so:
10007
10009
10037
...
99971
99989
99991
Tong cac so nguyen to co 5 chu so la: 8363

 

Phân tích số nguyên n thành tích các số nguyên tố

Đề bài: viết chương trình phân tích số nguyên n thành các thừa số nguyên tố. Ví dụ: 12 = 2 x 2 x 3.


Lời giải

/**
 * Chuong trinh phan tich so nguyen n thanh tich cac thua so nguyen to
 * Vi du: 12 = 2 x 2 x 3.
 * 
 * 
 */
#include<stdio.h>

/**
 * Phan tich so nguyen n thanh tich cac thua so nguyen to
 */
void phanTichSoNguyen(int n) {
    int i = 2;
    int dem = 0;
    int a[100];
    // phan tich
    while (n > 1) {
        if (n % i == 0) {
            n = n / i;
            a[dem++] = i;
        } else {
            i++;
        }
    }
    // neu dem = 0 thi n la nguyen to
    if (dem == 0) {
        a[dem++] = n;
    }
    // in ket qua ra man hinh
    for (i = 0; i < dem - 1; i++) {
        printf("%d x ", a[i]);
    }
    printf("%d", a[dem - 1]);
}

/**
 * Ham main
 */
int main() {
	int n;
    printf("Nhap so nguyen duong n = ");
    scanf("%d", &n);
    // phan tich so nguyen duong n
    phanTichSoNguyen(n);
}

Kết quả:

Nhap so nguyen duong n = 120
2 x 2 x 2 x 3 x 5

 

Tính tổng của các chữ số của môt số nguyên n

Đề bài: viết chương trình tính tổng các chữ số của một số nguyên n. Ví dụ: 1234 = 1 + 2 + 3 + 4 = 10.


Lời giải

#include<stdio.h>
 
const int DEC_10 = 10;

/**
 * Ham main
 */
int main() {
	int n;
    printf("Nhap so nguyen duong n = ");
    scanf("%d", &n);
    printf("Tong cac chu so cua %d la: %d", n, totalDigitsOfNumber(n));
}

/**
 * Tinh tong cac chu so cua mot so nguyen duong
 */
int totalDigitsOfNumber(int n) {
    int total = 0;
    do {
        total = total + n % DEC_10;
        n = n / DEC_10;
    } while (n > 0);
    return total;
}

Kết quả:

Nhap so nguyen duong n = 1234
Tong cac chu so cua 1234 la: 10

 

Tìm số thuận nghịch trong C

Đề bài: Một số được gọi là số thuận nghịch nếu ta đọc từ trái sang phải hay từ phải sang trái số đó ta vẫn nhận được một số giống nhau. Ví dụ 123321 là một số thuận nghịch. Hãy liệt kê tất cả các số thuận nghịch có 6 chữa số.


Lời giải

Cách 1: Duyệt các số từ 100000 đến 999999, rồi phân tách số hiện tại thành các chữ số đơn lẻ để kiểm tra tính thuận nghịch.

/**
 * Chuong trình li?t kê t?t c? các s? thu?n ngh?ch có 6 ch?a s?.
 * 
 *
 */
 #include<stdio.h>
    
const int DEC_10 = 10;

/**
 * main
 * 
 * @param args
 */
int main() {
    int count = 0, i;
    // in ra man hinh cac so thuan nghich co 6 chu so
    for (i = 100000; i < 1000000; i++) {
        if (isThuanNghich(i)) {
            printf("%d\n", i);
            count++;
        }
    }
    printf("Tong cac so thuan nghich co 6 chu so la: %d", count);
}

/**
 * kiem tra so thuan nghich
 * 
 * @param n: so nguyen duong
 * @return 1: la so thuan nghich
 *         0: khong la so thuan nghich
 */
int isThuanNghich(int n) {
    int a[20];
    int dem = 0, i;
    // phan tich n thanh mang cac chu so
    do {
        a[dem++] = (n % DEC_10);
        n = n / DEC_10;
    } while (n > 0);
    // kiem tra tinh thuan nghich
    for (i = 0; i < (dem/2); i++) {
        if (a[i] != a[(dem - i - 1)]) {
            return 0;
        }
    }
    return 1;
}

Kết quả:

100001
101101
102201
...
997799
998899
999999
Tong cac so thuan nghich co 6 chu so la: 900

 

Liệt kê số Fibonacci nhỏ hơn n và là số nguyên tố

Đề bài: Nhập số tự nhiên n từ bàn phím. Hãy liệt kê các số Fibonacci nhỏ hơn n là số nguyên tố.


Lời giải

/**
 *  Chuong trinh liet ke cac so Fibonacci nho hon n la so nguyen to.
 *  
 * @author viettuts.vn
 */
#include<stdio.h>

/**
 * Ham main
 */
int main() {
	int n;
    printf("Nhap so nguyen duong = ");
    scanf("%d", &n);
    printf("Cac so fibonacci nho hon %d va la so nguyen to: ", n);
    int i = 0;
    while (fibonacci(i) < n) {
        int fi = fibonacci(i);
        if (isPrimeNumber(fi)) {
            printf("%d ", fi);
        }
        i++;
    }
}

/**
 * Tinh so fibonacci thu n
 * 
 * @param n: chi so cua day fibonacci tinh tu 0
 *           vd: F0 = 0, F1 = 1, F2 = 1, F3 = 2
 * @return so fibonacci thu n
 */
int fibonacci(int n) {
    if (n < 0) {
        return -1;
    } else if (n == 0 || n == 1) {
        return n;
    } else {
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
}

/**
 * check so nguyen to
 * 
 *
 * @param n: so nguyen duong
 * @return 1: la so nguyen so, 
 *         0: khong la so nguyen to
 */
int isPrimeNumber(int n) {
    // so nguyen n < 2 khong phai la so nguyen to
    if (n < 2) {
        return 0;
    }
    // check so nguyen to khi n >= 2
    int i;
    int squareRoot = sqrt(n);
    for (i = 2; i <= squareRoot; i++) {
        if (n % i == 0) {
            return 0;
        }
    }
    return 1;
}

Kết quả:

Nhap so nguyen duong = 100
Cac so fibonacci nho hon 100 va la so nguyen to: 2 3 5 13 89