Skip to content

Buổi 2 – C# Console: Ép kiểu, I/O, Cấu trúc điều khiển, Vòng lặp, Mảng (bản chi tiết)

  • by

Thời lượng: 120′  |  Cấu trúc: 50% Lý thuyết – 50% Thực hành  |  Công cụ: VS Code + .NET SDK

I) Mục tiêu học tập

  • Hiểu rõ value type vs reference type, vùng nhớ stack/heap, truyền tham trị/tham chiếu.
  • Nắm vững ép kiểu (ngầm định/tường minh), Convert, Parse/TryParse và các lỗi phổ biến.
  • Viết được I/O console: Write/WriteLine, ReadLine, kiểm tra và làm sạch dữ liệu đầu vào.
  • Áp dụng thành thạo if/else, switch (kể cả pattern matching cơ bản).
  • Thực hành for, while, do..while, foreach trong các bài toán thực tế.
  • Làm việc với mảng 1 chiều: tạo, duyệt, tìm kiếm, tổng hợp (sum/min/max/avg).

II) Lý thuyết chi tiết (≈60′)

1) Value type vs Reference type, Stack vs Heap

Value types (lưu giá trị trực tiếp, thường trên stack): bool, byte, short, int, long, float, double, decimal, char, struct, enum.

Reference types (lưu tham chiếu tới đối tượng trên heap): string, object, array, class, interface, delegate.

// Value: sao chép giá trị
int a = 10;
int b = a;   // b = 10, thay đổi b không ảnh hưởng a
b++;
Console.WriteLine($"{a}, {b}"); // 10, 11

// Reference: sao chép tham chiếu (cùng trỏ 1 vùng heap)
int[] x = {1,2,3};
int[] y = x;
y[0] = 100;
Console.WriteLine(x[0]); // 100
  • Stack: cấp phát/thu hồi nhanh, dùng cho biến cục bộ/value type.
  • Heap: lưu đối tượng reference; GC (garbage collector) thu hồi khi không còn tham chiếu.

2) Ép kiểu & chuyển đổi

  • Widening (ngầm định): an toàn (ví dụ int → long → double).
  • Narrowing (tường minh): có thể mất dữ liệu (cần cast).
// Widening
int iv = 100;
double dv = iv;   // OK

// Narrowing
double d = 9.8;
int i = (int)d;   // 9 (mất phần thập phân)

// Convert/Parse/TryParse
string s = "123";
int n1 = Convert.ToInt32(s);  // an toàn hơn cast từ string
int n2 = int.Parse(s);        // ném lỗi nếu s không hợp lệ

if (int.TryParse("abc", out int n3))
  Console.WriteLine(n3);
else
  Console.WriteLine("Không phải số hợp lệ");

Khuyến nghị: dùng TryParse cho input người dùng; dùng decimal cho tiền tệ để giảm sai số nhị phân.

3) Thứ tự ưu tiên toán tử (Operator precedence)

  • Nhân/Chia/Phần trăm (×, ÷, %) ưu tiên hơn Cộng/Trừ.
  • Dùng ngoặc () để rõ ràng và đúng ý đồ.
int r1 = 2 + 3 * 4;      // 14
int r2 = (2 + 3) * 4;    // 20
bool b = 3 + 2 * 2 == 7; // true

4) I/O console & làm sạch dữ liệu

Console.Write("Nhập tuổi: ");
string raw = Console.ReadLine()?.Trim();
if (!int.TryParse(raw, out int age) || age < 0) {
  Console.WriteLine("Tuổi không hợp lệ!");
} else {
  Console.WriteLine($"Bạn {age} tuổi.");
}

5) Cấu trúc điều khiển: if/else, switch

double avg = 8.2;
if (avg >= 8.5) Console.WriteLine("Giỏi");
else if (avg >= 7.0) Console.WriteLine("Khá");
else Console.WriteLine("Trung bình");

// switch truyền thống
int day = 5;
switch (day) {
  case 1: Console.WriteLine("Mon"); break;
  case 2: Console.WriteLine("Tue"); break;
  default: Console.WriteLine("Other"); break;
}

// switch expression (pattern matching cơ bản)
string level = avg switch {
  >= 8.5 => "A",
  >= 7.0 => "B",
  _      => "C"
};
Console.WriteLine(level);

Ghi nhớ: C# không “fall‑through” như C/C++; mỗi case nên kết thúc bằng break (hoặc trả về/throw).

6) Vòng lặp: for, while, do..while, foreach

for (int k = 1; k <= 5; k++) Console.Write($"{k} ");   // 1 2 3 4 5

int w = 3;
while (w > 0) { Console.Write(w--); }                 // 321

int d2 = 0;
do { Console.Write(d2++); } while (d2 < 3);           // 012

int[] arr = {1, 2, 3};
foreach (var v in arr) Console.WriteLine(v);          // 1 2 3

7) Mảng 1 chiều

int[] a = {3, 7, 2, 9, 5};
Console.WriteLine(a.Length);

int sum = 0, min = a[0], max = a[0];
foreach (var v in a) {
  sum += v;
  if (v < min) min = v;
  if (v > max) max = v;
}
double avg2 = (double)sum / a.Length;
Console.WriteLine($"Sum={sum}, Min={min}, Max={max}, Avg={avg2:F2}");

III) Thực hành theo bước (≈60′)

Lab 1 – I/O & ép kiểu an toàn (10′)

Nhập subtotal (decimal), tính VAT 8% và tổng tiền (định dạng 2 chữ số thập phân).

Console.Write("Subtotal: ");
if (!decimal.TryParse(Console.ReadLine(), out decimal sub) || sub < 0) {
  Console.WriteLine("Giá trị không hợp lệ!"); return;
}
const decimal VAT = 0.08m;
decimal total = sub + sub * VAT;
Console.WriteLine($"Total = {total:F2}");

Lab 2 – Điều kiện & kiểm tra biên (15′)

Nhập điểm (0..100) → in xếp loại: A (≥85), B (70..84), C (<70). Nếu ngoài khoảng, báo lỗi.Gợi ý/Đáp án

Console.Write("Điểm: ");
if (!int.TryParse(Console.ReadLine(), out int s) || s < 0 || s > 100) {
  Console.WriteLine("Điểm không hợp lệ"); return;
}
string grade = s switch { >= 85 => "A", >= 70 => "B", _ => "C" };
Console.WriteLine($"Xếp loại: {grade}");

Lab 3 – Vòng lặp ứng dụng (20′)

  1. Bảng cửu chương: nhập n (2..9) → in n x 1..10.
  2. Tổng 1..N: tính bằng for và bằng công thức N*(N+1)/2.
  3. Đếm chữ số: nhập số nguyên dương, đếm số chữ số bằng while.

Gợi ý nhanh

// 1) Cửu chương
Console.Write("n = ");
int n = int.Parse(Console.ReadLine());
for (int i = 1; i <= 10; i++) Console.WriteLine($"{n} x {i} = {n*i}");

// 2) Tổng 1..N
Console.Write("N = ");
int N = int.Parse(Console.ReadLine());
long sumLoop = 0; for (int i = 1; i <= N; i++) sumLoop += i;
long sumFormula = (long)N*(N+1)/2;
Console.WriteLine($"Loop={sumLoop}, Formula={sumFormula}");

// 3) Đếm chữ số
Console.Write("Số dương: ");
int x = int.Parse(Console.ReadLine());
int cnt = 0; do { cnt++; x/=10; } while (x > 0);
Console.WriteLine($"Số chữ số: {cnt}");

Lab 4 – Mảng 1 chiều & truy vấn dữ liệu (15′)

Nhập mảng số nguyên (cách nhau bởi dấu cách), in sum/min/max/avg; kiểm tra một giá trị có thuộc mảng không.Đáp án mẫu

using System;
using System.Linq;

Console.Write("Nhập mảng: ");
int[] arr = Console.ReadLine()
  .Split(' ', StringSplitOptions.RemoveEmptyEntries)
  .Select(int.Parse)
  .ToArray();

int sum = 0, min = arr[0], max = arr[0];
foreach (var v in arr) { sum += v; if (v < min) min = v; if (v > max) max = v; }
double avg = (double)sum / arr.Length;
Console.WriteLine($"Sum={sum}, Min={min}, Max={max}, Avg={avg:F2}");

Console.Write("Tìm giá trị: ");
int target = int.Parse(Console.ReadLine());
bool found = arr.Contains(target);
Console.WriteLine(found ? "Có trong mảng" : "Không có");

IV) Quiz nhanh (5 câu)

  1. Khác nhau giữa int.Parseint.TryParse? Khi nào dùng cái nào?
  2. Cho ví dụ cần narrowing cast và rủi ro kèm theo.
  3. Điểm khác giữa whiledo..while (thứ tự kiểm tra điều kiện)?
  4. Vì sao nên dùng decimal cho tiền tệ thay vì double?
  5. foreach tiện ở chỗ nào so với for khi duyệt mảng?

V) Bài tập về nhà

  • Số nguyên tố: viết hàm kiểm tra và in tất cả số nguyên tố ≤ N (dùng vòng lặp).
  • Thống kê mảng số thực: nhập mảng, in medianstandard deviation (gợi ý: sắp xếp + công thức σ).
  • Tối ưu vòng lặp: benchmark tổng 1..N bằng vòng lặp vs công thức (thử N lớn), so sánh thời gian.

VI) Ghi chú cho giảng viên

  • Nhấn mạnh lỗi phổ biến: Parse fail, IndexOutOfRangeException, nhầm float/double/decimal, quên Trim() input.
  • Lớp nhanh: thêm mảng 2D (bảng điểm) và switch nâng cao (pattern matching với when).
  • Khuyến khích sinh viên dùng TryParse cho mọi input từ người dùng.

Leave a Reply

Your email address will not be published. Required fields are marked *