嵌入式linux C面试题集锦

1、语句for(;1;)有什么问题?他是什么意思?

无限循环,和while(1)相同
2do.....whilewhile....do的区别

前者循环一遍再判断,后者判断以后再循环
3、TCP 和UDP的区别

TCP:是面向连接的流传输控制协议,具有高可靠性,确保传输数据的正确性,有验证重发机制,不会出现丢失或乱序

UPD:是无连接的数据报服务,不对数据报进行检查与修改,无需等待对方的应答,会出现分组丢失,重复,乱序,但具有较好的实时性,UDP段结构比TCP的段结构简单,因此网络开销也小。
4、linux系统中多线程同步的方法有?

互斥锁、条件变量、信号量、读写锁
5、进程间通信的方式及优缺点

a、无名管道:无名管道是一种半双工的通信方式,而且只能在具有亲缘关系的进程间使用,进程的亲缘关系通常是指父子进程关系。

b、有名管道:有名管道也是一种半双工的方式,但是它允许无亲缘关系进程间的通信 。

c、信号量:信号量是一个计时器,可以用来控制多个进程对共享资源的访问,它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步。

d、消息队列:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识,消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。

e、信号:信号是一种比较复杂的通信方式,用于通知接受进程某个事件已经发生f

、共享内存:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但是多个进程都可以访问。共享内存是最快的IPC方式,他是针对其他进程间通信方式运行效率低而专门设计的。他往往与其他通信机制,如信号量,配合使用,来实现进程间的通信与同步。

g、套接字:套接字也是一种进程间通信机制。

优缺点:无名管道简单方便,但局限于单向通信的工作方式,并且只能在亲缘进程之间通信,有名管道虽然可以提供给任何关系

的进程使用,但是由于其长期存在于系统之中,使用不当容易出错。消息队列可以不局限于父子进程而允许任意进程通过共享消息队列

来实现进程间通信,并由系统调用函数来实现消息发送和接受之间的同步,从而使得用户在使用消息缓冲进行通信不再需要考虑同步问

题。使用方便,但是信息的复制需要额外消耗CPU的时间,不适宜于信息量大或者操作频繁的场合。共享内存利用内存缓冲区直接交换

信息,无需复制,快捷,信息量大是其优点。但是共享内存的通信方式是通过将共享的内存缓冲区直接附加到进程的虚拟地址空间中来

实现的。因此,进程之间的读写操作的同步问题操作系统无法自动实现,必须由各进程利用其它同步工具解决。另外,由于内存实体存

在于计算机系统中,所以只能由处于同一计算机系统中的诸进程共享,不能网络通信。
6、请问 int *p 和char *p分别占几个字节

都占四个字节,因为两者都是指针变量,指针变量里面保存的是地址,地址在操作系统中是固定长度的,长度是有系统的位数

决定的,操作系统是32位,长度则为4个字节,操作系统为64位,长度则为8个字节。
7、请简述sizeof(),和strlen()的区别

sizeof,测量一个变量或数据类型所占的字节长度,统计字符串长度的时候加上'\0',在编译阶段的时候就可以计算出长度

strlen,计算字符串长度,在统计字符串长度的时候不加上'\0',在函数运行的时候才计算出长度。
8、 请简述用户空间的内存分配及各空间保存的数据类型

用户空间供为3G,分为:栈空间,堆空间,数据区,代码段

栈空间保存:局部变量,函数形参,自动变量。栈空间特点,先进后出,空间由系统管理;栈空间生命周期所在函数执行结束

后释放;栈空间保存的局部变量未初始化时,默认初始化为随机值。

堆空间:由malloc , calloc ,ralloc,这些好函数分配的控件位堆空间,堆空间特点:先进先出,由用户管理

数据区:又分为.bss段、.data段、常量区。其中.bss段保存的是未初始化的全局变量,当全局变量未初始化时,系统默认初始

化为0,常量区保存的是常量,里面保存的值不能被修改,只能做读操作。.data段是保存已经初始化的全局变量以及被static修饰的

变量(静态变量)。数据区的声明周期是整个程序执行完之后再释放。

代码段保存的是代码。
9、文件系统的主要功能是实现对文件的按名存储
10、不利于嵌入式应用软件的移植的是在数据类型上,尽量直接使用C语言的数据类型
11、如果BootLoader、内核、启动参数以及其他的系统映像四部分在固态存储设备上分别独立存放,则其存储结构的分配顺序应当是:BootLoader、启动参数、内核、文件系统。
12char *p ="hello world";
    char p[] = "hello world";的区别
    char *p 代表指针p是一个指向字符常量的指针,指向一个常量区域,如果采用p[0] = 'H'等语句,就会报错。
    而 char p[],中的p是一个被分配在一个可读可写内存中的字符数组的首地址,可以用p[0] = 'H'赋值。
13、c和c++中的struct有什么不同?
    c和c++中struct的主要区别是c中的struct不可以含有成员函数,而c++中的struct中可以。c++中structclass的主要区别是在于默认的存取权限不同,struct默认为Public,而class默认为private
14、操作系统中进程调度策略有那几种?
    FCFS(先来先服务),优先级,时间片轮转,多级反馈
15、realloc函数的缺陷是:
    a)没有对入口参数的非法性进行检查
    b)在重新分配一个内存空间的时候,没有对这个空间进行合法性判断就释放掉原来的空间,因此有一定的概率会把原来内存空间的数据释放掉,造成数据会无缘无故丢失。
16、当在函数中返回一个局部数据的指针时例如:
    void GetString()
    {
        char p[] = "hello world";
        return p;
    }
    会发生什么问题?
    局部数组所占用的内存空间是由编译器分配在栈中的,当函数返回时,这些被占用的栈空间将被编译器添加的代码进行退栈操作,这时原来存放在栈中的数据就统统变成了无效数据了。因此,返回出去的指针将指向一块无效的栈空间,任何通过这个指针对其所指向的内容的访问都是无效(数据可能已经被后续的栈操作所改变)和危险的(通过这个指针所写入的数据有可能冲掉后续栈操作压人的有效数据)
17、分析以下程序
    //###################################         一          ###########################################
    void GetMemory1(char *p)    
    {    
        p = (char *)malloc(100);    
    }    

    void Test1(void)    
    {    
        char *str = NULL;    
        GetMemory1(str);      
        strcpy(str, "hello world");    
        printf(str);  //str一直是空,程序崩溃     
    }   
    /*程序会崩溃,因为str没有申请到内存空间。编译器总是要为函数的每个参数制作临时副本,把str当做参数传入到
    GetMemory中时,在GetMemory中为参数p申请到了一块堆内存了,然后函数执行完毕,这时候参数p就会退栈,
    而p所指向的那一块堆内存并没有释放掉,而且也没有相应的指针指向这块内存的首地址,我们申请出来的堆内存就
    永远无法使用了,这就造成了内存泄漏。每调用一次GetMemory函数,就泄漏一块内存。*/
    就象:   int   a   =   100int   b   =   a;       //   现在b等于a   
                b   =   500//   现在能认为a   =   500 ?      
        显然不能认为a   =   500,因为b只是等于a,但不是a! 当b改变的时候,a并不会改变,b就不等于a了。   
         因此,虽然p已经有new的内存,但str仍然是null  
    //###################################         二          ###########################################
    void GetMemory2(char **p, int num)    
    {    
        *p = (char *)malloc(num);    
    }    

    void Test2(void)    
    {    
        char *str = NULL;    
        GetMemory2(&str, 100);    
        strcpy(str, "hello");      
        printf(str);        
    }    
    /*程序输入为:hello。这个为地址传递,把str的地址通过参数传递给GetMemory函数,此时参数指针p
    是指向str,然后通过解引用取得str的首地址,把申请到堆空间的首地址赋值给str。此时str申请内
    存成功了。此外,在用malloc申请堆空间的时候,没有加上判断,if( p == NULL){ ……};*/
    //###################################         三          ###########################################
    char * GetMemory3(void)    
    {      
         char p[] = "hello world";    
         return p;    
    }    
    void Test3(void)    
    {    
         char *str = NULL;    
         str = GetMemory3();        
         printf(str);    
    }    
    /*输出乱码。局部数组所占用的内存空间是由编译器分配在栈中的,当函数返回时,这些被占用
    的栈空间将进行退栈操作。这时原来存放在栈中的数据就统统变成了无效数据了。因此,返回
出去的指针将指向一块无效的栈空间,任何通过这个指针对其所指向的内容的访问都是无效(数据可
能已经被后续的栈操作所改变)和危险的(通过这个指针所写入的数据有可能冲掉后续栈操作压人的有效数据)*/
    //###################################         四          ###########################################
    char * GetMemory4(void)    
    {      
         static char p[] = "hello world";    
         return p;    
    }    
    void Test3(void)    
    {    
         char *str = NULL;    
         str = GetMemory4();        
         printf(str);    
    }    
    /*输出为hello world。 因为局部数组p用static修饰,不再存放在栈中,而是在静态存储区,生命周期
    为程序的生命周期,等到程序退出后才会回收。*/
    //###################################         五          ###########################################
    char *GetMemory5(void)    
    {    
        char *p = "hello";    
        return p;    
    }    

    void Test4(void)    
    {    
        char *str = NULL;    
        str = GetMemory5();   
        cout<< str << endl;    
    }   
    /*输出hello。p指向的是字符串常量,字符串常量保存在只读的数据段,是全局区域,但不是像全局变量
    那样保存在普通数据段(静态存储区)。但无法对p所指的内存的内容修改,例如p[0] = 'y;这样的修改是错误的。*/
    //##################################         六          ####################################
    char *GetMemory6(void)    
    {     
         return "hello";    
    }    
    void Test3(void)    
    {    
        char *str = NULL;    
        str = GetMemory6();     
        printf(str);    
    }    
    输出hello,直接返回常量区。
    //###################################         七          ###########################################
    void GetMemory6(void) 
    {  
        char *str = (char*)malloc(100);  
        strcpy(str, "hello");  
        free(str);  
        //str = NULL,加上这句程序才不会有野指针  
        if (str != NULL)
         {  
            strcpy(str, "world");  
            printf(str);  
        }  
    }  

    void main()
    {    
        GetMemory6();  
    }    
    /*输出world,但程序存在问题,程序出现了野指针。
    野指针只会出现在像C和C++这种没有自动内存垃圾回收功能的高级语言中, 所以java或c#肯定
    不会有野指针的概念. 当我们用malloc为一个指针分配一个空间后, 用完这个指针,把它free
    掉,但是没有让这个指针指向NULL或某一个特定的空间。如上面程序一样,将str进行free后,
    只是释放了指针所指的内存,但指针并没有释放掉,此时指针所指的是垃圾内存;这样的话,
    if语句永为真,if判断无效。delete也存在同样的问题。
    防止产生野指针:(1)指针变量一定要初始化为NULL,因为任何指针变量刚被创建时不会自
    动成为NULL指针,它的缺省值是随机的。(2)当free或delete后,将指针指向NULL。通常
    判断一个指针是否合法,都是使用if语句测试该指针是否为NULL。*/
18volatilestaticconst
    volatile的作用是告知编译器,它修饰的变量随时都可能被改变,因此,编译后的程序每次在
    使用该变量的值时,都会从变量的地址中读取数据,而不是从寄存器中获取。用在以下情况:
    (a)、并行设备的硬件寄存器(如:状态寄存器)
    (b)、一个中断服务子程序中会访问到的非自动变量(也就是全局变量)
    (c)、多线程应用中被几个任务共享的变量。

    static:
    1static修饰全局变量:被修饰的全局变量的作用域范围限定为本源文件,
        另外的源文件不能通过extern关键词来使用这个全局变量。
    2static修饰局部变量:a)被修饰的局部变量只能被初始化一次。b)被修饰的局部
        变量的存储空间发生了改变,不再存储在栈中,而是存储在数据段中。
    3static修饰函数:被修饰的函数作用域范围限定为本源文件,另外的源文件不能使用被修饰的函数

    const:被const修饰的变量为只读的变量。例如:
    a) const int a;// a是只读的,a不能重新被赋值
    b) int const a;// 同(b)
    c) int const *a //指针a指向的内容是只读的,不能通过*a = 10来赋值,但是指针a本身可以重新被赋值,例如 a = &b
    d) const int *a //同(c)
    e) int *const a //指针a本身是只读的,不能令a重新指向,例如 a = &b,但是指针a指向的内容可以通过*a = 10来赋值
    f) const int *const a //指针a和a指向的内容都是只读的,不能执行a=&b,*a=10操作

猜你喜欢

转载自blog.csdn.net/yaowangii/article/details/79851968