本文我们了解一下嵌入式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
5.#include
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.}
嵌入式物联网需要学的东西真的非常多,千万不要学错了路线和内容,导致工资要不上去!
分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全!(点击找小助理领取)