1 單項選擇題(15⼩題,每⼩題2分,共30分)
1.1
解析:【傳值調用】,實參和形參之間傳遞的是“地址”
1.2
解析:【優先級】:算術運算符 > 關系運算符 > 賦值運算符
【結核性】:賦值運算符(從右至左) 算數運算符和關系運算符(從左至右)
相當於: ( k > i ) < j , ( i < j ) == ( j < k )
1.3
解析:指針數組是指數組的每一個元素都是一個指針變量的數組
相當於: point[2] 一樣
此題不合適之處:
#include <stdio.h> #include <stdlib.h> int main() { char *point[] = {"one","two","three","fourth"}; point[2] = point [3]; point[2] += 2; printf("%s",point[2]++); // 輸出的是字符串,不用point[2]++ return 0; }
例如:
1.4
解析:數組定義時,常量表達式中不允許包含變量
1.5
解析:【函數遞歸】,相當於 fib (2) + fib (1)
1.6
解析:【do 循環】
1.7
1.8
解析:【數組傳參】:傳過去的是地址,實參和虛參都改變
1.9
題目有錯!!!
解析:【運算優先級】:“ * ”和“ ++ ” 高於 " = ",“ * ”和“ ++ ”優先級相同,結合性:從右往左
*p1 += *p2++ 相當於: *p1 = *p1 + *(p2++)
*p2 = p1++ 相當於: *p1 = (p1++)
1.10
解析:【運算優先級】+ 【結合性】
i = 3 / 2 + 7 / 2 == 5 相當於: i = ( ( (3 / 2) + (7 / 2) ) == 5 )
j = 45 % 11 + (((7 > 8) ? 15: 14) == 14 相當於:j = (45 % 11) + ((((7 > 8) ? 15: 14) == 14 )
1.11
解析:!x是邏輯非操作,當x為0時,值為真,否則值為假。 在這里x = 8,即!x = 0,故while (!x) 為假,退出循環
例如:
1.12
解析:(i * j) / k + 6 - 15 % k 相當於 ((i * j) / k) + 6 - (15 % k) : “+”和“-” 結合性從左向右
1.13
解析: while()是循環語句。while(expr)表示當邏輯表達式expr為真時,循環運行循環體,直到expr值為假或遇到break語句時退出
由 316 = 13 * i + 11 * j 得:k 一定得是11的倍數
例:
1.14
解析:【字符數組的定義】:
char cc[ ] = {'1','2','3','4','5'}, 數組長度為5,字符串長度為5
char cc[ ] =”12345“,數組長度為6,字符串長度為5,自動在字符串結尾加上一個終止符 \0 ,
[strlen()]函數:測試字符串長度,不包括 \0
1.15
解析: 【指針與結構數組】:指向結構 的 指針 要先定義,后賦值
p 指向結構第一個字節,*p 相當於 stu
第一種方式:(*p).num 【由於結構成員引用符 "."的優先級比間接運算符 “ *” 高,故必須加括號】
第二種方式:p->num
第二種方式:stu.num 三種方式等價!!!
2 指出程序段中的錯誤:分析原因並修改。(每題15分,共30分)
2.1
改正后:
int main()
{
char *src = "HELLO,UESTC"; //指向字符串常量的指針
char *dest = NULL;
int len = strlen(src);
dest = (char *)malloc(len + 1);
char *d = dest;
char *s = &src[len - 1];
while ( len-- != 0 )
*d++ = *s--;
*d = '\0';
printf("%s\n", dest); // 使用printf()輸出時,%s 表示輸出一個字符串,src指向字符串的第一個字符,然后src自動加1
free(dest);
return 0;
}

知識點:
【指向字符串常量的指針】:不是將字符串存放在指針src中,而是將指向字符串的指針賦給指針變量,src指針指向字符串的首地址
2.2
改正后:
int func() {
//函數功能:復制字符數組data到array中 char data[50] = "welcome to CHENGDU and UESTC"; char *point; char array[200]=""; //初始化為空傳 int i = 0, length = 0; point = array; while (data[length] != '\0') //1處 length++; for (; i < length; i++) { *point = data[i]; //2處 point++; } puts(array); //3處 }
3 問答題(共70分)
3.1 C語⾔的單詞符號除關鍵字外,還包括其他哪四類?存儲類型關鍵字是哪4個?(每個1分,共8分)
答: 標識符【只能由字母、常量、下划線、數字組成,且第一個字符必須是字母或者下划線】、運算符、常量和分隔符【空格、制表符、換行符】。
存儲類型關鍵字:anto、extern、register、static
C語言變量有四種存儲類型:
自動型(auto)
外部型(extern)
靜態型(static)
寄存器型(register)
3.2 函數中,如何使⽤與局部變量同名的全局變量?(3分)
答:使⽤::(作⽤域區分符)(3分)
如何將一個內部變量或者是在函數后定義的外部變量,在該函數中使用:extern 變量名 (進行引用聲明,這時是不分配存儲空間的)
3.3 如何使⽤1個表達式將float類型變量f的值四舍五⼊ 轉換為long類型的值?(3分)
答:(long)(f + 0.5) (3分)
3.4 參數傳遞的⽅式分別是什么?(6分)
數組作為函數參數有三種形式:
1. 實參是數組元素; 傳(數據)值(2分)
2. 形參是指針,實參是數組; 傳地址值(2分)
3. 函數的形參和實參都是數組。 傳地址(2分)
3.5 C程序運⾏時,不對數組進⾏越界檢查,可能導致什么問題?(5分)
答:編譯通過,但可能導致運⾏出錯(訪問不可訪問的存儲單元)(3分)或訪問和修改
其他⾮數組元素的數據。(2分)
3.6 C語⾔的隱式類型轉換發⽣在哪4種情況下?轉換規則分別是什么?(6分)
混合運算: 級別低的類型向級別⾼的類型值轉換。 1分
將表達式的值賦給變量: 表達式的值向變量類型的值轉換。 1分
實參向函數形參傳值: 實參的值向形參的值進⾏轉換。 2分
函數返回值: 返回值向函數返回類型的值進⾏轉換。 2分
3.7 程序⽚段為: (14分)
當程序執⾏進⼊fun函數時,請列出各個數據(包括常量、變量)在內存中對應存儲區的名稱和數據的存儲順序以及所占⽤的存儲空間的字節數。
假設整數占2個字節,字符占2個字節,指針占4個字節;⽽內存按2個字節進⾏編址。存儲區名稱1分,其他每3個1分
int n = 2018;
void main() {
char * p=”COMPUTER”, *q;
int mm, arr[2018];
char ch2;
...
fun(mm);
...
}
void fun(int nn) {
int mm = 10;
static int snum;
...
}
3.8 下⾯的程序的功能是什么?(5分)
void main () { int d, i, j, k, flag1, flag2; scanf("%d", &d); for (i = 1; i <= 100; i++) { j = i; flag1 = 0;
// 該數是否含有 d while ((j > 0) && (!flag1)) { k = j % 10; j = j / 10; if (k == d) flag1 = 1; }
// 該數的平方是否含有 d if (flag1) { j = i * i; flag2 = 0; while ((j > 0) && (!flag2)) { k = j % 10; j /= 10; if (k == d) flag2 = 1; } if(flag2) printf("%-5d %-5d\n", i, i * i); } } }
功能:輸⼊數字d=0~9,找1~100中滿⾜條件的數:該數的本⾝及它的平⽅中都含有數字d。
3.9 采⽤Eratasthenes篩選法求2-200之間的素數
鏈接:https://www.cnblogs.com/pam-sh/p/12384776.html 請對第6、7、8、9⾏的代碼進⾏修改,使得程序執⾏效率得到提⾼。(8分)
void main()
{
int prime[201] = {0}; //用於存儲200以內的數是否已篩去
int d, i,k;
for (d = 2; d < 200; d++) if (prime[d] == 0) for (k = d + 1; k <= 200; k++) if (k % d == 0)
prime[k] = 1;
for (i = 2; i <= 200; i++)
if(prime[i]==0)
printf("%d\t", i);
}
// 改為:
for (d=2; d < sqrt(200); d++)
if (prime[d] == 0)
for (k = 2*d; k<=200; k = k+d) //篩去d的所有倍數
prime[k]=1;
要點:
為提高篩選效率:
一個合數n必有一個不大於sqrt(n)的正因子,故一個數若是沒有小於sqrt(n)的正因子,則說明它是一個素數
3.10 為提⾼程序執⾏效率,C語⾔除了提供指針、宏定義、位運算、不檢查數組下標外,簡述C語⾔還采取了其他哪些措施及原因(12分)
4 程序填空(每空2.5分,共50分)
4.1 快排找第K⼩
low = 0; // 該空為填空
high = n - 1; // 該空為填空
do
{
do
{
i = low;
j = high; // 該空為填空
t = a[i]; // 該空為填空
}while(i < j); // 該空為填空
a[i] = t; // 該空為填空
if(i == k)
return t; // 該空為填空
if(i > k)
high = i - 1; // 該空為填空
if(i < k)
low = i + 1; // 該空為填空
}while(low < high);
return a[low]; // 該空為填空
此題錯誤!!!
改正后:還是有錯!!!
low = 0; high = n - 1; do { i = low; j = high; t = a[i]; do { while (a[j--] > t) ; while (a[i++] < t) ; if(i < j) swap(a[j], a[i]); }while(i < j);
// 折半查找 if(i == k) return t; if(i > k) high = i - 1; if(i < k) low = i + 1; }while(low < high); return a[low];
參考:215
4.2 ⼀個包含9個數的⾮降序【升序】數列存儲在數組中,現在插⼊⼀個數到合適位置,使序列保持⾮降序(插⼊的數⼤於第⼀個數,⼩於第九個數)。
#define N 10 void main() { int a[N] = {1,2,4,8,16,32,64,128,256}; int m,i,d; scanf("%d",&d);
//找到插入點 for(i = 0; i < 9 ; i++) //這里填N-1也行 if( d < a[i] ) { m = i ; // m記錄插入點 break ; }
// m之后的往后移 for(i = 8; i >= m; i--) //這里填N-2也行 a[i + 1] = a[i];
// 插入 a[m] = d;
// 打印 for(i = 0;i < N;i++) printf("%d\t",a[i]); }

補充:把一個整數按從大到小順序插入到已經排好序的數組中
代碼:
#include <stdio.h>
#include <stdlib.h>
void insert(int a[],int n)
{
int i,s;
// 類似於 “直接查找排序”
for(i = 0; i < 10; i++)
{
// 找插入位置
if(n > a[i])
{
for(s = 9; s >= i; s--)
{
a[s + 1] = a[s]; // 將插入位置后的元素后移
break;
}
}
}
a[i] = n; // 插入數字
}
void main() { int i,j,temp = 0,n,p,q,s,a[10] = {127,3,6,28,54,68,87,105,162,18}; //排序(從大到小) //1.1 冒泡排序 ,從后向前 for(i = 0;i < 9;i++) // n - 1趟 { for(j = 9;j > i;j--) // n - i 次交換 { if(a[j] > a[j - 1]) { temp = a[j - 1]; a[j - 1] = a[j]; a[j] = temp; } } } //1.2冒泡排序 ,從前向后 for(i = 0;i < 9;i++) // n - 1趟 { for(j = 0;j < 9 - i ;j++) // n - i 次交換 { if(a[j] < a[j + 1]) { temp = a[j + 1]; a[j + 1] = a[j]; a[j] = temp; } } } // 從大到小輸出: printf("排好序的數:\n"); for(i = 0;i < 10;i++) { printf("%d\t",a[i]); } printf("\n"); // 2、簡單選擇排序:假設排序表為L[1....n-1],第i趟排序即從L[1....n-1]中選擇一個最大的元素與L[i]交換,每趟可以確定一個元素,經過n - 1趟就ok了 for(i = 0; i < 10; i++) { p = i; q = a[i]; for(j = i + 1; j < 10; j++) { if(q <a[j]) { p = j; q = a[j]; } } if(p != i) { s = a[i]; a[i] = a[p]; a[p] = s; } printf("%d\t",a[i]); } printf("\n"); printf("請輸入數字:\n"); scanf("%d",&n); insert(a,n); // 插入后從大到小輸出: for(i = 0; i <=10; i++) { printf("%d\t",a[i]); } printf("\n"); }

4.3 凱撒密碼
這道題是⼀道加密解密問題,⼤致的意思就是通過主函數輸⼊兩個字符串,第⼀個字符串作為加密解密的⽬標
字符串,第⼆個字符串通過函數轉換為整型數據作為解密加密的key,這道題也不難推導,以上是我在⽹絡上找到
的⼀個相似版本。
凱撒加密(Caesarcipher)是⼀種簡單的消息編碼⽅式:它根據字母表將消息中的每個字母移動常量位k。
舉個例⼦如果k等於3,則在編碼后的消息中,每個字母都會向前移動3位:
a會被替換為d;b會被替換成e;依此類推。字母表末尾將回卷到字母表開頭。
於是,w會被替換為z,x會被替換為a。
代碼:
#include <stdio.h>
#include <stdlib.h>
int main ()
{
char small_letter[26] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
char big_letter[26] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
char text[1000], result[1000];
int c, count = 0, k, p,i;
char function;
printf("Insert Text:");
c = getchar();
while (1) // 讀取字符串
{
if (c == '\n')
break;
text[count] = c;
printf("%c", text[count]);
count++;
c = getchar(); //讀取下一個字符
}
printf("\n");
printf("Encrypt or Decrypt? E or D :");
scanf("%c", &function);
// 解密
if (function == 'D')
{
printf("Insert Key :" );
scanf("%d", &k);
for (i = 0; i < count; i++)
{
if (text[i] >= 'A' && text[i] <= 'Z')
{
result[i] = big_letter[((text[i] - 'A') + k) % 26]; // 向后挪k位
}
//找出加密后字符在字符數組里的對應位置
else if (text[i] >= 'a' && text[i] <= 'z')
{
result[i] = small_letter[((text[i] - 'a') + k) % 26]; // 向后挪k位
}
else
result[i] = text[i];
printf("%c", result[i]);
}
}
// 加密
else
{
printf("Insert Key :" );
scanf("%d", &k);
for (i = 0; i < count; i++)
{
if (text[i] >= 'A' && text[i] <= 'Z')
{
p = ((text[i] - 'A') - k);
// 解碼涉及 字母表末尾將回卷到字母表開頭
while (p < 0)
p += 26;
result[i] = big_letter[p]; // 向前挪k位
}
//找出解密后字符在字符數組⾥里里的對應位置
//這里要注意不要讓它超出范圍(下表位置為負數)
else if (text[i] >= 'a' && text[i] <= 'z')
{
p = ((text[i] - 'a') - k);
while (p < 0)
p += 26;
result[i] = small_letter[p]; // 向前挪k位
}
else
result[i] = text[i];
printf("%c", result[i]);
}
printf("\n");
}
return 0;
}
5 程序設計(共20分)
5.1 輸⼊若⼲個整數(以0結束)如何逆序構建雙向鏈表
代碼:
#include <stdio.h>
#include <stdlib.h>
//雙鏈表結構定義
typedef struct DNode
{
int data;
struct DNode *pre;
struct DNode *next;
} DNode;
int main()
{
DNode *head, *s;
int t;
// 定義頭節點
head = (DNode*)malloc(sizeof(DNode));
head->pre = NULL;
head->next = NULL;
// 輸入
scanf("%d", &t);
while (t != 0)
{
s = (DNode*)malloc(sizeof(DNode));
s->data = t;
s->next = NULL;
s->pre = NULL;
if (head->next == NULL)
{
head->next = s;
s->pre = head;
}
else
{ // 頭插法【逆序】
s->next = head->next;
head->next->pre = s;
head->next = s;
s->pre = head;
}
scanf("%d", &t);
}
s = head->next;
while (s)
{
printf("%d ", s->data);
s = s->next;
}
return 0;
}
