1. 程式人生 > >2018 C筆試題

2018 C筆試題

⼀、單項選擇題(15⼩題,每⼩題2分,共30分)

 解析:【傳值呼叫】,實參和形參之間傳遞的是“地址”


 

 解析:【優先順序】:算術運算子 > 關係運算符  >   賦值運算子   

    【結核性】:賦值運算子(從右至左)   算數運算子和關係運算符(從左至右)

      相當於: ( k > i ) <  j   , ( i < j ) == ( j < k  )   


解析:指標陣列是指陣列的每一個元素都是一個指標變數的陣列

           相當於: point[2] 一樣

例如:


 

解析:陣列定義時,常量表達式中不允許包含變數


 

解析:【函式遞迴】,相當於 fib (2) + fib (1) 


 

解析:【do 迴圈】


 


 

解析:【陣列傳參】:傳過去的是地址,實參和虛參都改變


 

 題目有錯!!!

 

解析:【運算優先順序】:“ * ”和“ ++ ”  高於 " = ",“ * ”和“ ++ ”優先順序相同,結合性:從右往左

    *p1 += *p2++  相當於: *p1 = *p1 + *(p2++)

    *p2 =  p1++ 相當於: *p1 =  (p1++)


解析:【運算優先順序】+ 【結合性】

    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 )


 

 解析:!x是邏輯非操作,當x為0時,值為真,否則值為假。 在這裡等效於x==0 ,即x = 8,while (!x) 為假,退出迴圈

例如:

 


 

解析:(i * j) / k + 6 - 15 % k    相當於   ((i * j) / k) + 6 - (15 % k)   :  “+”和“-”  結合性從左向右


 解析: while()是迴圈語句。while(expr)表示當邏輯表示式expr為真時,迴圈執行迴圈體,直到expr值為假或遇到break語句時退出 

由 316 = 13 * i +  11 * j 得:k 一定得是11的倍數

 例:

 


 

 解析:【字元陣列的定義】:

char cc[ ]  = {'1','2','3','4','5'}, 陣列長度為5,字串長度為5

char cc[ ]  =”12345“,陣列長度為6,字串長度為5,自動在字串結尾加上一個終止符 \0 ,

[strlen()]函式:測試字串長度,不包括 \0


 

解析: 【指標與結構陣列】:指向結構 的 指標 要先定義,後賦值

p 指向結構第一個位元組,*p 相當於 stu 

  第一種方式:(*p).num    【由於結構成員引用符 "."的優先順序比間接運算子 “ *” 高,故必須加括號】

  第二種方式:p->num 

  第二種方式:stu.num     三種方式等價!!!


⼆、指出程式段中的錯誤:分析原因並修改。(每題15分,共30分)

改正後:

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指標指向字串的首地址


改正後:

void fun()
{
    char data[50] = "welcome to CHENGDU and UESTC";
    char *point;
    char array[200];
    int i = 0, length = 0;
    point = array;
    while (data[length] != '\0')
        length++;
    for (; i < length; i++)
    {
        *point = *data;
        point++;
    }
    puts(data);
}

三、問答題(共70分)

 1、C語⾔的單詞符號除關鍵字外,還包括其他哪四類?儲存型別關鍵字是哪4個?(每個1分,共8分)

答:  識別符號【只能由字母、常量、下劃線、數字組成,且第一個字元必須是字母或者下劃線】、運算子、常量和分隔符【空格、製表符、換行符】。
       儲存型別關鍵字:anto、extern、register、static

 2、函式中,如何使⽤與區域性變數同名的全域性變數?(3分)

答:使⽤::(作⽤域區分符)(3分)

 3、如何使⽤1個表示式將float型別變數f的值四舍五⼊ 轉換為long型別的值?(3分)

答:(long)(f + 0.5) (3分)

 4、引數傳遞的⽅式分別是什麼?(6分)

陣列作為函式引數有三種形式:
1. 實參是陣列元素;  傳(資料)值(2分)
2. 形參是指標,實參是陣列; 傳地址值(2分)
3. 函式的形參和實參都是陣列。 傳地址(2分)

 5、 C程式運⾏時,不對陣列進⾏越界檢查,可能導致什麼問題?(5分)

答:編譯通過,但可能導致運⾏出錯(訪問不可訪問的儲存單元)(3分)或訪問和修改
其他⾮陣列元素的資料。(2分)

 6、C語⾔的隱式型別轉換髮⽣在哪4種情況下?轉換規則分別是什麼?(6分)

混合運算: 級別低的型別向級別⾼的型別值轉換。 1分
將表示式的值賦給變數: 表示式的值向變數型別的值轉換。 1分
實參向函式形參傳值: 實參的值向形參的值進⾏轉換。 2分
函式返回值: 返回值向函式返回型別的值進⾏轉換。 2分

 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;
...
}

 

 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。

 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)的正因子,則說明它是一個素數

10、為提⾼程式執⾏效率,C語⾔除了提供指標、巨集定義、位運算、不檢查陣列下標外,簡述C語⾔還採取了其他哪些措施及原因(12分)

主要從 資料型別 型別檢查 邏輯運算的處理 等⽅⾯分析。
例如: 暫存器變數 ⽆布林型別 ⽆⼦界型別
a&&b(只有a成⽴才計算b) 陣列做引數是採⽤傳地址⽅式 等


 四、程式填空(每空2.5分,共50分)

 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];

程式碼:

const int n = 5;

void main()
{
    int a[5] = {3,1,4,6,2};
    int low,high,k;
    low = 0;
    high = n - 1;
    printf("請輸入查詢第K小的數:\n");
    scanf("%d",&k);
    find(a,low,high,k);
}

int find(int a[],int low,int high,int k)
{
    int t = a[low];
    int i = low;
    int j = high;
    while(low < high)
    {
        while(low < high && a[high] >= t)
            --high;
        a[low] = a[high];
        while(low < high && a[low] <= t)
            low++;
        a[high] = a[low];
    }
    a[low] = t;
    // 折半查詢

    if(low == k)
    {
        return a[low]);
        return 0;
    }
    else if(low > k)
        return find(a,i,low - 1,k);
    else
        return find(a,low + 1,j,k - low);
}

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 ; 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]); }

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 == 'E')
    {
        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;
}

五、程式設計(共20分) 

 輸⼊若⼲個整數(以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;
}