Lập trình C: Bài 2 – Kiểu dữ liệu và nhập xuất trong C

CHÚ Y: Bài viết đã được cập nhật và chỉnh sửa để đầy đủ hơn tại Bài 2: Các thành phần trong CBài 3: Nhập xuất trong C

Bài hôm nay nhìn tương đối dài tuy nhiên thì khi thực hành sẽ thấy rất là đơn giản. Đây là mục lục bài viết

A. Kiểu dữ liệu trong C

1. Các ký tự điều khiển

  • \n : Nhảy xuống dòng kế tiếp canh về cột đầu tiên.
  • \t : Canh cột tab ngang.
  • \r : Nhảy về đầu hàng, không xuống hàng.
  • \a : Tiếng kêu bip.
  • \\ : In ra dấu \
  • \” : In ra dấu “
  • \’ : In ra dấu ‘
  • %%: In ra dấu %

Đây chỉ là một số ký tự điểu khiển quen thuộc, hay dùng, ngoài ra còn một só ký tự điều khiển khác các bạn có thể xem thêm trong các tài liệu.
Dể hiểu rõ về các ký tự điều khiển các bạn hãy chạy thử chương trình sau và tự rút ra nhận xét cho riêng mình.

#include <stdio.h>

int main(){
	printf("\a");
	printf("Hinh nhu vua co tieng gi keu @@\n");
	printf("Ban dang o dong thu 2\nBay gio xuong dong 3 roi ne ^^\n");
	printf("\tDong nay cach ra 1 tab thi phai?\n");
	printf("\t\t\t\t\t\tCach ra nhieu tab qua \rVe dau dong thoi\n");
	printf("Dau \\ \nDau \'\nDau \" \nDau %%");

	// day la mot dong ghi chu

	/*
	  Day la mot doan ghi chu
	  Doan ghi chu nay co 2 dong
	 */

	// system("pause"); // su dung de dung man hinh neu ban dung dev-C
	return 0;
}

2. Từ khóa

Là các từ mà ngôn ngữ C đã xây dựng sẵn, chúng ta không nên định nghĩa lại chúng.

Bảng các từ khóa trong C

3. Kiểu và biến

a. Kiểu dữ liệu

Kiểu dữ liệu giống như là các thùng chứa, vật dụng để đựng đồ dùng của chúng ta. VD ca uống nước để đựng nước, cái rổ để đựng rau,…

Mỗi loại dữ liệu có kích thước khác nhau và tương ứng với miền giá trị và loại giá trị mà nó có thể thực hiện. VD kiểu int chiếm 2 byte bộ nhớ và để chứa các số nguyên,…

Kiểu dữ liệu trong C
Kiểu dữ liệu trong C

b. Biến – hằng
Tương ứng với mỗi kiểu dữ liệu chúng ta có các biến, hằng thuộc các kiểu đó và có miền giá trị tương ứng như trên dùng để lưu giá trị. Các bạn cần phân biệt kiểu và biến.
VD cái rổ A để đựng rau muống, cái rổ B để đựng rau cần thì tương ứng biến a lưu giá trị số 5, còn biến b lưu giá trị số 9 mặc dù chúng cùng kiểu

Biến có thể thay đổi trong quá trình thực hiện chương trình còn hằng thì không thể.

Cách khai báo biến: kiểu_dữ_liệu tên_biến;
– Tên biến hợp lệ là một chuỗi ký tự liên tục gồm: Ký tự chữ, số và dấu gạch dưới. Ký tự đầu của tên phải là chữ hoặc dấu gạch dưới. Khi đặt tên không được đặt trùng với các từkhóa.
Ví dụ1 :
Các tên đúng: delta, a_1, Num_ODD, Case
Các tên sai: 3a_1 (ký tự đầu là số); num-odd (sử dụng dấu gạch ngang); int (đặt tên trùng với từkhóa) ; del ta (có khoảng trắng); f(x) (có dấu ngoặc tròn)
Lưu ý: Trong C, tên phân biệt chữ hoa, chữ thường
Ví dụ2 : number khác Number ; case khác Case (case là từ khóa, do đó bạn đặt tên là Case vẫn đúng)
Cú pháp: kiểu danh_sach_cac_bien;
VD:

#include <stdio.h>

int main(){
	int a, b; // khai bao 2 bien kieu so nguyen
	float c, d; // khai bao 2 bien kieu so thuc
	a = 1;
	b = 2;
	c = 3.4;
	d = 5.6;

	int e = 4, f = 6;

	printf("a = %d; b = %d\n", a, b);
	printf("c = %f; d = %f\n", c, d);
	printf("e = %d; f = %d\n", e, f);

	// system("pause"); // su dung de dung man hinh neu ban dung dev-C
	return 0;
}

Như trên các bạn thấy cấu trúc khai báo rồi đó. Còn về lệnh xuất ra màn hình các giá trị thì có một số điều khác đó là cách sử dụng %d, %f . Cái này mình sẽ nói cụ thể ở phần sau, đến đây các bạn cứ viết theo để thấy được cách khai báo biến là ok roài. !

Vị trí khai báo biến:
Khi lập trình, bạn phải nắm rõ phạm vi của biến. Nếu khai báo và sử dụng không đúng, không rõ ràng sẽ dẫn đến sai sót khó kiểm soát được, vì vậy bạn cần phải xác định đúng vị trí, phạm vi sử dụng biến trước khi sử dụng biến.
Khai báo biến ngoài (biến toàn cục): Vị trí biến đặt bên ngoài tất cả các hàm, cấu trúc… Các biến này có ảnh hưởng đến toàn bộ chương trình. Chu trình sống của nó là bắt đầu chạy chương trình đến lúc kết thúc chương trình.
Khai báo biến trong (biến cục bộ): Vị trí biến đặt bên trong hàm, cấu trúc…. Chỉ ảnh hưởng nội bộ bên trong hàm, cấu trúc đó…. Chu trình sống của nó bắt đầu từ lúc hàm, cấu trúc được gọi thực hiện đến lúc thực hiện xong.
Lý thuyết đôi khi mơ hồ, các bạn làm ví dụ sau và chạy sẽ thấy rõ hơn nhiều.

#include <stdio.h>

int a = 1, b = 5; // khai bao bien toan cuc, no se duoc dung o bat ky dau

int main(){
	// khai bao 2 bien trong ham main, no se duoc dung trong toan bo ham main ke tu dong nay
	int c = 4, d = 6; 

	{
		int e = 6, d = 8;
		c = 7;
		printf("gia tri cac bien trong khoi:\n");
		printf("e = %d \t d = %d \t c = %d\n", e, d, c);
	}

	printf("gia tri cac bien trong ham main:\n");
	printf("c = %d \t d = %d\n", c, d);

	printf("gia tri cac bien toan cuc:\n");
	printf("a = %d \t b = %d\n", a, b);

	// system("pause"); // su dung de dung man hinh neu ban dung dev-C
	return 0;
}

Các bạn chạy chương trình, xem kết quả và tự rút ra nhận xét nhá, nếu vẫn chưa rõ có thể hỏi trực tiếp trên blog.
Cách khai báo hằng: Khai báo hằng bạn có thể khai báo ở bất kỳ đâu trong chương trình, khai báo ở đâu thì từ đó hằng sẽ được xác định.
Cú pháp: #define ten_hang gia_tri (Không có dấu chấm phảy ở cuối nhá)
Chú ý chúng ta không dùng cấu trúc const như một số người dùng vì khi dùng const trong một số trường hợp ta vẫn thay đổi được giá trị của hằng.

#include <stdio.h>

#define a 6 	// hang so
#define c 'a'  // hang ky tu
#define s "nguyenvanquan7826" // hang chuoi

int main(){
	printf("hang a = %d\n", a);
	printf("hang c = %c\n", c);
	printf("hang s = %s\n", s);

	// system("pause"); // su dung de dung man hinh neu ban dung dev-C
	return 0;
}

Các bạn chạy và cảm nhận nhá

B. Nhập, Xuất trong C

1. Chuỗi định dạng dữ liệu

Trước khi đến với phần nhập, xuất dữ liệu cho các biến mình sẽ nói về một số định dạng để nhập và xuất. Sau đây là các dấu mô tả định dạng:

  • %c : Ký tự đơn
  • %s : Chuỗi
  • %d : Số nguyên hệ 10 có dấu
  • %f : Số chấm động (VD 5.54 khi in sẽ ra 5.540000)
  • %e : Số chấm động (ký hiệu có số mũ)
  • %g : Số chấm động (VD 5.54 khi in sẽ in ra 5.54)
  • %x : Số nguyên hex không dấu (hệ 16)
  • %o : Số nguyên bát phân không dấu (hệ 8)
  • l : Tiền tố dùng kèm với %d, %x, %o để chỉ số nguyên dài (ví dụ%ld)

2. Xuất dữ liệu: printf();

Chúng ta sử dụng hàm printf để xuất dữ liệu ra màn hình console.

#include <stdio.h>

int main(){
	int a = 12;
	float b = 13.5;
	char c = 'Q';
	long d = 3454;
	char* s = "nguyenvanquan7826"; // khai bao kieu chuoi

	printf("tong cua %d va %f la %f \n", a, b, a+b);
	printf("tich cua %d va %ld la %ld \n", a, d, a*d);
	printf("ky tu c la: %c \n", c);
	printf("chuoi s la: %s \n", s);
	printf("dinh dang so mu cua b la %e \n", b);
	printf("so he 16 va he 8 cua %d la %x va %o \n", a, a, a);
	printf("ma ASCII cua %c la %d", c, c);

	// system("pause"); // su dung de dung man hinh neu ban dung dev-C
	return 0;
}

Mình xin giải thích 1 câu lệnh để làm rõ hơn việc xuất của chúng ta.
xuatdulieu

Các bạn cũng chú ý là đối với số nguyên và ký tự có sự qua lại với nhau thông qua mã ASCII nên chúng ta có thể in mã của ký tự bằng định dạng %d và cũng có thể in ký tự có mã là số nào đó thông qua định dạng %c. Tuy nhiên bản chất của biến không thay đổi. Ở Vd trên câu lệnh in mã ASCII của c sẽ cho số nguyên nhưng bản chất c vẫn là một biến kiểu char.
Các bạn hãy chạy và cảm nhận !

Tiếp nhá, một vài cách xuất có định dạng:

  • %5c : Xuất ký tự có bề rộng 5
  • %5d : Số nguyên có bề rộng 5
  • %20s : Xuất chuỗi có bề rộng 20
  • %5.3f : Xuất số thực có bề rộng 5 trong đó có 3 số sau dấu phẩy
  • %-5d : Số nguyên có bề rộng 5 nhưng căn lề trái

Chạy và cảm nhận vd !

#include <stdio.h>

int main(){
    int a = 12;
    float b = 13.5;
    char c = 'Q';
    long d = 3454;
    char* s = "nguyenvanquan7826"; // khai bao kieu chuoi
    
    printf("%6d %5.3f %.3f \n", a, b, a+b);
    printf("%-5d %5ld %5ld \n", a, d, a*d);
    printf("%5c \n", c);
    printf("%30s \n", s);
    
    // system("pause"); // su dung de dung man hinh neu ban dung dev-C
    return 0;
}

3. Nhập dữ liệu: scanf();

Ta sử dụng hàm scanf để nhập liệu từ bàn phím

#include <stdio.h>

int main(){
	int a;
	float b;

	printf("Nhap so nguyen a = ");
	scanf("%d", &a);

	printf("Nhap so thuc b = ");
	scanf("%f", &b);

	printf("a = %d \t b = %.3f", a, b);

	// system("pause"); // su dung de dung man hinh neu ban dung dev-C
	return 0;
}

Từ ví dụ này ta thấy cú pháp để nhập: scanf (“chuỗi định dạng”[, đối 1, đối 2,…]);
Chú ý đừng quên ký tự & trước mỗi biến. Nếu không sẽ sai.
Chuỗi định dạng được đặt trong ngoặc kép: “ ” và các định dạng tương tự như khi chúng ta xuất dữ liệu.
Tương ứng với mỗi định dạng là một kiểu tương ứng, nếu khác kiểu sẽ dần đến sai sót.

4. Nhập chuỗi trong C

Nếu các bạn dùng hàm scanf để nhập chuỗi thì bạn sẽ thấy rằng không thể nhập được chuỗi có dấu cách hoặc nếu trước đó bạn nhập số thì sau đó không nhập được chuỗi nữa. Nếu không tin bạn có thể thử chạy với chương trình sau:

#include <stdio.h>

int main(){
	int tuoi = 0;
	// khai bao chuoi co toi da 30 ky tu
	char ten[30], tenNguoiYeu[30];

	printf("Ho va ten cua ban ten la gi?");
	scanf("%s", ten); // nhap chuoi khong can dau &

	printf("Ban bao nhieu tuoi roi?");
	scanf("%d", &tuoi);

	printf("Nguoi yeu cua ban ten la gi?");
	scanf("%s", tenNguoiYeu);

	printf("\n====\n");
	printf("%s \n%d \n%s", ten, tuoi, tenNguoiYeu);
	// system("pause"); // su dung de dung man hinh neu ban dung dev-C
	return 0;
}

Kết quả là bạn sẽ không nhập được tuổi và tên người yêu như hình sau.
nhap chuoi trong c

Lý do là scanf chỉ đọc được dữ liệu không có khoảng trắng (đấu cách, dấu tab, enter, …) và các khoảng cách này sẽ được lưu vào bộ đệm bàn phím do đó bạn chỉ nhận được chuỗi đầu tiên trước đấu cách mà thôi (chữ Nguyen), sau mỗi dấu cách, các giá trị tiếp theo nếu phù hợp với kiểu dữ liệu của các biến tiếp theo thì nó sẽ gán luôn cho chúng và bạn sẽ không được nhập nữa. Do tuoi kiểu nguyên nên không nhận được, tenNguoiYeu sẽ nhận giá trị tiếp theo trong các giá trị nhận được là chữ Van.

5. Hiện tượng trôi lệnh

Hiện tượng như trên được gọi là hiện tượng trôi lệnh. Nếu bây giờ bạn thực hiện cho nhập số trước và chuỗi ngay sau đó thì hiện tượng này cũng xảy ra vì scanf không đọc được phím enter khi bạn nhấn lúc nhập xong số, nó được lưu vào bộ đệm và khi đọc giá trị nhập cho chuỗi nó tìm trong bộ đệm thấy ký tự enter là kiểu chuỗi nên nó gán luôn cho chuỗi đó.

Để nhập được chuỗi có khoảng trắng (dấu cách) chúng ta sử dụng hàm gets.

Để không bị trôi lệnh khi nhập số trước và chuỗi sau ta cần xóa bộ đệm bàn phím bằng lệnh fflush(stdin); ngay sau khi nhập số.

#include <stdio.h>

int main(){
	int tuoi = 0;
	// khai bao chuoi co toi da 30 ky tu
	char ten[30], tenNguoiYeu[30];

	printf("Ho va ten cua ban ten la gi?");
	gets(ten); // nhap chuoi khong can dau &

	printf("Ban bao nhieu tuoi roi?");
	scanf("%d", &tuoi);
	fflush(stdin);

	printf("Nguoi yeu cua ban ten la gi?");
	gets(tenNguoiYeu);

	printf("\n====\n");
	printf("%s \n%d \n%s", ten, tuoi, tenNguoiYeu);
	// system("pause"); // su dung de dung man hinh neu ban dung dev-C
	return 0;
}

Nếu bạn dùng Linux thì fflush(stdin); sẽ không hoạt động, bạn hãy đọc bài fflush(stdin) trong ubuntu (linux) hoặc gets() and fget() in C/C++ để biết cách khắc phục.

Bảng mã ASCII
ascii


CHÚ Y: Bài viết đã được cập nhật và chỉnh sửa để đầy đủ hơn tại Bài 2: Các thành phần trong CBài 3: Nhập xuất trong C