Tất cả câu hỏi

Ngân hàng câu hỏi trắc nghiệm có giải thích chi tiết.

120/11.033 câuCòn 10.913
ARead data from the file.
BPrint to the screen.
CRead data from the keyboard.
DOpen a file.
EPrint to file.
Lời giải
Đáp án đúng: "Read data from the file." Hàm fscanf là bản mở rộng của scanf: tham số đầu là con trỏ tệp chỉ luồng nguồn, sau đó là chuỗi định dạng và danh sách địa chỉ biến; hàm đọc văn bản trong tệp, chuyển theo đặc tả rồi nạp vào các biến, và trả về số mục chuyển đổi thành công. Mô tả "Print to the screen." là việc của printf, in ra luồng ra chuẩn. Mô tả "Read data from the keyboard." là việc của scanf, tức fscanf với luồng stdin; bàn phím chỉ là một trường hợp riêng, còn fscanf nói chung đọc từ luồng được truyền vào. Mô tả "Open a file." là việc của fopen, hàm tạo ra con trỏ tệp mà fscanf cần. Mô tả "Print to file." là việc của fprintf, đi hướng ngược lại: lấy giá trị trong bộ nhớ, ghi thành văn bản vào tệp.
Mở trang câu hỏi này →
Đề bài
int n;
char c;
scanf("%d", &n);
c = getchar();
printf("%d",c);
A10
B20
C0
DUndefined
Lời giải
Đáp án đúng: "10". Khi người dùng gõ 20 rồi nhấn phím xuống dòng, vùng đệm của luồng vào chuẩn chứa hai chữ số và một ký tự xuống dòng. Đặc tả %d đọc hai chữ số rồi dừng ngay khi gặp ký tự không phải chữ số, và bỏ lại ký tự xuống dòng trong đệm. Lệnh getchar kế đó lấy đúng ký tự còn lại ấy, tức ký tự xuống dòng, mã ASCII bằng 10; in nó bằng %d nên màn hình hiện 10. Số "20" là giá trị của n, nhưng printf in biến c chứ không in n, và c chỉ giữ được một ký tự. Số "0" ứng với byte rỗng, thứ không có trong dòng người dùng gõ. Kết luận "Undefined" sai vì luồng vào chuẩn có vùng đệm nên ký tự xuống dòng còn nguyên ở đó, kết quả hoàn toàn đoán được; đây cũng là lý do phải dọn đệm trước khi đọc ký tự.
Mở trang câu hỏi này →
Agetchar() , scanf()
Bgetchar() , fgets()
Cscanf() , fgetc()
Dfgets() , fgetc()
Lời giải
Đáp án đúng: "getchar() , scanf()". Hai hàm này làm việc thẳng trên luồng vào chuẩn mà không cần ai chỉ luồng cho chúng, và luồng vào chuẩn mặc định có vùng đệm: ký tự người dùng gõ nằm lại trong đệm cho tới khi được đọc, nên scanf đọc xong vẫn để lại phần chưa dùng, kể cả dấu xuống dòng, cho lần getchar sau. Cặp "getchar() , fgets()" lẫn một hàm cần đối số luồng, vì fgets đòi con trỏ tệp nên không gắn riêng với vào chuẩn, muốn đọc bàn phím phải truyền stdin vào. Cặp "scanf() , fgetc()" cũng vậy, fgetc nhận luồng làm đối số và dùng được cho tệp bất kỳ. Cặp "fgets() , fgetc()" gồm hai hàm đều mang đối số luồng, nên nó mô tả vào ra tệp tổng quát chứ không phải tiện ích đọc sẵn trên luồng vào chuẩn.
Mở trang câu hỏi này →
104What will be the result of the following C code?4 lựa chọncó code
Đề bài
char str1[20] = "Hello";
char str2[20] = "World";
strcat(str1, str2);
printf("%s", str1);
AHelloWorld
BHello World
CWorldHello
DWorld Hello
Lời giải
Đáp án đúng: "HelloWorld". Hàm strcat tìm byte rỗng kết thúc của chuỗi đích rồi chép chuỗi nguồn vào từ đúng chỗ đó, kèm một byte kết thúc mới; nó không tự chèn dấu cách và cũng không đổi thứ tự. Vậy str1 vốn là Hello được nối thêm World ngay sau chữ cuối, cho HelloWorld dài mười ký tự, vẫn vừa trong mảng hai mươi ô nên không tràn. Chuỗi "Hello World" đòi một dấu cách ở giữa, muốn có thì phải nối thêm một chuỗi chứa dấu cách trước khi nối từ thứ hai. Chuỗi "WorldHello" đảo vai hai chuỗi: strcat luôn ghi vào tham số đầu, nên muốn kết quả đó phải gọi với str2 làm đích. Chuỗi "World Hello" vừa đảo vai vừa thêm dấu cách, không khớp điều gì trong lời gọi.
Mở trang câu hỏi này →
AIncrements
BSquare root
CDivision
DMultiplication
Lời giải
Đáp án đúng: "Increments". Con trỏ có số học riêng, định nghĩa trên phép cộng và trừ với số nguyên: tăng con trỏ một đơn vị là nhảy sang phần tử kế tiếp, tức địa chỉ cộng thêm đúng kích thước kiểu được trỏ, nên p++ là lối duyệt mảng rất thông dụng. Ngoài ra chỉ phép trừ hai con trỏ cùng kiểu là hợp lệ, cho khoảng cách theo số phần tử. Phép "Square root" trước hết không phải toán tử mà là hàm sqrt của thư viện toán, và nó nhận số thực chứ không nhận địa chỉ. Phép "Division" không có nghĩa với địa chỉ: chia một vị trí trong bộ nhớ cho một số không sinh ra vị trí nào có ý nghĩa, nên chuẩn C không định nghĩa nó cho con trỏ. Phép "Multiplication" cũng vậy, nhân địa chỉ lên nhiều lần cho ra một số nằm ngoài mọi vùng nhớ hợp lệ, trình dịch từ chối thẳng.
Mở trang câu hỏi này →
Aint *p;
Bint p*;
Cint +p;
Dint $p;
Lời giải
Đáp án đúng: "int *p;". Khai báo trong C đọc theo lối dùng là gì: dấu sao đứng trước tên nói rằng *p là một int, suy ra p là con trỏ tới int. Vì thế dấu sao thuộc về bộ phận khai báo của tên, viết int *p; hay int* p; đều cùng nghĩa, miễn nó đứng trước tên biến. Dòng "int p*;" đặt dấu sao sau tên, cú pháp không có dạng này nên trình dịch báo lỗi ngay; hậu tố trong khai báo chỉ dành cho ngoặc vuông của mảng và ngoặc tròn của hàm. Dòng "int +p;" dùng dấu cộng, thứ chỉ là toán tử trong biểu thức chứ không phải bộ phận khai báo, nên không tạo được con trỏ. Dòng "int $p;" dùng ký tự không thuộc tập cho phép của tên định danh; tên chỉ gồm chữ cái, chữ số và dấu gạch dưới, nên dòng này sai ngay ở bước tách từ.
Mở trang câu hỏi này →
Đề bài
int a[] = {1,2,3,4};
int i=0, s=0;
for (; a[i]; ++i)
    s += a[i];
printf("%d", s);
A10
BCompiler error
CRuntime error
DGarbage value
Lời giải
Đáp án đúng: "10". Vòng for bỏ trống phần khởi tạo vì i đã bằng 0 từ trước, và dùng chính a[i] làm điều kiện: C coi mọi số khác không là đúng, nên vòng còn chạy khi phần tử hiện tại khác 0. Bốn phần tử 1, 2, 3, 4 đều khác không nên s cộng dồn thành 10, rồi i lên 4. Cần nói rõ một điểm yếu của đề: mảng chỉ có bốn ô, nên lần đọc a[4] đã ra ngoài biên và theo chuẩn là hành vi không xác định; đề ngầm giả định ô kề đó bằng 0 để vòng dừng, và với giả định ấy printf in 10. Kết luận "Compiler error" sai vì cú pháp hợp lệ, phần khởi tạo của for được phép để trống. Kết luận "Runtime error" không bắt buộc xảy ra vì đọc một ô ngay sau mảng trên ngăn xếp thường không bị hệ điều hành chặn. Kết luận "Garbage value" chỉ xảy ra nếu ô ngoài biên khác 0, và khi đó tổng sẽ lớn hơn 10.
Mở trang câu hỏi này →
AThe program compiles and runs without any errors, but the behavior is undefined
BThe program compiles and runs without any errors, and the 11th element is accessed
CThe program fails to compile due to a compilation error
DThe program compiles and runs without any errors, and the 11th element is automatically added to the array
Lời giải
Đáp án đúng: "The program compiles and runs without any errors, but the behavior is undefined". C đổi an toàn lấy tốc độ: chỉ số mảng chỉ là phép cộng địa chỉ rồi lấy giá trị, không kèm mã kiểm biên nào, nên chương trình vẫn dịch xong và vẫn chạy, chỉ là nó đọc ghi vào vùng không thuộc mảng. Chuẩn gọi đó là hành vi không xác định: có thể ra số rác, có thể phá biến khác, có thể gây lỗi truy cập, và kết quả đổi theo máy lẫn trình dịch. Câu "The program compiles and runs without any errors, and the 11th element is accessed" sai vì phần tử thứ mười một không tồn tại, thứ bị chạm tới là ô nhớ kế bên. Câu "The program fails to compile due to a compilation error" sai vì chỉ số thường chỉ biết lúc chạy. Câu "The program compiles and runs without any errors, and the 11th element is automatically added to the array" sai vì mảng trong C có kích thước cố định lúc khai báo.
Mở trang câu hỏi này →
Đề bài
void swap(int *a, int *b) {
    int t = *a;
    *a = *b;
    *b = t;
}

int main() {
    int x = 5, y = 10;
    swap(&x, &y);
    printf("%d %d", x, y);
    return 0;
}
A10 5
B5 10
C0 0
DCompilation error
Lời giải
Đáp án đúng: "10 5". C truyền tham số theo giá trị, nên muốn hàm sửa được biến của nơi gọi thì phải truyền địa chỉ: lời gọi swap(&x, &y) đưa địa chỉ của x và của y vào hai con trỏ. Trong hàm, t giữ bản sao giá trị đầu là 5, rồi ô mà con trỏ thứ nhất trỏ tới nhận 10 nên x thành 10, cuối cùng ô của con trỏ thứ hai nhận t nên y thành 5. Mọi phép ghi đều qua dấu sao, tức ghi thẳng vào ô nhớ gốc, nên sau lời gọi printf in 10 rồi 5. Dãy "5 10" là thứ tự ban đầu, nó xảy ra nếu hàm nhận hai bản sao int thường và chỉ đổi chỗ bản sao. Dãy "0 0" sai vì không có chỗ nào gán 0. Kết luận "Compilation error" sai vì nguyên mẫu nhận con trỏ int, lời gọi truyền đúng địa chỉ, và phép gán qua dấu sao hoàn toàn hợp lệ.
Mở trang câu hỏi này →
Đề bài
#include<stdio.h>
void updatePosition(int *time, float* position, float v)
{
    if ((*position < 5) && (*position > -5))
        *position += v;
    else
        *position += -0.1*(*position);
    time += 1;
}

main()
{
    float p = 4.0, v = 1;
    int t = 0;
    printf("t = %d, p = %f\n", t, p);
    updatePosition(&t, &p, v);
    updatePosition(&t, &p, v);
    printf("t = %d, p = %f\n", t, p);
}

What is the result displayed to the screen?

At = 0, p = 4.000000 t = 2, p = 6.000000
Bt = 0, p = 4.000000 t = 2, p = 5.000000
Ct = 0, p = 4.000000 t = 2, p = 4.500000
Dt = 0, p = 4.000000 t = 2, p = 4.000000
Lời giải
Đáp án đúng: "t = 0, p = 4.000000 t = 2, p = 4.500000". Lần gọi đầu, giá trị trỏ tới nằm giữa -5 và 5 nên p tăng thêm v, thành 5.0. Lần gọi sau, điều kiện nhỏ hơn 5 đã sai vì p đúng bằng 5.0, nên nhánh else chạy: p cộng thêm -0.1 nhân 5.0, tức giảm 0.5 còn 4.5. Phải nói thẳng một khuyết điểm của đề: lệnh time += 1 chỉ dịch bản sao con trỏ trong hàm chứ không ghi qua dấu sao, nên t thật sự vẫn là 0, mà cả bốn lựa chọn đều in t = 2; vì vậy chỉ giá trị của p phân định được, và 4.500000 là con số duy nhất đúng. Dòng "t = 0, p = 4.000000 t = 2, p = 6.000000" coi như cả hai lần gọi đều vào nhánh cộng v. Dòng "t = 0, p = 4.000000 t = 2, p = 5.000000" dừng ở kết quả lần gọi đầu. Dòng "t = 0, p = 4.000000 t = 2, p = 4.000000" coi như lần gọi sau trả p về giá trị cũ.
Mở trang câu hỏi này →
A(condition) ? True_Value : False_Value
Bfor ( InitBlock; Condition; Task2) Task1;
Cdo{ statements;} while (condition) ;
Dwhile (condition){ statements; }
Lời giải

Đáp án đúng: "(condition) ? True_Value : False_Value". Đây là toán tử điều kiện ba toán hạng: nó tính điều kiện rồi cho ra một trong hai giá trị, tức là một biểu thức trả về giá trị, chạy đúng một lần và không có cơ chế quay lại, nên không phải cấu trúc lặp. Dạng "for ( InitBlock; Condition; Task2) Task1; " là for chuẩn với ba phần khởi tạo, điều kiện, cập nhật, còn thân chỉ là một lệnh nên không cần ngoặc nhọn. Dạng "do{ statements;} while (condition) ; " là do while, chạy thân trước rồi mới kiểm điều kiện nên thân luôn chạy ít nhất một lần, và dấu chấm phẩy cuối là bắt buộc. Dạng "

Lời giải
while (condition){
  statements;
}

" là while chuẩn, kiểm điều kiện trước mỗi nhịp. Ba dạng này đều lặp được, chỉ toán tử điều kiện là không.

Mở trang câu hỏi này →
ATo execute a block of codes repeatedly as long as a specified condition is true.
BTo perform mathematical calculations.
CTo define variables within a program.
DTo execute a statement based on a condition
Lời giải
Đáp án đúng: "To execute a block of codes repeatedly as long as a specified condition is true." Vòng lặp trong C gồm một điều kiện và một thân; mỗi nhịp kiểm điều kiện rồi chạy thân, nên cùng một đoạn mã được dùng lại nhiều lần với dữ liệu khác nhau, và dừng khi điều kiện hết đúng. Thân là cả khối nếu bọc ngoặc nhọn, còn không thì chỉ gồm đúng một lệnh. Câu "To perform mathematical calculations." sai vì phép tính là việc của toán tử và hàm thư viện, thân vòng lặp có thể chẳng có phép tính nào. Câu "To define variables within a program." là việc của câu khai báo; phần khởi tạo của for có thể khai báo biến đếm nhưng đó không phải mục đích của vòng lặp. Câu "To execute a statement based on a condition" mô tả if: chạy hay không chạy một lần, thiếu hẳn ý lặp lại.
Mở trang câu hỏi này →
AIt is used to decide whether the part of the code will be executed or not based on the specified condition.
BIt allows you to repeat a block of code a specified number of times.
CIt is used to define a function in a programming language.
DIt is used to declare variables and assign values to them.
Lời giải
Đáp án đúng: "It is used to decide whether the part of the code will be executed or not based on the specified condition." Cấu trúc if tính giá trị biểu thức điều kiện, coi khác không là đúng, rồi chạy nhánh tương ứng, nhờ đó một khối mã có chạy hay không phụ thuộc dữ liệu lúc chạy. Cần nhớ nhánh không bọc ngoặc nhọn chỉ ôm đúng một lệnh, nên lệnh viết sau đó nằm ngoài nhánh dù được thụt vào. Câu "It allows you to repeat a block of code a specified number of times." là việc của vòng lặp; if không bao giờ quay lại chạy khối lần nữa. Câu "It is used to define a function in a programming language." sai vì định nghĩa hàm cần kiểu trả về, tên hàm và danh sách tham số. Câu "It is used to declare variables and assign values to them." là việc của câu khai báo và phép gán, hai thứ độc lập với điều kiện.
Mở trang câu hỏi này →
A2.5
B2.0
C2
D3.5
Lời giải
Đáp án đúng: "2.0". Biểu thức 5 / 2 chỉ gồm hai hằng số nguyên nên trình dịch dùng phép chia nguyên, cho 2 và bỏ phần dư; kiểu của biến đích không quay lại ảnh hưởng cách tính biểu thức bên phải, đây là chỗ bẫy của câu hỏi. Giá trị 2 sau đó mới được nâng lên float thành 2.0, và %.1f in một chữ số sau dấu chấm nên màn hình hiện 2.0. Muốn có phép chia thực phải để ít nhất một toán hạng là số thực, chẳng hạn viết 5.0 / 2. Số "2.5" là kết quả của phép chia thực, chỉ xuất hiện khi đã có toán hạng thực. Số "2" là cách in một số nguyên bằng %d, còn %.1f luôn kèm dấu chấm và một chữ số. Số "3.5" không ứng với cách tính nào của 5 chia 2, dù chia nguyên hay chia thực.
Mở trang câu hỏi này →
Aint a = 25;
Ba = 25;
CInt a = 25;
Da = (Int) 25;
Lời giải
Đáp án đúng: "int a = 25;". Một khai báo đầy đủ cần tên kiểu đứng trước, rồi tên biến, và có thể kèm dấu bằng với giá trị khởi tạo; int là từ khoá kiểu nguyên viết toàn chữ thường, nên dòng này vừa tạo biến vừa gán giá trị đầu cho nó. Dòng "a = 25;" chỉ là một phép gán, nó đòi a phải được khai báo ở đâu đó trước; chuẩn C hiện hành đã bỏ luật ngầm hiểu kiểu int nên dòng này không tự tạo ra biến. Dòng "Int a = 25;" sai vì C phân biệt chữ hoa chữ thường, từ viết hoa đó không phải từ khoá mà bị coi là một tên kiểu chưa từng định nghĩa. Dòng "a = (Int) 25;" mắc cả hai lỗi cùng lúc: không có khai báo kiểu cho a, và phép ép kiểu lại viện tới một tên kiểu không tồn tại.
Mở trang câu hỏi này →
116What is printed?4 lựa chọncó code
Đề bài
char sentence[81] = "This is a test";
int n = strlen(sentence);
printf("%d", n);
A13
B14
C15
DCompilation error
Lời giải
Đáp án đúng: "14". Mảng sentence có tám mươi mốt ô nhưng được khởi tạo từ hằng chuỗi, nên chỉ phần đầu mang nội dung, ô ngay sau chữ cuối giữ byte rỗng kết thúc và các ô còn lại cũng bằng không. Hàm strlen đếm số ký tự tới trước byte kết thúc, kể cả dấu cách: bốn chữ của This, một dấu cách, hai chữ của is, một dấu cách, một chữ a, một dấu cách rồi bốn chữ của test, cộng lại đúng 14. Số "13" là kết quả khi bỏ sót một dấu cách, lỗi đếm thường gặp vì dấu cách không nhìn thấy rõ. Số "15" là số byte chuỗi thật sự chiếm, tức mười bốn ký tự cộng byte kết thúc. Kết luận "Compilation error" sai vì khởi tạo mảng char tám mươi mốt ô bằng một chuỗi ngắn hơn là hợp lệ.
Mở trang câu hỏi này →
A14
B3
C10
D0
Lời giải
Đáp án đúng: "3". Trong hằng chuỗi, dãy gồm dấu chéo ngược và số không là một ký tự duy nhất, chính là byte rỗng dùng để đánh dấu kết thúc chuỗi. Khi trình dịch dựng hằng này, vùng nhớ lần lượt chứa ba chữ in hoa của FPT, một byte rỗng, mười chữ của University, rồi một byte rỗng nữa, tổng cộng mười lăm byte. Hàm strlen đi từ byte đầu và dừng ở byte rỗng đầu tiên, nên nó chỉ đếm được ba ký tự. Số "14" là số chữ cái nhìn thấy trên mặt chữ, tức cách đếm bỏ qua ý nghĩa của byte rỗng. Số "10" là độ dài của phần đứng sau byte rỗng, phần mà strlen không bao giờ chạm tới. Số "0" chỉ đúng nếu ký tự đầu tiên đã là byte rỗng, trong khi ở đây byte đầu là một chữ in hoa.
Mở trang câu hỏi này →
A0
B1
C10
D11
Lời giải
Đáp án đúng: "0". Dấu chấm than là phép phủ định logic trên một toán hạng: C coi mọi giá trị khác không là đúng và chỉ số không là sai, còn kết quả của phép logic luôn là int mang giá trị 0 hoặc 1. Toán hạng 1 là đúng nên phủ định nó cho sai, tức 0. Số "1" là kết quả của phép phủ định hai lần, hoặc là chính toán hạng ban đầu khi quên áp phép toán. Số "10" ứng với cách hiểu nhầm dấu chấm than thành phép ghép ký tự, như thể viết 1 rồi 0 cạnh nhau; C không có phép nối số kiểu đó. Số "11" cũng là một dãy ký tự ghép lại, lại thêm hiểu nhầm rằng phủ định của 1 vẫn là 1. Cần phân biệt phủ định logic với đảo bit, vì đảo bit của 1 trên int bốn byte cho -2.
Mở trang câu hỏi này →
119Given the following code snippet:4 lựa chọncó code
Đề bài
#include <stdio.h>
#define MONTHS_IN_YEAR 12
int main() {
    const int WORKING_DAYS = 22;
    printf("%d ", MONTHS_IN_YEAR);
    printf("%d", WORKING_DAYS);
    return 0;
}

Choose the correct statement:

AThe output will be: 12 22
BNo output
CCompile error
DRuntime error
Lời giải
Đáp án đúng: "The output will be: 12 22". Dòng define là chỉ thị tiền xử lý: trước khi dịch, mọi chỗ viết MONTHS_IN_YEAR bị thay bằng dãy ký tự 12, nên lệnh in đầu nhận hằng số 12. Biến WORKING_DAYS khai báo const int kèm giá trị khởi tạo là hợp lệ, vì const chỉ ngăn gán lại về sau chứ không ngăn khởi tạo, nên lệnh in thứ hai cho 22. Chuỗi định dạng đầu có dấu cách sau %d nên hai số cách nhau một khoảng. Kết luận "No output" sai vì cả hai lệnh printf đều chạy với đối số hợp lệ. Kết luận "Compile error" sai vì không có vi phạm nào: tên hằng viết hoa chỉ là quy ước, và const int khởi tạo ngay là lối dùng đúng. Kết luận "Runtime error" sai vì chương trình chỉ in hai số nguyên rồi trả về 0, không chạm tới vùng nhớ nào có thể gây lỗi.
Mở trang câu hỏi này →
A2 bytes
B1 byte
C8 bytes
D4 bytes
Lời giải
Đáp án đúng: "4 bytes". Trên gần như mọi trình dịch C hiện hành, float là số thực theo chuẩn IEEE 754 độ chính xác đơn: ba mươi hai bit chia thành một bit dấu, tám bit số mũ và hai mươi ba bit phần định trị, tức đúng bốn byte, và sizeof(float) trả về 4. Số "2 bytes" là kích thước thường thấy của short int, không có kiểu thực chuẩn nào nhỏ như vậy. Số "1 byte" là kích thước của char, kiểu mà chuẩn ấn định bằng một byte, quá nhỏ để chứa cả dấu, số mũ và phần định trị. Số "8 bytes" là kích thước của double, bản độ chính xác kép với mười một bit số mũ và năm mươi hai bit định trị; chính vì gấp đôi chỗ mà double giữ được nhiều chữ số nghĩa hơn float.
Mở trang câu hỏi này →