嵌入式c語言筆試題
時間:2019-10-23 來源:北京中心,袁老師
本文我們了解一下嵌入式c語言的筆試題,本文的主要內容如下:

為什么嵌入式行業注重C語言的考察?
首先我們先解決第一個問題,為什么嵌入式行業注重c語言的考察?或者說為什么嵌入式開發用c語言開發,在這么多種編程語言中為什么單單c語言在嵌入式行業中這么受用呢?
c語言出色的可移植性和能夠直接訪問硬件使得它非常適合在嵌入式行業開發使用。其實能夠直接訪問硬件的語言有匯編和C語言,但是匯編語言屬于低級語言,難以完成一些復雜的功能,此外匯編語言和CPU的架構緊密相關,X86架構和ARM架構的匯編代碼是不同的,這就違背了嵌入式開發中可移植的原則。然而匯編比C語言訪問硬件的效率更高,所以,一般將硬件初始化的工作交給匯編,比較復雜的操作交給C語言。
那其他的面向對象的變成語言又有無法直接操作硬件的局限性使得c語言在嵌入式開發中有著不可取代的地位和作用。
常見嵌入式C語言筆試題的幾個專題
數據類型
1.用變量a定義如下類型的變量
(1)一個整形數
(2)一個指向整形數的指針
(3)一個指向指針 的指針,被指向的指針指向一個整形數
(4)一個有十個整形數的數組
(5)一個有10個指針的數組,數組元素指向一個整形數
(6)一個指向有10個整形數數組的指針
(7)一個指向函數的指針,該函數有一個整形參數并返回一個整形數
(8)一個有10個指針的數組,該數組指向一個函數,該函數有一個整型參數并返回一個整形數
答案:
(1)int a;
(2)int *a;
(3)int **a;
(4)int a[10];
(5)int *a[10];
(6)int (*a)[10];
(7)int (*a)(int );
(8)int (*a[10])(int );
解析:
這道題有兩種考法,一是給出要求,自己寫出定義語句,二是給出定義語句,自己寫出變量a的含義。
解決辦法掌握幾個原則就好,這里首先提供給大家一個圖片,下圖描述的是c語言中運算符的優先級。

然后看這個變量的本質是什么,越靠近本質的定義其優先級越高,什么意思呢?我們分析兩個變量來感受一下
一個有10個指針的數組,數組元素指向一個整形數 : int *a[10];
一個指向有10個整形數數組的指針: int (*a)[10];
通過上面運算符優先級的圖片可以知道 [] 的優先級是高于 * 的,所以int *a[10];中,a的本質是數組,然后數組的中存放的數據成員是指針,數據成員指向的是整型數據。
那,int (*a)[10]; 呢?這里用圓括號將 *a 括住,表示強調a的本質是指針類型,a指向的是數組,這個被指向的數組有十個整型的數據。
辨析完了指針數組和數組指針,大家再嘗試著分析一下其他復雜的數據類型可以看著要求寫出定義語句或者看著定義語句寫出變量a的含義。
2.以下為 Linux/Windows 下的32 位C程序, 請計算sizeof 的值
1.void func(char str[100]);
2.int main(int argc, const char *argv[])
3.{
4. char str[] = "hello";
5. char *p = str;
6. int n = 10;
7. char str_fun[100];
8. void*p_malloc = malloc(100);
9. printf("sizeof(str) = %d\n",sizeof(str));
10. printf("sizeof(p) = %d\n",sizeof(p));
11. printf("sizeof(n) = %d\n",sizeof(n));
12. func(str_fun);
13. printf("sizeof(p_malloc) = %d\n",sizeof(p_malloc));
14. return 0;
15.}
16.void func(char str[100])
17.{
18. printf("sizeof(str) = %d\n",sizeof(str));
19.}
答案:
1.sizeof(str) = 6
2.sizeof(p) = 4
3.sizeof(n) = 4
4.sizeof(str) = 4
5.sizeof(p_malloc) = 4
解析:
首先第一個計算的是數組str的字節長度,str是在賦初值的同時確定的長度其長度是“hello\0”共6個字符長度,也就是6個字節。
第二個計算的是指針p的字節長度,不論指向什么數據類型的指針,其字節長度都為4。
第三個計算的是整型變量n的字節長度,在32位系統下,整型數據占4字節。
第四個是在子函數中計算的形參str的字節長度,對于函數的形參來說不論是數組還是指針它的本質都是指針,所以它的字節長度為4字節。
第五個計算的是指針p_malloc的字節長度,雖然它指向了一個100字節大小的內存空間,但是它的本質還是一個指針,仍然是4字節。
關鍵字和預處理
1.static關鍵字有什么作用?
答:
(1)函數體內,static變量的作用范圍為該函數,不同于auto變量,該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值。
(2)在模塊內的static全局變量可以被模塊內所有函數訪問,但不能被模塊外其他函數訪問。
(3)在模塊內的static函數只可以被這一模塊內的其它函數調用,這個函數的使用范圍被限制在聲明它的模塊內。
2.const關鍵字有什么作用
答:
(1)欲阻止一個變量被改變,可以使用const關鍵字,定義該變量時,通常要對它初始化,因為以后就沒有機會再去改變它了。
(2)對于指針來說,可以指定指針本身,也可以指定指針所指向的數據,或二者同時指定為const。
(3)在函數申明中,const可以修飾形參,表明它是一個輸入參數,在函數內部不能改變其值。
3.const 與 # define 相比有何優點?
答:
(1)const 修飾的只讀變量具有特定的數據類型,而宏沒有數據類型編譯器可以對前者進行類型安全檢查,而對后者只進行字符替換,沒有類型安全檢查
(2)編譯器通常不為普通const只讀變量分配存儲空間,而是將它們保存在符號表中,這使他成為一個編譯期間得知,沒有了存儲于讀內存的操作,使它的效率更高
4.枚舉與# define宏的區別有哪些?
答:
枚舉與宏的概述
(1)枚舉:是指將變量的值一一列舉出來,變量的值只限于列舉出來的值的范圍內
(2) # define宏定義是用一個指定的標識符來代表一個字符串
枚舉與# define宏的區別
(1)在編譯器中可以調試枚舉變量,不能調試宏常量
(2)# define宏常量是在預編譯階段進行簡單替換。枚舉常量則是在編譯的時候才確定 其值
(3) 枚舉可以一次定義大量相關的常量,而# define宏一次只能定義一個
5.typedef與#define宏的相似之處與不同之處是什么?
答:
(1)相似之處:通常都可以理解為為一個字符起別名,在程序中用一個新的字符代替原有的字符
(2)區別
a.實質含義不同,# define是字符串替換,typedef是為類型起了一個別
b. 宏定義的句尾沒有分號作為結束標志,其本身并不在編譯過程中進行,而是在預處理過程中就已經完成了很難發現潛在的錯誤
指針和段錯誤
1.指針、數組和地址之間的關系是的什么?
答:
(1)數組是保存在一片連續內存單元中的,而數組名就是這片連續內存單元的首地址,內存 單元的地址就是指針,因此數組名也是一個指針。
(2)數組是由多個數組元素組成,元素按其數組類型的不同,所占連續內存的大小也不同。一個數組的元素的首地址就是其所占連續內存單元的首地址。
(3)指針變量既可以指向一個數組,也可以指向一個數組元素。將數組名或數組的第一個元素的地址賦給指針,指針就指向了一個數組。如果想使指針變量指向第i個元素,就可以把i元素首地址賦給它。
2.如何用指針表示多維數組
答:
舉個例子:假設a是二維數組名,a代表整個二維數組的首地址
那么a+i、a[i]、(a+i)、&a i 是等同的,
a[i]+j=(*(a+i)+j)該元素的值等于*(*(a+i)+j)
3.二級指針如何應用于一維數組?
答:
int a=[10],*p1,**p2,i;
p1=a;
p2=&p1;
a[i]=*(*p2+i)=* (p1+i)=*(a+i)
字符串相關函數
1.size_t strlen(const char *s);
功能:計算字符串長度
參數: s:字符數組
返回值:返回字符串實際長度,不包括‘\0’在內
1.//自己實現
2.int my_strlen(const char *s)
3.{
4. char * sc;
5. for (sc = s; *sc != '\0'; ++sc);
6. return sc - s;
7.}
2.char *strcpy(char *dest, const char *src);
功能:將src的數據復制到dest里面
參數: dest:目標字符數組 src:源的字符數組
返回值: 復制后的字符數組
說明:dest字符數組1必須足夠大
連接前,兩串均以‘\0’結束;連接后,dest的‘\0’取消,新串最后加‘\0’
1.//自己實現
2.char *my_strcpy(char *dest, const char *src)
3.{
4. int i;
5. while(src[i] != '\0')
6. {
7. dest[i] = src[i];
8. i++;
9. }
10.
11. dest[i] = '\0';
12. return dest;
13.}
3.char *strcat(char *dest, const char *src);
功能: 將src的數據追加到dest后面
參數: dest:目標字符數組 src:源的字符數組
返回值: 同最終的dest
說明:字符數組1必須足夠大
連接前,兩串均以‘\0’結束;連接后,串1的‘\0’取消,新串最后加‘\0’
1.//自己實現
2.char *strcat(char *dest, const char *src)
3.{
4. int i = 0, j = 0;
5. while(dest[i] != '\0'){
6. i++;
7. }
8. while(src[j] != '\0'){
9. dest[i++] = src[j++];
10. }
11. dest[i] = '\0';
12. return dest;
13.}
4.int strcmp(const char *s1, const char *s2);
功能:比較兩個字符串的長度
返回值:若字符串1< 字符串2, 返回負整數
若字符串1> 字符串2, 返回正整數
若字符串1== 字符串2, 返回零
說明:
對兩串從左向右逐個字符比較(ASCII碼),直到遇到不同字符或‘\0’為止
字符串比較不能用“==”,必須用strcmp
1.//自己實現
2.int my_strcmp (const char *s1, const char *s2)
3.{
4. int ret;
5. while ((ret = *(unsigned char *) s1 - *(unsigned char*) s2++) == 0 && *s1++);
6. return ret;
7.}
鏈表
在鏈表中最復雜的是雙向循環鏈表,展示一下雙向循環鏈表,相信如果雙向循環鏈表可以理解透徹,單向鏈表自不在話下。
1.雙向循環鏈表
1.//linklist.h
2.#ifndef __LINKLIST_H__
3.#define __LINKLIST_H__
4.#include <stdio.h>
5.#include <stdlib.h>
6.//雙向循環鏈表
7.typedef int datatype;
8.typedef struct dnode{
9. datatype data;
10. struct dnode *prior;
11. struct dnode *next;
12.}DLinkList, *DLinkList_p;
13.DLinkList_p creat_dlinklist(void);
14.DLinkList_p getnode_dlinklist(DLinkList_p D, int pos);
15.int insert_dlinklist(DLinkList_p D, datatype value, int pos);
16.void show_dlinklist(DLinkList_p D);
17.int delete_dlinklist(DLinkList_p D, int pos);
18.#endif
1.// linklist.c
2.#include "linklist.h"
3.DLinkList_p creat_dlinklist(void){
4. DLinkList_p D = NULL;
5. D = (DLinkList *)malloc(sizeof(DLinkList));
6. if(NULL == D){
7. printf("malloc error!\n");
8. return NULL;
9. }
10. D->data = 0;
11. D->prior = D;
12. D->next = D;
13. return D;
14.}
15.DLinkList_p getnode_dlinklist(DLinkList_p D, int pos){
16. if(NULL == D){ printf("D is NULL"); return NULL; }
17. if(pos < 0){ printf("pos error!\n"); return NULL; }
18. int i = 0;
19. DLinkList_p p = D->next;
20. while( p != D && i < pos){
21. p = p->next;
22. i++;
23. }
24. if(p == D){ printf("pos > length\n"); return NULL; }
25. if(i == pos){ return p; }
26. printf("pos > length!\n");
27. return NULL;
28.}
29.//插入函數
30.int insert_dlinklist(DLinkList_p D, datatype value, int pos){
31. DLinkList_p new = NULL; DLinkList_p Q = NULL;
32. if(NULL == D){ printf("D is NULL\n"); return -1; }
33. if(pos < 0){ printf("pos error!\n"); return -1; }
34. else if( D->next == D ){ Q = D; }
35. else{ Q = getnode_dlinklist(D, pos); }
36. if( NULL == Q ){ printf("Q get NULL\n"); return -1; }
37.
38. new = (DLinkList *)malloc(sizeof(DLinkList));
39. if(NULL == new){
40. printf("malloc error!\n");
41. return -1;
42. }
43. new->data = value;
44. new->next = Q;
45. new->prior = Q->prior;
46. Q->prior->next = new;
47. Q->prior = new;
48. return 0;
49.}
50.//刪除
51.int delete_dlinklist(DLinkList_p D, int pos){
52. DLinkList_p del = NULL;
53. if(NULL == D){ printf("D is NULL\n"); return -1; }
54. if(pos < 0){ printf("pos error!\n"); return -1; }
55. else{ del = getnode_dlinklist(D, pos); }
56. if( NULL == del ){ printf("Q get NULL\n"); return -1; }
57.
58. del->prior->next = del->next;
59. del->next->prior = del->prior;
60. free(del);
61. del = NULL;
62. return 0;
63.}
64.void show_dlinklist(DLinkList_p D){
65. if(NULL == D){ printf("D is NULL\n"); return; }
66. DLinkList_p p = D->next;
67. while(p != D){
68. printf("%d\n", p->data);
69. p = p->next;
70. }
71.}

