Bài tập C: hệ đếm, kiểu dữ liệu, rẽ nhánh, vòng lặp
Luyện nền tảng bám theo Chương 1 đến 4: hệ đếm và bù hai, kiểu và biến, nhập xuất, toán tử, rẽ nhánh và vòng lặp. Tự làm trước, bí thì mở Gợi ý. Lời giải đầy đủ nằm trong từng bài học tương ứng.
Bài 1: đổi số nguyên sang hệ nhị phân
Nhập một số nguyên dương n, in ra biểu diễn nhị phân của nó (ví dụ 13 cho 1101).
Gợi ý
Lấy dư cho 2 để rút từng bit từ phải sang trái, rồi chia nguyên cho 2. Lưu các bit vào
mảng rồi in ngược lại. Nhớ #include <stdio.h>.
#include <stdio.h>
int main(void) {
int n;
scanf("%d", &n); // read a positive integer
int bits[32];
int count = 0;
if (n == 0) bits[count++] = 0;
while (n > 0) {
bits[count++] = n % 2; // remainder is the lowest bit
n /= 2; // integer division drops the fraction
}
for (int i = count - 1; i >= 0; i--) {
printf("%d", bits[i]);
}
printf("\n");
return 0;
}
Xem lại bài Hệ đếm và biểu diễn bù hai.
Bài 2: nhập và tính trung bình ba số thực
Nhập ba số thực, in ra trung bình cộng của chúng với hai chữ số thập phân.
Gợi ý
Kiểu double dùng %lf khi đọc bằng scanf, còn printf dùng %f. Chia cho 3.0
(số thực) để không bị cắt phần lẻ.
#include <stdio.h>
int main(void) {
double a, b, c;
scanf("%lf %lf %lf", &a, &b, &c); // %lf reads a double
double avg = (a + b + c) / 3.0; // divide by 3.0 to keep the fraction
printf("%.2f\n", avg); // %f prints a double
return 0;
}
Xem lại bài Kiểu dữ liệu, biến và nhập xuất.
Bài 3: tách chữ số hàng đơn vị và hàng chục
Nhập một số nguyên có ít nhất hai chữ số, in ra chữ số hàng đơn vị và hàng chục.
Gợi ý
Hàng đơn vị là n % 10. Hàng chục là (n / 10) % 10, trong đó / là chia nguyên nên
cắt bỏ phần lẻ.
#include <stdio.h>
int main(void) {
int n;
scanf("%d", &n);
int don_vi = n % 10; // last digit
int hang_chuc = (n / 10) % 10; // integer division then remainder
printf("%d %d\n", hang_chuc, don_vi);
return 0;
}
Xem lại bài Toán tử và biểu thức.
Bài 4: kiểm tra số nguyên tố
Nhập số nguyên n, in "Nguyen to" nếu n là số nguyên tố, ngược lại in "Khong".
Gợi ý
Số nhỏ hơn 2 không phải nguyên tố. Duyệt các ước từ 2 tới i * i <= n, nếu n % i == 0
thì có ước nên không nguyên tố. Dùng một biến cờ khởi tạo rõ ràng, biến cục bộ không tự
gán 0.
#include <stdio.h>
int main(void) {
int n;
scanf("%d", &n);
int la_nt = 1; // flag, initialized explicitly
if (n < 2) la_nt = 0;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) { // divisor found
la_nt = 0;
break;
}
}
printf(la_nt ? "Nguyen to\n" : "Khong\n");
return 0;
}
Xem lại bài Vòng lặp.
Bài 5: giai thừa bằng vòng lặp
Nhập số nguyên dương n, tính n! = 1 * 2 * ... * n.
Gợi ý
Biến tích phải khởi tạo bằng 1, không phải 0. Giai thừa lớn rất nhanh nên dùng
unsigned long long. Với số nguyên có dấu, tràn số là hành vi không xác định, chỉ
unsigned mới quay vòng theo modulo.
#include <stdio.h>
int main(void) {
int n;
scanf("%d", &n);
unsigned long long gt = 1; // product starts at 1
for (int i = 2; i <= n; i++) {
gt *= i; // multiply accumulate
}
printf("%llu\n", gt);
return 0;
}
Xem lại bài Vòng lặp.
Bài 6: bảng cửu chương với vòng lặp lồng
Nhập một số k từ 1 đến 9, in bảng cửu chương của k từ k x 1 đến k x 10.
Gợi ý
Một vòng for (int i = 1; i <= 10; i++) là đủ, mỗi dòng in k, i và tích k * i.
Nếu muốn in cả bảng từ 1 đến 9 thì lồng thêm một vòng ngoài.
#include <stdio.h>
int main(void) {
int k;
scanf("%d", &k);
for (int i = 1; i <= 10; i++) {
printf("%d x %d = %d\n", k, i, k * i);
}
return 0;
}
Xem lại bài Vòng lặp.
Bài 7: phân loại điểm bằng if-else và switch
Nhập điểm nguyên trong khoảng 0 đến 10, in xếp loại: từ 8 trở lên "Gioi", từ 7 "Kha",
từ 5 "Trung binh", còn lại "Yeu". Thử làm cả hai cách: chuỗi if / else if và switch.
Gợi ý
Với if, kiểm tra từ ngưỡng cao xuống thấp, nhánh đúng đầu tiên chạy rồi bỏ qua phần
còn lại. Với switch, gom nhiều nhãn liền nhau và nhớ break để không rơi xuống nhánh
kế. Không dùng == để so sánh số thực, ở đây điểm là số nguyên nên switch mới hợp lệ.
#include <stdio.h>
int main(void) {
int diem;
scanf("%d", &diem);
switch (diem) {
case 10:
case 9:
case 8:
printf("Gioi\n");
break; // break stops fall-through
case 7:
printf("Kha\n");
break;
case 6:
case 5:
printf("Trung binh\n");
break;
default:
printf("Yeu\n");
}
return 0;
}
Xem lại bài Rẽ nhánh.
Bài 8: ước chung lớn nhất theo thuật toán Euclid
Nhập hai số nguyên dương a và b, tìm ước chung lớn nhất của chúng bằng thuật toán
Euclid (lặp cho tới khi số dư bằng 0).
Gợi ý
Ý chính: thay cặp (a, b) bằng (b, a % b) và lặp cho tới khi b bằng 0, khi đó a
chính là ước chung lớn nhất. Phép % là phần dư của chia nguyên.
#include <stdio.h>
int main(void) {
int a, b;
scanf("%d %d", &a, &b);
while (b != 0) { // Euclid: replace (a, b) with (b, a % b)
int r = a % b;
a = b;
b = r;
}
printf("%d\n", a); // gcd sits in a when b becomes 0
return 0;
}
Xem lại bài Vòng lặp.
Bài 9: tính tổng các chữ số
Nhập một số nguyên n, tính tổng các chữ số của nó. Ví dụ n = 1234 cho kết quả 10.
Gợi ý
Lấy chữ số cuối bằng n % 10, cộng dồn rồi bỏ nó đi bằng n /= 10 (chia nguyên cắt phần
lẻ). Nếu n âm thì xử lý trên giá trị tuyệt đối.
#include <stdio.h>
int main(void) {
int n;
scanf("%d", &n);
if (n < 0) n = -n; // work on the absolute value
int sum = 0;
while (n > 0) {
sum += n % 10; // add the last digit
n /= 10; // drop it with integer division
}
printf("%d\n", sum);
return 0;
}
Xem lại bài Toán tử và biểu thức.
Bài 10: in tam giác sao
Nhập chiều cao h, in một tam giác vuông bằng dấu sao: dòng thứ i có đúng i dấu sao.
Gợi ý
Vòng ngoài chạy theo từng dòng, vòng trong in số dấu sao bằng chỉ số dòng. Dùng putchar
cho gọn, kết mỗi dòng bằng ký tự xuống dòng.
#include <stdio.h>
int main(void) {
int h;
scanf("%d", &h);
for (int i = 1; i <= h; i++) { // row i has i stars
for (int j = 0; j < i; j++) putchar('*');
putchar('\n');
}
return 0;
}
Xem lại bài Vòng lặp.
Bài 11: đảo ngược một số nguyên
Nhập một số nguyên dương n, in ra số tạo bởi các chữ số của n viết theo thứ tự ngược.
Ví dụ 1234 cho 4321.
Gợi ý
Mỗi bước lấy chữ số cuối n % 10 và ghép vào kết quả theo công thức rev = rev * 10 + n % 10,
rồi bỏ chữ số đó với n /= 10. Lặp tới khi n bằng 0.
#include <stdio.h>
int main(void) {
int n;
scanf("%d", &n);
int rev = 0;
while (n > 0) {
rev = rev * 10 + n % 10; // append the last digit
n /= 10;
}
printf("%d\n", rev);
return 0;
}
Xem lại bài Vòng lặp.
Bài 12: tìm số nhỏ nhất trong ba số
Nhập ba số nguyên, in ra số nhỏ nhất trong ba số đó.
Gợi ý
Khởi tạo biến min bằng số đầu tiên (không phải 0, vì cả ba số có thể đều âm), rồi lần
lượt so sánh với hai số còn lại và cập nhật khi gặp số nhỏ hơn.
#include <stdio.h>
int main(void) {
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
int min = a; // start from the first value, not 0
if (b < min) min = b;
if (c < min) min = c;
printf("%d\n", min);
return 0;
}
Xem lại bài Rẽ nhánh.
Câu hỏi tự kiểm
- 1Trong scanf, muốn đọc đúng một giá trị kiểu double thì dùng định dạng nào?
- 2Hằng số 012 viết trong mã C có giá trị thập phân là bao nhiêu?
- 3Với hai biến kiểu int, biểu thức 7 / 2 cho kết quả gì?
- 4Phát biểu nào đúng về tràn số trong C?