Đề Lý thuyết số 1: Đề thi 2024 - 2025
Câu 1.
Cho đoạn chương trình sau:
#include <iostream>
using namespace std;
int main() {
int a = 15 % 6;
int b = (a++) + 2;
int c = (a > b ? a - b : b - a);
int d = 2 + (c >= 3);
cout << a << b << c << d;
return 0;
}
Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Sau khi thực hiện chương trình, kết quả in ra màn hình là 4 5 1 2
Giải thích:
Câu lệnh: int a = 15 % 6;
Câu lệnh: int b = (a++) + 2;
- Xét câu lệnh này có xuất hiện toán tử tăng sau () nên:
- và
Câu lệnh: int c = (a > b ? a - b : b - a);
- Thay giá trị vào:
- Vì là Sai, biểu thức trả về giá trị sau dấu : là
- Vậy
Câu lệnh: int d = 2 + (c >= 3);
- Biểu thức so sánh hay trả về giá trị False (trong C++ tương ứng với số 0).
- Vậy
Câu 2.
Cho một đoạn chương trình sau:
#include <iostream>
using namespace std;
int main() {
int x = 1, y = 0;
if (!y || (x++))
cout << x - y;
else
cout << y - x;
return 0;
}
Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Sau khi thực hiện chương trình, kết quả in ra màn hình là: 1
Giải thích:
Xét điều kiện trong câu lệnh if (!y || (x++)):
- Ban đầu ta có , do đó biểu thức (phủ định của 0) sẽ tương đương với
!false, kết quả là1. - Trong toán tử logic OR (
||), nếu điều kiện thứ nhất đã đúng (true) thì toàn bộ mệnh đề được kết luận là đúng không cần xét điều kiện thứ hai.
Do đó, giá trị của biến vẫn giữ nguyên là 1.
Vì điều kiện if đúng, chương trình thực hiện lệnh: cout << x - y;.
Với và , phép tính sẽ là: .
Câu 3.
Cho một đoạn chương trình sau:
#include <iostream>
using namespace std;
int main() {
int x = 13, y = 4;
switch (x % y) {
case 0: y--;
case 1: x -= y;
case 2: y /= 2;
case 3: x %= 3;
}
cout << y << x;
return 0;
}
Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Sau khi thực hiện chương trình, kết quả in ra màn hình là 20
Giải thích:
Khởi tạo: .
Biểu thức switch: .
Chương trình sẽ nhảy vào case 1:
- .
Vì không có lệnh break nên chương trình tiếp tục vào các case tiếp theo:
Nhảy vào case 2:
- .
Tương tự như case 1, không có break nên tiếp tục nhảy vào case 3:
- .
Kết quả cuối cùng:
- Giá trị hiện tại là và .
- Lệnh
cout << y << x;sẽ in ra màn hình giá trị của trước, sau đó đến .
Câu 4.
Cho lưu đồ sau, với

Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Sau khi thực hiện chương trình, kết quả in ra màn hình là 10
Giải thích:
Dựa vào lưu đồ, thuật toán thực hiện việc duyệt qua từng chữ số của và biến sẽ cộng dồn giá trị của chữ số đó nếu nó là số lẻ.
Khởi tạo: .
Bước 1: (là số lẻ vì )
Bước 2: (là số chẵn, điều kiện là Sai)
- không đổi ()
Bước 3: (là số lẻ)
Bước 4: (là số chẵn)
- không đổi ()
Bước 5: (là số chẵn)
- không đổi ()
Kết thúc: khiến điều kiện lặp bị Sai. Chương trình thoát lặp và in giá trị của =10.
Câu 5.
Cho một đoạn chương trình sau:
#include <iostream>
using namespace std;
int S = 0, i = 5;
int main() {
while (i > 0 && S < 10) {
S += i;
i++;
}
cout << i << S;
return 0;
}
Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Sau khi thực hiện chương trình, kết quả in ra màn hình là 711
Giải thích:
Dựa vào vòng lặp while với điều kiện :
Khởi tạo: .
Lần 1: Điều kiện là Đúng.
Lần 2: Điều kiện là Đúng.
Lúc này , điều kiện trở thành Sai.
Thoát vòng lặp.Chương trình thực hiện lệnh cout << i << S;. In ra giá trị và viết liền nhau là 711.
Câu 6.
Cho một đoạn chương trình sau:
#include <iostream>
using namespace std;
int main() {
int n = 3085, t = 0;
do {
n = n / 10;
if (n % 10 % 2) continue;
t += n % 10;
} while (n);
cout << t;
return 0;
}
Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Sau khi thực hiện chương trình, kết quả in ra màn hình là 8
Giải thích:
Dựa vào vòng lặp do-while:
Khởi tạo: .
Lần 1:
- Xét điều kiện
if (n % 10 % 2)(False). - Nhảy đến lệnh tiếp theo: .
Lần 2:
- Xét điều kiện
if(False). - Nhảy đến lệnh tiếp theo: .
Lần 3:
- Xét điều kiện
if(True). - Thực hiện lệnh
continue(bỏ qua các lệnh còn lại trong vòng lặp, quay lại kiểm tra điều kiệnwhile).
Lần 4:
- Xét điều kiện
if(False). - Thực hiện lệnh tiếp theo: .
Kết thúc: nên điều kiện vòng lặp while(n) bị sai và thoát.
Câu 7.
Cho một đoạn chương trình sau:
#include <iostream>
using namespace std;
void fun(int &a, int b) {
a = --b; // a=4, b=4
b %= 2; // b=0
}
int main() {
int a = 5, b = 10;
fun(b, a);
cout << a << b;
return 0;
}
Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Sau khi thực hiện chương trình, kết quả in ra màn hình là 54
Giải thích:
Phân tích hàm fun(int &a, int b):
- Tham số thứ nhất
int &alà tham chiếu (reference). - Tham số thứ hai
int blà tham trị (value).
Khi gọi hàm fun(b, a) trong main:
- Biến
bcủamain(giá trị 10) được truyền vào tham số&a(tham chiếu). Do đó, mọi sự thay đổi trênatrong hàmfunthực chất là thay đổi biếnbcủamain. - Biến
acủamain(giá trị 5) được truyền vào tham sốb(tham trị). Giá trị được copy sang một vùng nhớ khác, nên thay đổibtrong hàmfunkhông ảnh hưởng đếnacủamain.
Trong hàm fun thực thi:
Ban đầu: &a (chiếu tới b_main = 10), b_fun = 5.
Câu lệnh a = --b;:
--b(tiền tố): giảmb_funxuống 1 đơn vị .- Gán giá trị này cho
a:a = 4. Vìalà tham chiếu củab_mainnên lúc nàyb_main= 4.
Câu lệnhb %= 2;: làm cho b_fun = 4 % 2 = 0 (không ảnh hưởng đến main).
Khi quay lại hàm main:
- Biến
acủamainvẫn giữ nguyên giá trị ban đầu là 5. - Biến
bcủamainđã bị thay đổi thông qua tham chiếu trong hàmfun, giá trị mới là 4. - Lệnh
cout << a << b;in ra hai giá trị viết liền nhau là 54.
Câu 8.
Cho một đoạn chương trình sau:
#include <iostream>
using namespace std;
int fun(int n) {
if (n == 0) return 0;
return ((n % 10 % 7) ? 1 : n % 10) + fun(n / 10);
}
int main() {
cout << fun(731);
return 0;
}
Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Sau khi thực hiện chương trình, kết quả in ra màn hình là 9
Giải thích:
Trong quá trình gọi hàm đệ quy fun(n), ta có câu lệnh chủ chốt:
return ((n % 10 % 7) ? 1 : n % 10) + fun(n / 10);
Ý nghĩa:
- Nếu chữ số cuối cùng () chia cho 7 có dư (không chia hết cho 7), biểu thức điều kiện trả về 1.
- Nếu chữ số cuối cùng chia hết cho 7 (dư 0), biểu thức điều kiện trả về chính chữ số đó ().
- Sau đó cộng dồn với giá trị của hàm gọi đệ quy cho các chữ số phía trước (
fun(n / 10)).
Quá trình thực thi cụ thể:
fun(731):
- Chữ số cuối là 1. (khác 0) Trả về 1.
- Biểu thức:
fun(73):
- Chữ số cuối là 3. (khác 0) Trả về 1.
- Biểu thức:
fun(7):
- Chữ số cuối là 7. (chia hết cho 7) Trả về chính nó là 7.
- Biểu thức:
fun(0):
- Thỏa mãn điều kiện dừng
if (n == 0), trả về 0.
Tính ngược lại:
Câu 9.
Cho một đoạn chương trình sau:
#include <iostream>
using namespace std;
void fun(int a[], int &n, int k) {
for (int i = k; i < n - 1; i++)
a[i] = a[i + 1];
n--;
}
int out(int a[], int n) {
int S = 0;
for (int i = 0; i < n; i++)
S += a[i];
return S;
}
int main() {
int a[5] = {1, 2, 7, 0, 3};
int n = 5;
fun(a, n, 3);
cout << out(a, n);
return 0;
}
Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Sau khi thực hiện chương trình, kết quả in ra màn hình là 13
Giải thích:
Chương trình thực hiện việc xóa một phần tử tại vị trí trong mảng và tính tổng các phần tử còn lại.
Khởi tạo: Mảng với .
Gọi hàm fun(a, n, 3) (Xóa phần tử tại chỉ số ):
- Tham số
&nđược truyền theo tham chiếu, nên giá trị trongmainsẽ bị thay đổi trực tiếp.
Vòng lặp for ():
- Khi : .
- Mảng lúc này trở thành: .
Kết thúc vòng lặp: Thực hiện n-- .
Gọi hàm out(a, n) với :
- Hàm này tính tổng các phần tử từ đến .
- .
Câu 10.
Cho một đoạn chương trình sau:
#include <iostream>
using namespace std;
int fun(int a[][3], int n) {
int t = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (a[i][j])
t++;
return t;
}
int main() {
int a[3][3] = {{1, 0, 3}, {0, 3, 1}, {3, 2, 0}};
cout << fun(a, 3);
return 0;
}
Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Sau khi thực hiện chương trình, kết quả in ra màn hình là 6
Giải thích:
Mục đích của hàm fun:
Hàm này sử dụng hai vòng lặp lồng nhau để duyệt qua tất cả các phần tử của mảng 2 chiều. Điều kiện if (a[i][j]) tương đương với việc kiểm tra xem giá trị tại ô đó có khác 0 hay không. Nếu khác 0, biến đếm t sẽ tăng lên 1.
Phân tích mảng a[3][3]:
- Hàng 0:
{1, 0, 3}Có 2 phần tử khác 0 (là 1 và 3). - Hàng 1:
{0, 3, 1}Có 2 phần tử khác 0 (là 3 và 1). - Hàng 2:
{3, 2, 0}Có 2 phần tử khác 0 (là 3 và 2).
Tổng cộng có phần tử thỏa mãn điều kiện khác 0.
Câu 11.
Cho chương trình sau:
#include <iostream>
using namespace std;
void f(int &p1, int p2)
{
p1++;
p2++;
}
int main()
{
int x1 = 1;
int x2 = 1;
f(x1, x2);
cout << "x1 is " << x1 << " x2 is " << x2;
return 0;
}
Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Kết quả của chương trình này là: x1 is 2 x2 is 1
Giải thích:
Hàm f(int &p1, int p2):
int &p1: Là tham số truyền theo tham chiếu. Khi hàm thực hiệnp1++, nó tác động trực tiếp lên vùng nhớ của biến được truyền vào (làx1).int p2: Là tham số truyền theo tham trị. Khi gọi hàm, một bản sao của giá trị được tạo ra. Lệnhp2++chỉ làm tăng giá trị của bản sao này bên trong hàm, không ảnh hưởng đến biến gốc (x2).
Quá trình thực thi trong main:
- Khởi tạo .
- Gọi hàm
f(x1, x2):p1trỏ đếnx1x1tăng lên thành 2.p2nhận giá trị copy củax2(là 1)p2tăng lên 2, nhưngx2vẫn là 1.
Câu 12.
Cho một đoạn chương trình sau:
#include <iostream>
using namespace std;
int main() {
int n = 10;
int *p1 = &n;
int *p2 = p1;
p1 = new int(50);
n--;
cout << (*p1) << (*p2);
return 0;
}
Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Sau khi thực hiện chương trình, kết quả in ra màn hình là 509
Giải thích:
Chương trình thực hiện các thao tác quản lý bộ nhớ và con trỏ như sau:
Khởi tạo ban đầu:
int n = 10;: Biếnnmang giá trị 10.int *p1 = &n;: Con trỏp1trỏ đến địa chỉ của biếnn.int *p2 = p1;: Con trỏp2cũng trỏ đến địa chỉ màp1đang trỏ (tức là cùng trỏ vào biếnn).
Thay đổi địa chỉ con trỏ:
-
p1 = new int(50);: Lệnhnewcấp phát một vùng nhớ mới trên Heap mang giá trị 50 và chop1trỏ vào đó. -
Lưu ý: Lúc này
p1không còn trỏ vàonnữa, nhưngp2thì vẫn trỏ vào biếnnở vùng nhớ Stack.
Thay đổi giá trị biến:
n--;: Giá trị của biếnngiảm xuống 1 (từ 10 còn 9).- Vì
p2đang trỏ vàonnên*p2lúc này sẽ bằng 9.
Kết quả in ra:
*p1: Giá trị tại vùng nhớ mới là 50.*p2: Giá trị của biếnnsau khi giảm là 9.
Câu 13.
Cho một đoạn chương trình sau:
#include <iostream>
using namespace std;
void fun(int* a, int* b) {
int temp = *b;
*b = *a;
*a = temp;
}
int main() {
int* p1 = new int(5);
int* p2 = new int(7);
fun(p1, p2);
cout << *p1 << " " << *p2;
return 0;
}
Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Sau khi thực hiện chương trình, kết quả in ra màn hình là 7 5
Giải thích:
Chương trình sử dụng hàm để hoán đổi (swap) giá trị của hai vùng nhớ mà con trỏ đang trỏ tới:
Khởi tạo:
p1trỏ tới vùng nhớ có giá trị 5.p2trỏ tới vùng nhớ có giá trị 7.
Gọi hàm fun(p1, p2):
- Tham số
anhận địa chỉ củap1, tham sốbnhận địa chỉ củap2. int temp = *b;: Biến tạmtemplưu giá trị tại địa chỉb(giá trị là 7).*b = *a;: Gán giá trị tại địa chỉa(là 5) vào địa chỉb. Lúc này vùng nhớ củap2mang giá trị 5.*a = temp;: Gán giá trị củatemp(là 7) vào địa chỉa. Lúc này vùng nhớ củap1mang giá trị 7.
Kết quả:
- Sau khi hàm kết thúc, giá trị tại hai vùng nhớ đã được tráo đổi cho nhau.
- Lệnh
cout << *p1 << " " << *p2;sẽ in ra giá trị mới là 7 5.
Câu 14.
Cho một đoạn chương trình sau:
#include <iostream>
using namespace std;
struct Account {
int id;
char type;
};
int main() {
Account Arr[3] = {{10, 'A'}, {20, 'B'}, {30, 'C'}};
Account* x = Arr;
Account* y = x + 2;
cout << x->type;
cout << (y->id) - (x->id);
return 0;
}
Sau khi thực hiện chương trình, kết quả in ra màn hình là gì?
Lời giải:
Sau khi thực hiện chương trình, kết quả in ra màn hình là A20
Giải thích:
Chương trình thực hiện thao tác trên mảng các cấu trúc thông qua con trỏ:
Khởi tạo mảng: Mảng Arr gồm 3 phần tử kiểu Account:
Arr[0] = {id: 10, type: 'A'}Arr[1] = {id: 20, type: 'B'}Arr[2] = {id: 30, type: 'C'}
Thiết lập con trỏ:
Account* x = Arr;: Con trỏxtrỏ đến phần tử đầu tiên của mảng (Arr[0]).Account* y = x + 2;: Dịch chuyển con trỏ đi 2 đơn vị cấu trúc, do đóytrỏ đến phần tử thứ ba của mảng (Arr[2]).
Thực thi các lệnh in:
cout << x->type;: Truy cập thành phầntypecủa phần tử màxđang trỏ tới (Arr[0]). Kết quả in ra là ký tự A.cout << (y->id) - (x->id);:y->idlà giá trịidcủaArr[2], bằng 30.x->idlà giá trịidcủaArr[0], bằng 10.- Phép toán: . Kết quả in ra là số 20.
Câu 15. Mô tả bài toán:
Viết chương trình quản lý danh sách các tài khoản User gồm ID (số nguyên), Pass (chuỗi) và thực hiện các yêu cầu sau:
- Khai báo kiểu dữ liệu cấu trúc User.
- Nhập thông tin cho User.
- Hãy cho biết pass nào KHÔNG hợp lệ trong danh sách. Biết rằng Pass chỉ hợp lệ khi thỏa mãn tất cả điều kiện sau:
- Pass phải có trên 5 ký tự.
- Pass phải có chữ cái, chữ số và ký tự đặc biệt (Ký tự đặc biệt là các ký tự
! @ # $).
Input
- Nhập số lượng User trong mảng
Arr. - dòng tiếp theo, mỗi dòng là thông tin của một User.
Output
- Xuất ra các Pass KHÔNG hợp lệ trong
Arr. - Nếu tất cả các Pass đều hợp lệ thì xuất ra
NoFound.
Gợi ý:
- Khai báo kiểu dữ liệu cấu trúc User
struct User{
int ID;
string Pass;
};
- Nhập thông tin cho User.
struct NUser{
int n;
User *p;};
void Nhapthongtin(User &A){
cin>>A.ID>>A.Pass;
}
NUser Nhap(){
NUser ds;
cin>>ds.n;
ds.p=new User[ds.n];
for(int i=0;i<ds.n;i++){
Nhapthongtin(ds.p[i]);}
return ds;
}
- Hãy cho biết pass nào KHÔNG hợp lệ trong danh sách. Biết rằng Pass chỉ hợp lệ khi thỏa mãn tất cả điều kiện sau:
- Pass phải có trên 5 ký tự.
- Pass phải có chữ cái, chữ số và ký tự đặc biệt (Ký tự đặc biệt là các ký tự
! @ # $).
bool Check(User a){
bool len=false,alpha=false,digit=false,special=false;
if(a.Pass.length()>5) len=true;
for(char x:a.Pass){
if((x>='A' && x<='Z') || (x>='a' && x<='z')) alpha=true;
if(x>='0' && x<='9') digit=true;
if(x=='!' ||x=='@' || x=='#' ||x=='$') special=true;
}
if(len && alpha && digit && special) return 1;
return 0;
}
void Xuatthongtin(User a){
cout<<a.ID<<" "<<a.Pass<<endl;}
int main(){
bool ktr=0;
NUser ds;
ds=Nhap();
for(int i=0;i<ds.n;i++){
if(!Check(ds.p[i])){
Xuatthongtin(ds.p[i]);
ktr=1;
}
}
if(!ktr) cout<<"NoFound";
return 0;}
Câu 16. Mô tả bài toán:
Viết chương trình cho phép người dùng liên tục nhập vào các số nguyên. Việc nhập chỉ DỪNG khi nhập số 0 (không tính số 0 vào dãy số nguyên) và xuất ra màn hình số nguyên có giá trị lớn thứ hai và nhỏ thứ 2 trong dãy số nguyên đã nhập.
| Input | Output |
|---|---|
| 50920 25923 159223 0 | 50920 50920 |
| 12 9220 120000 653 0 | 9220 653 |
(Lưu ý không sử dụng các cấu trúc mảng, tập hợp để giải quyết bài toán, cũng như không được sử dụng các từ khóa này trong bài làm: vector, set, map, [, ], INT_MAX, INT_MIN)
Gợi ý
Vì không được dùng mảng ([ ]) hay các thư viện tập hợp, bạn cần dùng 4 biến riêng biệt để lưu trữ giá trị:
max1,max2: Lớn nhất và lớn thứ hai.min1,min2: Nhỏ nhất và nhỏ thứ hai.
Cách xử lý:
- Khởi tạo các biến bằng giá trị của số đầu tiên nhập vào.
- Với mỗi số tiếp theo, so sánh để cập nhật thứ tự:
- Nếu : , .
- Nếu và : .
- Tương tự với logic tìm
min.
#include<iostream>
using namespace std;
int main(){
int n;
int Max1=-10e9;//Lấy giá trị int bé nhất
int Max2=-10e9;
int Min1=10e9;//lấy giá trị int lớn nhất
int Min2=10e9;
cin>>n;
while(n>0){
if(n>Max1){
Max2=Max1;
Max1=n;
}
else if(n<Max1 && n>Max2){
Max2=n;
}
if(n<Min1){
Min2=Min1;
Min1=n;
}
else if(n>Min1 && n<Min2){
Min2=n;
}
cin>>n;
}
cout<<Max2<<"\n";
cout<<Min2;
return 0;