2023-2024¶
为了让同学们适应期末考试,每日一题的题面都将使用英文描述。
December¶
「10」 I Love pointer¶
What is the output of the following program on a 64-bit system?
char str[3][10]={"","ILoveCKC","ILoveZJU"};
printf("%lu#%lu\n",strlen(str[0]),sizeof(str[0]));
printf("%lu#%lu\n",strlen(str),sizeof(str));
printf("%d#%c\n",str[1][-10],str[1][10]); // Don't write this in your own code.
printf("%s\n",(**str == (*(str + 1) + 8)[1] ? "True" : "False"));
printf("%s",&str[1][9] == &((*(str + 1) + 8)[1]) ? "True" : "False");
Answer
0#10
0#30
0#I
True
True
strlen(str[0])
returns the length of the string pointed to bystr[0]
, which is 0.sizeof(str[0])
returns the size of the arraystr[0]
, which is 10.strlen(str)
returns the length of the string pointed to bystr
, which is 0.sizeof(str)
returns the size of the arraystr
, which is 30. In fact,str[0]
's value is same asstr
's value.str[1][-10]
is equivalent to*(str[1] - 10)
which is equivalent to**(str + 1 * 10 - 10)
which is equivalent to** str
. Sostr[1][-10]
's value is'\0'
.str[1][10]
is equivalent to*(str[1] + 10)
which is equivalent to**(str + 1 * 10 + 10)
which is equivalent to** (str + 20)
Sostr[1][10]
's value is'I'
.(*(str + 1) + 8)[1]
is the same asstr[1][9]
. So**str == (*(str + 1) + 8)[1]
is true.
供题人:胡育玮
「9」 sizeof
All in One¶
What is the output of the following program on a 64-bit system?
char str[][3] = {'L', 'o', 'v', 'e', 'C', 'K', 'C'};
printf("%d ", (int)sizeof(str));
printf("%d ", (int)sizeof(&str));
printf("%d ", (int)sizeof(*str));
printf("%d ", (int)sizeof(str + 1));
printf("%d ", (int)sizeof(*str + 1));
printf("%d ", (int)sizeof(*(str + 1)));
printf("%d", (int)sizeof(*(*(str + 1) + 1)));
Answer
9 8 3 8 8 3 1
.
This is a comprehensive problem combining sizeof
and pointer.
- When the object is an array name, the return value is the total size of the whole array. At initialization, the third row of the array will be filled to a 1-D array of length 3 automatically:
char str[][3] = {{'L', 'o', 'v'}, {'e', 'C', 'K'}, {'C', '\0', '\0'}};
. Therefore the value ofsizeof(str)
equals to 3 * 3 * 1 = 9 sincesizeof(char) = 3
. - In the expression
&str
,&
represents the address-of operator and the return value is the address of the entire array. That, of course, can be regarded as a pointer and hencesizeof(&str)
equals 8 (Bytes), the size of a pointer on a 64-bit system. - Now let's focus on
str
. We know thatstr
is an array ofchar [3]
. In the view of pointer,str
is also a pointer to the first element (Note that the element here is an array of length 3). Hence*str
is equivalent tostr[0]
which is an 1D array of length 3. So the output ofsizeof(*str)
is 3 * 1 = 3. - In the previous discussion we know that
str
is a pointer to array of length 3 (char (*)[3]
actually), sostr + 1
is also a pointer and the output is 8. *str
(equivalent tostr[0]
), will be converted toint *
when added by 1. Therefore*str + 1
is a pointer tostr[0][1]
and 8 will be output again.- From discussion 3 and 4 it's not difficult to find
*(str + 1)
an array of length 3 (str[1]
), so 3 is the answer. *(*(str + 1) + 1)
is classical equivalence ofstr[1][1]
. Thereforesizeof(*(*(str + 1) + 1))
equals tosizeof(char)
, namely 1.
供题人:徐若禺
「8」 J lost¶
Given the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Which of the following is correct?
A. This program fails to compile, because you cannot assign to an array in line 13.
B. Because of the call-by-value, function xqc
cannot modify the character arrays in function main
.
C. Change 1694
in line 7 to 1994
, and the result of the program is the same.
D. This program outputs I am a Man of Fortune, and J must seek my Fortune
.
Answer
C.
A: Inside function xqc
, c
is a pointer type char *
rather than an array type, because when an array type is used in a function parameter list, it actually is the corresponding pointer type. Therefore, the assignment in line 13 is valid, and it means "to move the pointer c
one position backward".
B: The function xqc
can modify the character arrays in function main
, because it takes the address of the character arrays as parameters. The function xqc
can modify the contents of the character arrays through the pointers.
C: The ~
operator is the bitwise NOT operator. The ~1694
is equivalent to -1695
. The ~3
is equivalent to -4
. Therefore, the calls to function xqc
are equivalent to:
xqc(c + 1, -1695);
xqc(d - -4, -65);
And i & 1
gets the last bit of i
. Both -1695
and -65
are odd numbers, so i & 1
is 1
, and the character 1 + 'I'
, which is 'J'
, is assigned. Changing 1694
to 1994
does not change the result of the program, because ~1994
is -1995
, and -1995
is also an odd number.
D: This program outputs Jam a Man of Fortune, and J must seek my Fortune
.
Tip
You don't need to calculate the exact value of ~1694
. All you need to know is that the last bit of 1694
is 0 (since it is an even number), and the bitwise NOT operator will reverse that last bit. Therefore, ~1694
is an odd number, and i & 1
is 1
. Ditto for ~1994
.
供题人:李英琦
「7」 The difference between strlen
and sizeof
¶
1 2 3 4 5 6 7 8 9 10 11 12 |
|
What are the results?
Answer
D.
arr1
has \0
at the end, but arr2
doesn't.
The sizeof
operator returns the size of its operand in bytes. In this case, the size of arr1
is 5, because it contains 4 characters and a null character \0
. The size of arr2
is 4, because it contains just 4 characters. The \0
is absent in arr2
.
The strlen
function returns the length of the string, that is, the number of characters in the string before the null character \0
. In this case, the length of arr1
is 4, because it contains 4 characters before the null character \0
. But the length of arr2
is indeterminable, because it does not contain a null character \0
. The strlen
function will continue to read memory until it finds a null character \0
, resulting totally random result. If there is no null character \0
in the memory, the behavior is undefined.
供题人:华展辉,李英琦
「6」 Stack and Queue (adapted from FDS mid-term exam)¶
Given an empty stack S
and an empty queue Q
. Push elements {1, 2, 3, 4, 5, 6, 7}
one by one onto S
. If each element that is popped from S
is enqueued onto Q
immediately, and if the dequeue sequence is {3, 2, 4, 6, 7, 5, 1}
, then the minimum size of S
should be:
Answer
C.
Stack is LIFO (Last In, First Out), queue is FIFO (First In, First Out). So dequeue sequence of queue is also the enqueue sequence. If enqueue sequence of Q is {3, 2, 4, 6, 7, 5, 1}, all operation of stack S must be the following:
- Push 1 and 2 and 3 into stack sequentially. Stack S now contains 3 nodes.
- Pop 3, stack contains 2 nodes
- Pop 2, stack contains 1 node
- Push 4, stack contains 2 nodes
- Pop 4, stack contains 1 node
- Push 5, stack contains 2 nodes
- Push 6, stack contains 3 nodes
- Pop 6, stack contains 2 nodes
- Push 7, stack contains 3 nodes
- Pop 7, stack contains 2 nodes
- Pop 5, stack contains 1 node
- Pop 1, stack is empty
In the process, there are at most 3 nodes in stack S, so the minimum size of S should be 3.
供题人:姚雪涛
「5」 Monotonic stacks¶
Monotonic stacks are a specialized version of the standard stack data structure, designed to maintain elements in a pre-defined sorted order. Unlike regular stacks, which allow push and pop operations without any constraints, monotonic stacks enforce an order - either increasing or decreasing - on the elements. This means that elements are either strictly increasing or strictly decreasing from the top to the bottom of the stack.
The core operations of a monotonic stack, namely push
, are modified to maintain the stack’s order. During a push
operation, elements that break the monotonic property are removed from the stack before the new element is added.
For example, now we have a decreasing monotonic stack, where elements closer to the top have the smaller values:
[5,4,2,1]
^
|
top
We push a data with the value \(3\), and because \(1,2\) is smaller than \(3\), we remove them. And finally it will be:
[5,4,3]
^
|
top
Now, your task is to create an decreasing monotonic stack in the C language.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
Answer
单调栈是一种特殊的栈,其中每个元素都严格小于或大于它下面的元素。大家在后续的课程中有可能会接触到他的一些应用。接下来我们逐一看看这些题目怎么填写:
第一空:这里需要初始化栈顶元素。由于栈是空的,所以栈顶应该设置为 NULL
。
stack->top = NULL;
第二空:这是最难的一空。根据题意,这一层循环的目的是:移除所有小于或等于新元素的栈顶元素,以维持栈的单调性。但是还有一种情况:如果栈本身是空的,或者所有元素都比新元素小,那必须得退出循环。
while (stack->top != NULL && stack->top->data <= data)
第三空:不大容易想到。在移除栈顶元素后,应该释放该节点占用的内存。
free(temp);
为什么出这个?因为 wk 明确说过,考试考这个填空,不写 free 就少 2 分,所以出了这个空来让大家注意。
第四空:这里需要将新节点的 next
指针指向之前的栈顶元素,然后将栈顶指针指向新节点,这样新节点就成为了新的栈顶。
newNode->next = stack->top;
供题人:谢集
「4」 Command Line Arguments¶
If you run the following command in the terminal:
1 |
|
Please describe what will the program see in argv
and argc
.
Answer
argv
is an array of pointers to strings, and argc
is the number of strings in argv
. The argv
array contains the following strings:
argv[0] = "./a.out"
argv[1] = "this"
argv[2] = "is"
argv[3] = "a"
argv[4] = "test"
The argc
is 5, because there are 5 strings in argv
.
The argv
array is terminated by a null pointer, so argv[5]
is a null pointer.
For more information about argv
and argc
, see cppreference-argc, argv.
供题人:朱宝林
「3」 sizeof
struct
¶
Consider the following code fragment:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
What is the value of sizeof(A)
and sizeof(B)
?
Answer
sizeof(A)
is 16, and sizeof(B)
is 8 (on a 64-bit modern system).
The sizeof
operator returns the size of its operand in bytes. The size of a structure type is as large as the sum of the sizes of its members.
You may think the size of A
is 14, because the size of char[10]
is 10, and the size of int
is 4. However, to improve performance of memory access, C standard allows the compiler to add padding bytes after each member of a structure, and the padding strategy is implementation specific. A common strategy is to align each member to the size of its type, that is to say, make their memory address to be a multiple of the size of the member. For example, on a 64-bit system, the address of a 4-byte integer must be a multiple of 4.
Therefore, The size of A
is 16. The compiler will add 2 padding bytes after char[10]
, to make the address of int
a multiple of 4 in struct A
.
The size of B
is 8, because B
is a pointer and the size of pointer is 8. The size of type to which B
points does not affect the size of B
. Notice that type B
is not equivalent to type struct B
.
For more information about sizeof
operator, see cppreference-sizeof.
供题人:朱宝林、孙兆江
「2」 Print Non-printable Characters¶
Write a program to convert unprintable characters (characters with ASCII codes between 0x00
~0x1f
and 0x7f
) in the input string to hexadecimal format for output.
Requirements:
- Do not use the
printf
series of formatting output functions. - The minimum field width for output is
2
, and if the hexadecimal number is less than 2 digits, pad it with leading zeros. For example,0x0a
.
Sample Input:
Hello
World!
Sample Output:
Hello\0x0aWorld!
Answer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
If you are not familiar with bitwise operations, the 14th and 15th lines in the above code fragment can be written in a more understandable form:
putchar(hex_digits[temp / 16]);
putchar(hex_digits[temp % 16]);
供题人:朱宝林
「1」 Hello, Cat¶
After executing the following code fragment, the output should be __.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
A. Hello, world; llold, ld.
B. Hello, world; lloldw<, ld.
C. Hellold, world; llold, ld.
D. Helloldw<, world; lloldw<, ld.
Answer
C
.
The strcat
function appends a copy of the string pointed to by s4
to the end of the string pointed to by s3
. The s3
and s4
pointers point to the third character of s1
and the fourth character of s2
, respectively. Therefore, the strcat
function appends the string "ld"
to the end of the string "Hellold"
, resulting in "Helloldld"
, and the printf
function prints "Hellold, world; llold, ld."
.
When the strcat
function appends the string "ld"
after "Hello", it overwrites the null character '\0'
at the end of the string "Hello"
and write a new null character '\0'
at the end of the string "Helloldld"
. Therefore, the character w
and <
after the null character '\0'
in s1
are not printed.
供题人:郑俊达
November¶
「30」 Basic Doubly Linked List¶
Please fill in the blanks to complete the following code fragment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Answer
list
list->next
node
node
list->next
Notice this is a doubly linked list with a dummy node. The dummy node is a special node that does not store any data. It is used to simplify the implementation of the linked list. In this case, the dummy node is list
.
The insertFront
function inserts a new node with data
at the front of the list. The new node is inserted between the dummy node and the first node of the list. The insertFront
function takes two steps:
- Create a new node and set its
data
todata
. - Insert the new node between the dummy node and the first node of the list.
If you want to iterate over the list, you should start from the first node of the list, which is list->next
.
供题人:朱宝林
「29」 Soyo Size¶
On a 64-bit machine, the output of the following code fragment is __.
1 2 3 4 5 6 7 8 9 |
|
Answer
C.
When an array type is used in a function parameter list, it is transformed to the corresponding pointer type: int f(int a[])
and int f(int *a)
declare the same function. See cppreference-Array to pointer conversion for more information.
So the parameter soyo
in function print_soyo
is actually a pointer, and the size of a pointer is variable depending on the architecture. On a 64-bit machine, the size of a pointer is 8 bytes, and on a 32-bit machine, the size of a pointer is 4 bytes. Therefore, the output of this program is 8
.
供题人:苏煜程
「28」 Naughty Pointer¶
The following code fragment prints out __.
1 2 3 |
|
Answer
6
.
Obviously, the type of p
is declared as int (*)[3]
, which is a pointer to an array of 3 integers. We know that in the initializer, a
will be converted to a pointer to its first element, so *a
is equivalent to a[0]
, which is an array of 3 integers. Then, the type of *a
will be converted from int [3]
to int *
again. Therefore, adding 1 to *a
will make it point to the next integer, which is a[0][1]
.
You may notice that the type of *a + 1
is not the same as pointer p
. In fact, its type is casted to int (*)[3]
when assigned to p
. Trying to figure out the "meaning" of p
now may become more difficult. Instead, just remember the value of pointer p
is the address of a[0][1]
.
Now consider the expression *(*(p + 1) + 1)
. First, since the type of p
is int (*)[3]
, adding 1 to p
will make it point to the next array of 3 integers; that is to say, the value of p
will be the address of the third integer after a[0][1]
, which is a[1][1]
. So *(p + 1)
is just equivalent to &a[1][1]
. Then, adding 1 to *(p + 1)
will make it point to the next integer, which is a[1][2]
. Thus, the value of *(*(p + 1) + 1)
is a[1][2]
, which is 6.
供题人:孙兆江
「27」 I Love scanf
¶
After entering the following inputs, does the program operate normally? If it does, what should be the output?
1 2 3 4 5 |
|
1 2 3 4 |
|
Answer
The program operates normally and the output is:
20231127#
#c#kc-agc
The scanf
function reads input from the standard input stream, which is usually the keyboard. The format string of scanf
is "%d%c %c%s\n"
. The first %d
matches the integer 20231127
, the second %c
matches the character '\n'
because %c
won't miss any character including ' '
and '\n'
. The space in formatting string will ignore every blank character, so the third %c
matches the character 'c'
, and the fourth %s
matches the string "kc-agc"
, whose length is 7. When you print \n
after line2, scanf
will not stop, because '\n'
in formatting string will ignore every blank character. So until you enter a non-blank character and use enter to send it to the program from buffer, scanf
will stop.
供题人:胡育玮
「26」 Broken strcpy()
¶
Does this strcpy()
implementation do its job?
1 2 3 4 5 |
|
Answer
No, it's broken. This implementation does not terminate the string pointed to by s
. To correctly copy a string, the character used in assignment must be the same character used in loop condition.
What does that mean? Suppose t = "Hello"
, then:
*t
is'H'
, and is assigned to*s
.s
andt
increment.*t
, now being'e'
, is used to evaluate thewhile
condition.- ... this process repeats until
t
points to'o'
and is assigned to*s
. s
andt
increment.*t
, now being'\0'
, is used to evaluate thewhile
condition. The loop ends.
See the problem? The null byte '\0'
is not copied to s
, therefore it's left unterminated. Any attempt to use s
as a string will result in undefined behavior.
Worse still, what happens if t
is an empty string i.e. t = ""
?
'\0'
is assigned to*s
.s
andt
increment.t
gets past its end.- Now we have a memory out-of-bounds. Accessing
*t
is undefined behavior. - And it keeps copying garbage values until some arbitrary
'\0'
, or it goes too far and causes a segmentation fault.
供题人:李英琦
「25」 I Love Strcat¶
The following code fragment prints out __.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
A. I love cats!\n\n
B. \n\n
C. \nI love cats!\n
D. I love cats!\nI love cats!\n
Answer
A
.
The function my_strcat
is supposed to concatenate s1
and s2
and store the result in s3
. However, the function does not work as expected. The problem lies in the line s3 = malloc(len1 + len2 + 1);
. The function my_strcat
takes s3
as a parameter, which is a pointer to a char
array. When the function is called, the value of s3
is copied to the function's local variable s3
. Therefore, the malloc
function allocates memory for the local variable s3
, not the original s3
in main
. The memory allocated for the local variable s3
is not used after the function returns, so it is a memory leak. The original s3
in main
is not modified, so it is still an empty string.
You may think that the problem can be solved by simply deleting the line s3 = malloc(len1 + len2 + 1);
. However, this will cause another problem. s3
is initialized as an empty string, which means that it is a pointer to a char
array with only one element, the null character \0
. The memory allocated for s3
is not enough to store the concatenated string. Therefore, this will cause a buffer overflow.
供题人:梅敏炫
「24」 Pointer Array¶
The output of the following code fragment is __.
1 2 3 4 5 6 7 8 9 |
|
Answer
A.
a[]
is an array of pointers, which stores the addresses of three strings, and pa
points to the address of the first element of a
, as shown below:
Pointer operations take precedence over addition, so *(*pa + 1)
equals to n
.
In summary, the code fragment prints out none
.
供题人:华展辉
「23」 typedef
and String¶
The preprocessing of this program is as follows:
1 2 3 4 5 6 7 |
|
After executing the following code fragment, the output should be __.
1 2 3 4 5 6 |
|
Answer
Output is:
k
ok
oo
The address pointed to by library[0]->book[0]
plus (strlen(library[0]->book[0])-i-1) * sizeof(char)
will be eventually passed to %.2s
and placed into the output stream.
Thus, when i=0
, i=1
, and i=2
, the strings passed to %.2s
are "k\0", "ok\0", and "ook\0", respectively. Among these, the length of the third string "ook\0" exceeds 2, so only the first two characters "oo" will be output.
This question involves multiple concepts, primarily focusing on both the proper usage of typedef
and issues related to pointer output with char*
in C. The analysis will be divided into two parts: typedef
and char*
. If you are already familiar with typedef
, you can directly skip this section.
typedef
In the C language, typedef
is used to create new names for existing data types.
When using typedef
, errors can occur in the specification of its usage. One common misunderstanding is to interpret typedef (type_name) (new_name)
, which is correct only in a few cases, such as typedef int Integer
.
However, the correct understanding should be: if you need to redefine a type, first write the declaration statement of that type: type variable_name
, then replace variable_name
with the alias you want, and finally add typedef
in front of the entire statement.
For example, after int array[10]
, where the type of the variable array
is int [10]
, you can rename array
to the alias IntegerList
and add typedef
at the front, resulting in typedef int IntegerList[10]
.
After this, you can directly use the alias IntegerList
to define variables of type int [10]
, such as IntegerList a;
, which is equivalent to decelaration: int a[10]
.
Returning to the question, let's analyze the two typedef
statements in the question.
The first one creates an alias for a structure variable. If we initially want to declare a variable of type struct Bookcase*
, we would write it like this:
struct Bookcase {
char* book[10];
} *Bookcase1;
Following the rules of typedef
, replace the variable name Bookcase1
with the alias PtrToBookcase
and add typedef
at the beginning of the entire statement, resulting in the form seen in the question:
typedef struct Bookcase {
char* book[10];
} *PtrToBookcase;
This statement means giving an alias, PtrToBookcase
, to the type struct Bookcase*
.
The second typedef
is very similar to the example we mentioned earlier, typedef int IntegerList[10];
.
It first declares PtrToBookcase Ptr1[MAX_SIZE]
, then replaces the variable name Ptr1
with the alias Lib_data_base
, and adds typedef
at the front.
Therefore, its meaning is to give an alias, Lib_data_base
, to the type PtrToBookcase [MAX_SIZE]
.
Consequently, the subsequent Lib_data_base library
actually creates an array of PtrToBookcase
, named library
, with MAX_SIZE
elements.
char*
After understanding typedef
, let's now explore the issue related to string output in this program.
There are two potentially confusing elements in this code: %.2s
and library[0]->book[0]+strlen(library[0]->book[0])-i-1
.
%.2s
is relatively straightforward: It is used to control the output of strings. %s
would directly output the characters stored at the memory location pointed to by a char*
type pointer and all characters in consecutive memory until encountering the '\0' character.
The additional .2
in %.2s
is used to limit the length of the output string. If the string length is less than or equal to 2, it will be output normally. If it exceeds 2, only the first two characters will be output.
library[0]->book[0]+strlen(library[0]->book[0])-i-1
involves operations on a char*
type pointer.
library[0]->book[0]
is a char*
type pointer. Adding n
to it effectively shifts the pointer to a position n * sizeof(char)
bytes forward from the current address. Subtracting n
from it shifts the pointer to a position n * sizeof(char)
bytes backward from the current address.
供题人:姚雪涛
October¶
「29」 Precedence¶
The output of the following code fragment is __.
1 2 |
|
Answer
The answer is 2.
Several operators appear in this problem, listed in order of operation precedence from top to bottom:
- Suffix increacement and decreacement:
a++
- Logical NOT:
!
- Prefix increacement and decreacement:
--a
- Subtraction:
-
- Bitwise left shift:
<<
- Comparison:
<
,>
- Logical OR:
||
- Ternary conditional:
a ? b : c
See more about operator precedence at cppreference.com.
Knowing this, let's break down the expression from the innermost to the outermost parts.
1 - 1
evaluates to 0, andy << 0
has the value 2.2 > 2
is false, thus the value of the Logical OR depends on the right part.x++
assigns the value ofx
(1) to the expression and then incrementsx
by 1, makingx
equal to 2.--y
decreases the value ofy
(2) by 1, soy
becomes 1.x++ > --y
is equivalent to 1 > 1, which is false, so this part equals 0.!(x++ > --y)
negates false, so this part equals 1, making the condition of the Ternary conditional true.- Since
x
has the value of 2 andy
has the value of 1, the output will be 2.
供题人:徐若禺
「27」 Or in switch
¶
What will happen when compiling and executing the following code fragment with input 5
?
1 2 3 4 5 6 7 8 9 10 |
|
A. It will print odd digit
.
B. It will print odd digit not a digit
.
C. It will print not a digit
.
D. It cannot be compiled.
Answer
D
.
The compiler will tell you that case label value has already appeared in this switch
.
There are many problems in this code fragment, and the most important one is that 0 || 2 || 4 || 6 || 8
will not behave as expected in case
statement. It will be evaluated as 1
because 0 || 2 || 4 || 6 || 8
is equivalent to ((((0 || 2) || 4) || 6) || 8)
. The result of 0 || 2
is 1
, so the result of 0 || 2 || 4
is 1
, and so on. Therefore, the case
statement will be evaluated as case 1
. The same problem exists in case 1 || 3 || 5 || 7 || 9
, which will also be evaluated as case 1
.
The correct way to write this code fragment is:
char ch;
scanf("%c", &ch);
switch (ch) {
case '0': case '2': case '4': case '6': case '8':
printf("even digit "); break;
case '1': case '3': case '5': case '7': case '9':
printf("odd digit "); break;
default:
printf("not a digit ");
}
For more information about switch
statement, see cppreference-Switch statement.
供题人:郑俊达
「26」 Bitwize Operator¶
Which of the following options can achieve a swapping effect for pair(*,*)
?
Note that ^
represents XOR
operation. For binary numbers, 0 XOR 0 = 0
, 0 XOR 1 = 1
, 1 XOR 0 = 1
, 1 XOR 1 = 0
.
A. (x, y)
: x ^= y ^= x ^= y;
B. (a[x], a[y])
: a[x] ^= a[y] ^= a[x] ^= a[y];
C. (x, y)
: x -= y += x -= y;
D. (a[x], a[y])
: a[x] -= a[y] += a[x] -= a[y];
Answer
A
.
B
will always be0
whenx==y
.C
andD
is not logically correct.
供题人:程昕宇
「25」 Eternal Binary-Search¶
After executing the following code fragment, the output should be __.
1 2 3 4 5 6 7 8 9 10 |
|
Answer
In fact, this code fragment has no output because it is stuck in an endless loop. Let's see what happens: At first the code executes perfectly, l
increasing and r
decreasing constantly. However, when the value of r-l
reduce to 1
, the value of l
and r
will never change again. That's because mid
equals to l
and ok[mid]
is true
(Think about it. why?), so l = mid
will be execute, again and again with no value change.
Binary Search is a very simple, common and useful algorithm that you will learn soon. However, when using Binary Search, it is easy to write a wrong code. It is said that only 10% of the programmers can write a exactly correct code. Hence, you need to pay special attention to this algorithm. A small change can possibly change the code correctness. For example, modifying the int mid = (l + r) / 2;
to int mid = (l + r + 1) / 2;
makes the code correct.
供题人:郑涵文
「24」 Nested switch
, Confusing default
and break
¶
After executing the following code fragment, the output should be __.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Answer
one two four
The syntax of switch
statement is:
switch (expression) {
case constant-expression:
statements
case constant-expression:
statements
default:
statements
}
The expression
must have an integral or enumerated type, or be of a class type in which the class has a single conversion function to an integral or enumerated type. The constant-expression
for each case
must be a constant expression of the same type as the expression, and no two of the constant expressions associated with the same switch
statement shall have the same value after conversion.
The switch
statement evaluates expression
, then looks for the case
constant-expression whose value is equal to the value of expression
(after conversion). If such a case
is found, the statements following that case
are executed until a break
statement is encountered. If no case
is found whose value is equal to the value of the expression, and if there is a default
label, the statements following the default
label are executed. Otherwise, the statements of the switch
statement are skipped.
If some case
labels are not followed by break
statements, the execution of the switch
statement falls through to the next case
label. You can use this behavior to execute multiple statements for a particular case
label or to execute statements for more than one case
label.
供题人:朱宝林
「23」 Prefix OR Postfix¶
After executing the following code fragment, the value of variable x
is __.
1 2 3 4 |
|
Answer
11
-
The result of the increment and decrement operators
Increment and decrement operators have postfix form
x++
(orx--
), and prefix form++x
(or--x
).- The result of the postfix forms is the value of
x
. - The result of the prefix forms is the value of
x + 1
for++x
(orx - 1
for--x
).
For more information, see cppreference-Increment/decrement operators
- The result of the postfix forms is the value of
-
Logical OR
||
The logical OR expression has the form
lhs || rhs
, in whichrhs
is only evaluated iflhs
compares equal to0
.For more information, see cppreference-Logical operators
When x < 9
, each loop will cause x
to increase by 1
. Note that only x-- < 9
is evaluated in each loop now.
Now x
is equal to 9
before the cond-expression of the for loop. First, x-- < 9
is evaluated, which compares equal to 0
, and causes x
to decrease by 1
. Then x
is equal to 8
and ++x < 10
is evaluated, which compares equal to 1
and causes x
to increase by 1
. Loop continues.
Then, x
is equal to 11
before the cond-expression of the for loop. Now x-- < 9
and ++x < 10
both compare equal to 0
, so the loop ends. x
firstly decreases by 1
and then increases by 1
, so the final value of x
is 11
.
供题人:苏煜程
「22」 String Comparison¶
What's wrong with this code snippet?
1 2 3 4 5 6 7 8 |
|
Answer
Actually, the output of this program is unpredictable.
- To compare two strings, you should use
strcmp
function in<string.h>
header file. Learn how to use the function by yourself. - In the code snippet above,
a
,b
andc
are all arrays ofchar
, soa > b
anda > c
are actually comparing the addresses of these arrays. You may think that the array declared later has a larger address, but this is not always true. It depends on the design of the architecture that the stack grows towards higher memory addresses or towards lower memory addresses. So the output of this program is unpredictable. For more information on this, see StackOverflow: Is the order of memory addresses of successively declared variables always descending?
供题人:杨琳玥
「21」 Addition¶
After executing the following code fragment, the output should be __.
1 2 3 4 5 |
|
Answer
Not equal.
In C (and many other programming languages), floating-point arithmetic is not always exact due to the way numbers are represented in binary. This means that sometimes, tiny errors can be introduced and accumulated when performing mathematical operations on floating-point numbers.
In this case, when adding 0.1 and 0.2 together, the result is not precisely 0.3 due to these inaccuracies. Thus, directly comparing floating-point numbers with ==
can lead to unexpected results.
To deal with such issues in real programs, check if the difference between two floating-point numbers is smaller than a tiny threshold.
For more information about floating-point numbers, search for IEEE 754.
供题人:孙兆江
「20」 Bad for¶
After executing the following code fragment, the output should be __.
1 2 3 4 |
|
Hint
Review Oct.「18」 & 「16」 may help you get right answer.
Answer
-1
.
Notice that the condition of for
is x = y
, not x == y
. So for
loop will terminate until y = 0
. You should consider overflow in unsigned int
variable.
When we execute ++
for unsigned int y
in for
loop, we will get 0x111...1
(\(2^{32}-1\)) as the max unsigned int
, and then we will get 0x00...0
as 0
because of overflow. So x
gets the value of y(0)
and terminates for
. In printf
, x-1
is 0x11...1
. When you use %d
to print, it will be considered as a signed interger, so the answer is -1
, not \(2^{32}-1\).
供题人:胡育玮
「19」 IsPrime?¶
What's wrong with this code snippet?
1 2 3 4 5 6 7 8 9 10 11 |
|
Answer
Notice the condition of the for
loop: i <= d
, which means i
will eventually be equal to d
.
Therefore d % i == 0
evaluates to 1, reporting composite for every input greater than 1.
供题人:李英琦
「18」 Bad if
-else
¶
After executing the following code fragment, the output is __.
1 2 3 4 5 6 |
|
Answer
D
.
Notice that the condition of if
in line 5 is x = 0
, not x == 0
. The former means "0 is assigned to x", and then the if sentence won't be executed since it is equivalent to if(0)
. Thus the value of y
is its initial value, -2.
供题人:梅敏炫
「17」 Character¶
Given: char c = '@';
, the value of expression 'A' <= c <= 'Z'
is __.
Answer
1
.
To solve this problem you do not need to remember ASCII code. This problem is about operator precedence. The expression 'A' <= c <= 'Z'
is equivalent to (('A' <= c) <= 'Z')
. No matter what the value of c
is, the expression ('A' <= c)
will be evaluated to 1
or 0
, which is less than 'Z'
. Therefore, the value of the expression 'A' <= c <= 'Z'
is 1
.
But in other problems you may need to remember some key ASCII codes:
Character | ASCII Code |
---|---|
'0' |
48 |
'A' |
65 |
'a' |
97 |
Upper case is prior to lower case. The difference between 'A'
and 'a'
is 32
. So if you want to convert a lowercase letter to uppercase, you can use c - 32
. Or an easier way: c - 'a' + 'A'
.
来自:C 大 13 年期末
「16」 Overflow¶
For code below:
1 2 |
|
What will be the value of sht
after the execution?
Answer
B.
Remember that unsigned short
is an unsigned integer type, so it will not be negative. Instead, it will be the largest value of unsigned short
type. The largest value of unsigned short
type is 65535
, because unsigned short
is 16-bit long.
来自:C 大 13 年期末